blob: de36307ae0d231a45e19e8841f429977a410eeb1 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
tomhudson@google.com278cbb42011-06-30 19:37:01 +000010#include "GrBufferAllocPool.h"
11#include "GrClipIterator.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000012#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000013#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000014#include "GrIndexBuffer.h"
15#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000016#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000017#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000018#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000019#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000020#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000021#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000022#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000023
bsalomon@google.com91958362011-06-13 17:58:13 +000024// Using MSAA seems to be slower for some yet unknown reason.
25#define PREFER_MSAA_OFFSCREEN_AA 0
26#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000027
bsalomon@google.com27847de2011-02-22 20:59:41 +000028#define DEFER_TEXT_RENDERING 1
29
30#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
31
bsalomon@google.comd46e2422011-09-23 17:40:07 +000032// When we're using coverage AA but the blend is incompatible (given gpu
33// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000034#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000035
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000036static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
37static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000038
39static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
40static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
41
42// We are currently only batching Text and drawRectToRect, both
43// of which use the quad index buffer.
44static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
45static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
46
bsalomon@google.combc4b6542011-11-19 13:56:11 +000047#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
48
bsalomon@google.com05ef5102011-05-02 21:14:59 +000049GrContext* GrContext::Create(GrEngine engine,
50 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000051 GrContext* ctx = NULL;
52 GrGpu* fGpu = GrGpu::Create(engine, context3D);
53 if (NULL != fGpu) {
54 ctx = new GrContext(fGpu);
55 fGpu->unref();
56 }
57 return ctx;
58}
59
bsalomon@google.com27847de2011-02-22 20:59:41 +000060GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000061 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000062 delete fTextureCache;
63 delete fFontCache;
64 delete fDrawBuffer;
65 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000066 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000067
bsalomon@google.com205d4602011-04-25 12:43:45 +000068 GrSafeUnref(fAAFillRectIndexBuffer);
69 GrSafeUnref(fAAStrokeRectIndexBuffer);
70 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000071 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000072}
73
bsalomon@google.com8fe72472011-03-30 21:26:44 +000074void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000075 contextDestroyed();
76 this->setupDrawBuffer();
77}
78
79void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000080 // abandon first to so destructors
81 // don't try to free the resources in the API.
82 fGpu->abandonResources();
83
bsalomon@google.com30085192011-08-19 15:42:31 +000084 // a path renderer may be holding onto resources that
85 // are now unusable
86 GrSafeSetNull(fPathRendererChain);
87
bsalomon@google.com8fe72472011-03-30 21:26:44 +000088 delete fDrawBuffer;
89 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000090
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 delete fDrawBufferVBAllocPool;
92 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000093
bsalomon@google.com8fe72472011-03-30 21:26:44 +000094 delete fDrawBufferIBAllocPool;
95 fDrawBufferIBAllocPool = NULL;
96
bsalomon@google.com205d4602011-04-25 12:43:45 +000097 GrSafeSetNull(fAAFillRectIndexBuffer);
98 GrSafeSetNull(fAAStrokeRectIndexBuffer);
99
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000100 fTextureCache->removeAll();
101 fFontCache->freeAll();
102 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000103}
104
105void GrContext::resetContext() {
106 fGpu->markContextDirty();
107}
108
109void GrContext::freeGpuResources() {
110 this->flush();
111 fTextureCache->removeAll();
112 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000113 // a path renderer may be holding onto resources
114 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000115}
116
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000117////////////////////////////////////////////////////////////////////////////////
118
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000119int GrContext::PaintStageVertexLayoutBits(
120 const GrPaint& paint,
121 const bool hasTexCoords[GrPaint::kTotalStages]) {
122 int stageMask = paint.getActiveStageMask();
123 int layout = 0;
124 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
125 if ((1 << i) & stageMask) {
126 if (NULL != hasTexCoords && hasTexCoords[i]) {
127 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
128 } else {
129 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
130 }
131 }
132 }
133 return layout;
134}
135
136
137////////////////////////////////////////////////////////////////////////////////
138
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000139enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000140 // flags for textures
141 kNPOTBit = 0x1,
142 kFilterBit = 0x2,
143 kScratchBit = 0x4,
144
145 // resource type
146 kTextureBit = 0x8,
147 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000148};
149
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000150GrTexture* GrContext::TextureCacheEntry::texture() const {
151 if (NULL == fEntry) {
152 return NULL;
153 } else {
154 return (GrTexture*) fEntry->resource();
155 }
156}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000157
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000158namespace {
159// returns true if this is a "special" texture because of gpu NPOT limitations
160bool gen_texture_key_values(const GrGpu* gpu,
161 const GrSamplerState& sampler,
162 GrContext::TextureKey clientKey,
163 int width,
164 int height,
165 bool scratch,
166 uint32_t v[4]) {
167 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
168 // we assume we only need 16 bits of width and height
169 // assert that texture creation will fail anyway if this assumption
170 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000171 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000172 v[0] = clientKey & 0xffffffffUL;
173 v[1] = (clientKey >> 32) & 0xffffffffUL;
174 v[2] = width | (height << 16);
175
176 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000177 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000178 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
179
180 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
181 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
182
183 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000184 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000185 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000186 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000187 }
188 }
189 }
190
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000191 if (scratch) {
192 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000193 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000194
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000195 v[3] |= kTextureBit;
196
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000197 return v[3] & kNPOTBit;
198}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000199
200// we should never have more than one stencil buffer with same combo of
201// (width,height,samplecount)
202void gen_stencil_key_values(int width, int height,
203 int sampleCnt, uint32_t v[4]) {
204 v[0] = width;
205 v[1] = height;
206 v[2] = sampleCnt;
207 v[3] = kStencilBufferBit;
208}
209
210void gen_stencil_key_values(const GrStencilBuffer* sb,
211 uint32_t v[4]) {
212 gen_stencil_key_values(sb->width(), sb->height(),
213 sb->numSamples(), v);
214}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000215
216// This should be subsumed by a future version of GrDrawState
217// It does not reset stage textures/samplers or per-vertex-edge-aa state since
218// they aren't used unless the vertex layout references them.
219// It also doesn't set the render target.
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000220void reset_draw_state(GrDrawState* drawState){
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000221
222 drawState->setViewMatrix(GrMatrix::I());
223 drawState->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000224 drawState->resetStateFlags();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000225 drawState->setEdgeAAData(NULL, 0);
226 drawState->disableStencil();
227 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000228 drawState->setBlendFunc(kOne_BlendCoeff,
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000229 kZero_BlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000230 drawState->setFirstCoverageStage(GrDrawState::kNumStages);
231 drawState->setDrawFace(GrDrawState::kBoth_DrawFace);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000232}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000233}
234
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000235GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
236 int width,
237 int height,
238 const GrSamplerState& sampler) {
239 uint32_t v[4];
240 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
241 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000242 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
243 GrResourceCache::kNested_LockType));
244}
245
bsalomon@google.comfb309512011-11-30 14:13:48 +0000246bool GrContext::isTextureInCache(TextureKey key,
247 int width,
248 int height,
249 const GrSamplerState& sampler) const {
250 uint32_t v[4];
251 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
252 GrResourceKey resourceKey(v);
253 return fTextureCache->hasKey(resourceKey);
254}
255
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000256GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000257 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000258 uint32_t v[4];
259 gen_stencil_key_values(sb, v);
260 GrResourceKey resourceKey(v);
261 return fTextureCache->createAndLock(resourceKey, sb);
262}
263
264GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
265 int sampleCnt) {
266 uint32_t v[4];
267 gen_stencil_key_values(width, height, sampleCnt, v);
268 GrResourceKey resourceKey(v);
269 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
270 GrResourceCache::kSingle_LockType);
271 if (NULL != entry) {
272 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
273 return sb;
274 } else {
275 return NULL;
276 }
277}
278
279void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000280 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000281 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000282}
283
284static void stretchImage(void* dst,
285 int dstW,
286 int dstH,
287 void* src,
288 int srcW,
289 int srcH,
290 int bpp) {
291 GrFixed dx = (srcW << 16) / dstW;
292 GrFixed dy = (srcH << 16) / dstH;
293
294 GrFixed y = dy >> 1;
295
296 int dstXLimit = dstW*bpp;
297 for (int j = 0; j < dstH; ++j) {
298 GrFixed x = dx >> 1;
299 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
300 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
301 for (int i = 0; i < dstXLimit; i += bpp) {
302 memcpy((uint8_t*) dstRow + i,
303 (uint8_t*) srcRow + (x>>16)*bpp,
304 bpp);
305 x += dx;
306 }
307 y += dy;
308 }
309}
310
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000311GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000312 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000313 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000314 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000315 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000316
317#if GR_DUMP_TEXTURE_UPLOAD
318 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
319#endif
320
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000321 TextureCacheEntry entry;
322 uint32_t v[4];
323 bool special = gen_texture_key_values(fGpu, sampler, key,
324 desc.fWidth, desc.fHeight, false, v);
325 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000326
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000327 if (special) {
328 TextureCacheEntry clampEntry =
329 findAndLockTexture(key, desc.fWidth, desc.fHeight,
bsalomon@google.com97912912011-12-06 16:30:36 +0000330 GrSamplerState::ClampNearest());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000331
332 if (NULL == clampEntry.texture()) {
333 clampEntry = createAndLockTexture(key,
bsalomon@google.com97912912011-12-06 16:30:36 +0000334 GrSamplerState::ClampNearest(),
bsalomon@google.com27847de2011-02-22 20:59:41 +0000335 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000336 GrAssert(NULL != clampEntry.texture());
337 if (NULL == clampEntry.texture()) {
338 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000339 }
340 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000341 GrTextureDesc rtDesc = desc;
342 rtDesc.fFlags = rtDesc.fFlags |
343 kRenderTarget_GrTextureFlagBit |
344 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000345 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
346 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000347
348 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
349
350 if (NULL != texture) {
351 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000352 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000353 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000354 drawState->setRenderTarget(texture->asRenderTarget());
355 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000356
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000357 GrSamplerState::Filter filter;
358 // if filtering is not desired then we want to ensure all
359 // texels in the resampled image are copies of texels from
360 // the original.
361 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
362 filter = GrSamplerState::kNearest_Filter;
363 } else {
364 filter = GrSamplerState::kBilinear_Filter;
365 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000366 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000367 filter);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000368 drawState->setSampler(0, stretchSampler);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000369
370 static const GrVertexLayout layout =
371 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
372 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
373
374 if (arg.succeeded()) {
375 GrPoint* verts = (GrPoint*) arg.vertices();
376 verts[0].setIRectFan(0, 0,
377 texture->width(),
378 texture->height(),
379 2*sizeof(GrPoint));
380 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
381 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
382 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000383 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000384 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000385 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000386 } else {
387 // TODO: Our CPU stretch doesn't filter. But we create separate
388 // stretched textures when the sampler state is either filtered or
389 // not. Either implement filtered stretch blit on CPU or just create
390 // one when FBO case fails.
391
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000392 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000393 // no longer need to clamp at min RT size.
394 rtDesc.fWidth = GrNextPow2(desc.fWidth);
395 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000396 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000397 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000398 rtDesc.fWidth *
399 rtDesc.fHeight);
400 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
401 srcData, desc.fWidth, desc.fHeight, bpp);
402
403 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
404
405 GrTexture* texture = fGpu->createTexture(rtDesc,
406 stretchedPixels.get(),
407 stretchedRowBytes);
408 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000409 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000410 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000411 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000412
413 } else {
414 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
415 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000416 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000417 }
418 }
419 return entry;
420}
421
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000422namespace {
423inline void gen_scratch_tex_key_values(const GrGpu* gpu,
424 const GrTextureDesc& desc,
425 uint32_t v[4]) {
426 // Instead of a client-provided key of the texture contents
427 // we create a key of from the descriptor.
428 GrContext::TextureKey descKey = desc.fAALevel |
429 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000430 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000431 // this code path isn't friendly to tiling with NPOT restricitons
432 // We just pass ClampNoFilter()
bsalomon@google.com97912912011-12-06 16:30:36 +0000433 gen_texture_key_values(gpu, GrSamplerState::ClampNearest(), descKey,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000434 desc.fWidth, desc.fHeight, true, v);
435}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000436}
437
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000438GrContext::TextureCacheEntry GrContext::lockScratchTexture(
439 const GrTextureDesc& inDesc,
440 ScratchTexMatch match) {
441
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000442 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000443 if (kExact_ScratchTexMatch != match) {
444 // bin by pow2 with a reasonable min
445 static const int MIN_SIZE = 256;
446 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
447 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
448 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000449
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000450 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000451 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
452
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000453 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000454 int origWidth = desc.fWidth;
455 int origHeight = desc.fHeight;
456 bool doubledW = false;
457 bool doubledH = false;
458
459 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000460 uint32_t v[4];
461 gen_scratch_tex_key_values(fGpu, desc, v);
462 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000463 entry = fTextureCache->findAndLock(key,
464 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000465 // if we miss, relax the fit of the flags...
466 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000467 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000468 break;
469 }
470 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
471 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
472 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
473 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
474 } else if (!doubledW) {
475 desc.fFlags = inDesc.fFlags;
476 desc.fWidth *= 2;
477 doubledW = true;
478 } else if (!doubledH) {
479 desc.fFlags = inDesc.fFlags;
480 desc.fWidth = origWidth;
481 desc.fHeight *= 2;
482 doubledH = true;
483 } else {
484 break;
485 }
486
487 } while (true);
488
489 if (NULL == entry) {
490 desc.fFlags = inDesc.fFlags;
491 desc.fWidth = origWidth;
492 desc.fHeight = origHeight;
493 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
494 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000495 uint32_t v[4];
496 gen_scratch_tex_key_values(fGpu, desc, v);
497 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000498 entry = fTextureCache->createAndLock(key, texture);
499 }
500 }
501
502 // If the caller gives us the same desc/sampler twice we don't want
503 // to return the same texture the second time (unless it was previously
504 // released). So we detach the entry from the cache and reattach at release.
505 if (NULL != entry) {
506 fTextureCache->detach(entry);
507 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000508 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000509}
510
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000511void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000512 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000513 // If this is a scratch texture we detached it from the cache
514 // while it was locked (to avoid two callers simultaneously getting
515 // the same texture).
516 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
517 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000518 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000519 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000520 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000521}
522
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000523GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000524 void* srcData,
525 size_t rowBytes) {
526 return fGpu->createTexture(desc, srcData, rowBytes);
527}
528
529void GrContext::getTextureCacheLimits(int* maxTextures,
530 size_t* maxTextureBytes) const {
531 fTextureCache->getLimits(maxTextures, maxTextureBytes);
532}
533
534void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
535 fTextureCache->setLimits(maxTextures, maxTextureBytes);
536}
537
bsalomon@google.com91958362011-06-13 17:58:13 +0000538int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000539 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000540}
541
542int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000543 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000544}
545
546///////////////////////////////////////////////////////////////////////////////
547
bsalomon@google.come269f212011-11-07 13:29:52 +0000548GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
549 return fGpu->createPlatformTexture(desc);
550}
551
552GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
553 return fGpu->createPlatformRenderTarget(desc);
554}
555
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000556GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
557 // validate flags here so that GrGpu subclasses don't have to check
558 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
559 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000560 return NULL;
561 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000562 if (desc.fSampleCnt &&
563 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000564 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000565 }
566 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
567 desc.fSampleCnt &&
568 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
569 return NULL;
570 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000571 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000572}
573
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000574///////////////////////////////////////////////////////////////////////////////
575
bsalomon@google.com27847de2011-02-22 20:59:41 +0000576bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000577 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000578 const GrDrawTarget::Caps& caps = fGpu->getCaps();
579 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000580 return false;
581 }
582
bsalomon@google.com27847de2011-02-22 20:59:41 +0000583 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
584
585 if (!isPow2) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000586 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
587 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000588 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000589 return false;
590 }
591 }
592 return true;
593}
594
595////////////////////////////////////////////////////////////////////////////////
596
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000597const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
598
bsalomon@google.com27847de2011-02-22 20:59:41 +0000599void GrContext::setClip(const GrClip& clip) {
600 fGpu->setClip(clip);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000601 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000602}
603
604void GrContext::setClip(const GrIRect& rect) {
605 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000606 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000607 fGpu->setClip(clip);
608}
609
610////////////////////////////////////////////////////////////////////////////////
611
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000612void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000613 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000614 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000615}
616
617void GrContext::drawPaint(const GrPaint& paint) {
618 // set rect to be big enough to fill the space, but not super-huge, so we
619 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000620 GrRect r;
621 r.setLTRB(0, 0,
622 GrIntToScalar(getRenderTarget()->width()),
623 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000624 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000625 SkTLazy<GrPaint> tmpPaint;
626 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000627 GrDrawState* drawState = fGpu->drawState();
628 GrAutoMatrix am;
629
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000630 // We attempt to map r by the inverse matrix and draw that. mapRect will
631 // map the four corners and bound them with a new rect. This will not
632 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000633 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000634 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000635 GrPrintf("Could not invert matrix");
636 return;
637 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000638 inverse.mapRect(&r);
639 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000640 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000641 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000642 GrPrintf("Could not invert matrix");
643 return;
644 }
645 tmpPaint.set(paint);
646 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
647 p = tmpPaint.get();
648 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000649 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000650 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000651 // by definition this fills the entire clip, no need for AA
652 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000653 if (!tmpPaint.isValid()) {
654 tmpPaint.set(paint);
655 p = tmpPaint.get();
656 }
657 GrAssert(p == tmpPaint.get());
658 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000659 }
660 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000661}
662
bsalomon@google.com205d4602011-04-25 12:43:45 +0000663////////////////////////////////////////////////////////////////////////////////
664
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000665namespace {
666inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
667 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
668}
669}
670
bsalomon@google.com91958362011-06-13 17:58:13 +0000671struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000672 enum Downsample {
673 k4x4TwoPass_Downsample,
674 k4x4SinglePass_Downsample,
675 kFSAA_Downsample
676 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000677 int fTileSizeX;
678 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000679 int fTileCountX;
680 int fTileCountY;
681 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000682 GrAutoScratchTexture fOffscreen0;
683 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000684 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000685 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000686};
687
bsalomon@google.com471d4712011-08-23 15:45:25 +0000688bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000689 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000690#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000691 return false;
692#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000693 // Line primitves are always rasterized as 1 pixel wide.
694 // Super-sampling would make them too thin but MSAA would be OK.
695 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000696 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000697 return false;
698 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000699 if (target->getDrawState().getRenderTarget()->isMultisampled()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000700 return false;
701 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000702 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000703#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000704 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000705#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000706 return false;
707 }
708 return true;
709#endif
710}
711
bsalomon@google.com91958362011-06-13 17:58:13 +0000712bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000713 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000714 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000715 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000716 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000717
718 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000719
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000720 GrAssert(NULL == record->fOffscreen0.texture());
721 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000722 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000723
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000724 int boundW = boundRect.width();
725 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000726
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000727 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000728
729 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
730 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
731
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000732 if (requireStencil) {
733 desc.fFlags = kRenderTarget_GrTextureFlagBit;
734 } else {
735 desc.fFlags = kRenderTarget_GrTextureFlagBit |
736 kNoStencil_GrTextureFlagBit;
737 }
738
bsalomon@google.comc4364992011-11-07 15:54:49 +0000739 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000740
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000741 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000742 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000743 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000744 desc.fAALevel = kMed_GrAALevel;
745 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000746 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000747 OffscreenRecord::k4x4SinglePass_Downsample :
748 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000749 record->fScale = OFFSCREEN_SSAA_SCALE;
750 // both downsample paths assume this
751 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000752 desc.fAALevel = kNone_GrAALevel;
753 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000754
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000755 desc.fWidth *= record->fScale;
756 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000757 record->fOffscreen0.set(this, desc);
758 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000759 return false;
760 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000761 // the approximate lookup might have given us some slop space, might as well
762 // use it when computing the tiles size.
763 // these are scale values, will adjust after considering
764 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000765 record->fTileSizeX = record->fOffscreen0.texture()->width();
766 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000767
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000768 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000769 desc.fWidth /= 2;
770 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000771 record->fOffscreen1.set(this, desc);
772 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000773 return false;
774 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000775 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000776 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000777 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000778 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000779 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000780 record->fTileSizeX /= record->fScale;
781 record->fTileSizeY /= record->fScale;
782
783 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
784 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
785
tomhudson@google.com237a4612011-07-19 15:44:00 +0000786 record->fClip = target->getClip();
787
bsalomon@google.com91958362011-06-13 17:58:13 +0000788 target->saveCurrentDrawState(&record->fSavedState);
789 return true;
790}
791
792void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
793 const GrIRect& boundRect,
794 int tileX, int tileY,
795 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000796
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000797 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000798 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000799
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000800 GrPaint tempPaint;
801 tempPaint.reset();
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000802 this->setPaint(tempPaint, target);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000803 GrDrawState* drawState = target->drawState();
804 drawState->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000805#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000806 target->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000807#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000808
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000809 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000810 int left = boundRect.fLeft + tileX * record->fTileSizeX;
811 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000812 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000813 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000814 GrMatrix scaleM;
815 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000816 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000817
bsalomon@google.com91958362011-06-13 17:58:13 +0000818 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000819 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000820 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000821 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000822 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
823 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000824 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000825#if 0
826 // visualize tile boundaries by setting edges of offscreen to white
827 // and interior to tranparent. black.
828 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000829
bsalomon@google.com91958362011-06-13 17:58:13 +0000830 static const int gOffset = 2;
831 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
832 record->fScale * w - gOffset,
833 record->fScale * h - gOffset);
834 target->clear(&clear2, 0x0);
835#else
836 target->clear(&clear, 0x0);
837#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000838}
839
bsalomon@google.com91958362011-06-13 17:58:13 +0000840void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000841 const GrPaint& paint,
842 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000843 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000844 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000845 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000846 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000847 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000848 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000849 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
850 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000851 tileRect.fRight = (tileX == record->fTileCountX-1) ?
852 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000853 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000854 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
855 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000856 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000857
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000858 GrSamplerState::Filter filter;
859 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
860 filter = GrSamplerState::k4x4Downsample_Filter;
861 } else {
862 filter = GrSamplerState::kBilinear_Filter;
863 }
864
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000865 GrMatrix sampleM;
bsalomon@google.com97912912011-12-06 16:30:36 +0000866 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000867
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000868 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000869 int scale;
870
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000871 enum {
872 kOffscreenStage = GrPaint::kTotalStages,
873 };
874
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000875 GrDrawState* drawState = target->drawState();
876
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000877 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000878 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000879 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000880 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000881
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000882 // Do 2x2 downsample from first to second
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000883 drawState->setTexture(kOffscreenStage, src);
884 drawState->setRenderTarget(dst);
885 drawState->setViewMatrix(GrMatrix::I());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000886 sampleM.setScale(scale * GR_Scalar1 / src->width(),
887 scale * GR_Scalar1 / src->height());
888 sampler.setMatrix(sampleM);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000889 drawState->setSampler(kOffscreenStage, sampler);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000890 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
891 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000892 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
893
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000894 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000895 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000896 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000897 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000898 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000899 } else {
900 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
901 record->fDownsample);
902 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000903 }
904
bsalomon@google.com91958362011-06-13 17:58:13 +0000905 // setup for draw back to main RT, we use the original
906 // draw state setup by the caller plus an additional coverage
907 // stage to handle the AA resolve. Also, we use an identity
908 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000909 int stageMask = paint.getActiveStageMask();
910
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000911 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000912 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000913
914 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000915 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000916 if (drawState->getViewInverse(&invVM)) {
917 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000918 }
919 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000920 // This is important when tiling, otherwise second tile's
921 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000922 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000923
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000924 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000925 sampleM.setScale(scale * GR_Scalar1 / src->width(),
926 scale * GR_Scalar1 / src->height());
927 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000928 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
929 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000930 sampler.preConcatMatrix(sampleM);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000931 drawState->setSampler(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000932
reed@google.com20efde72011-05-09 17:00:02 +0000933 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000934 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000935 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000936 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000937}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000938
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000939void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
940 GrPathRenderer* pr,
941 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000942 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000943}
944
945////////////////////////////////////////////////////////////////////////////////
946
bsalomon@google.com27847de2011-02-22 20:59:41 +0000947/* create a triangle strip that strokes the specified triangle. There are 8
948 unique vertices, but we repreat the last 2 to close up. Alternatively we
949 could use an indices array, and then only send 8 verts, but not sure that
950 would be faster.
951 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000952static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000953 GrScalar width) {
954 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000955 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000956
957 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
958 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
959 verts[2].set(rect.fRight - rad, rect.fTop + rad);
960 verts[3].set(rect.fRight + rad, rect.fTop - rad);
961 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
962 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
963 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
964 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
965 verts[8] = verts[0];
966 verts[9] = verts[1];
967}
968
bsalomon@google.com205d4602011-04-25 12:43:45 +0000969static void setInsetFan(GrPoint* pts, size_t stride,
970 const GrRect& r, GrScalar dx, GrScalar dy) {
971 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
972}
973
974static const uint16_t gFillAARectIdx[] = {
975 0, 1, 5, 5, 4, 0,
976 1, 2, 6, 6, 5, 1,
977 2, 3, 7, 7, 6, 2,
978 3, 0, 4, 4, 7, 3,
979 4, 5, 6, 6, 7, 4,
980};
981
982int GrContext::aaFillRectIndexCount() const {
983 return GR_ARRAY_COUNT(gFillAARectIdx);
984}
985
986GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
987 if (NULL == fAAFillRectIndexBuffer) {
988 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
989 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000990 if (NULL != fAAFillRectIndexBuffer) {
991 #if GR_DEBUG
992 bool updated =
993 #endif
994 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
995 sizeof(gFillAARectIdx));
996 GR_DEBUGASSERT(updated);
997 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000998 }
999 return fAAFillRectIndexBuffer;
1000}
1001
1002static const uint16_t gStrokeAARectIdx[] = {
1003 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
1004 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
1005 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
1006 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
1007
1008 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1009 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
1010 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
1011 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
1012
1013 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1014 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
1015 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
1016 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1017};
1018
1019int GrContext::aaStrokeRectIndexCount() const {
1020 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1021}
1022
1023GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1024 if (NULL == fAAStrokeRectIndexBuffer) {
1025 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1026 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001027 if (NULL != fAAStrokeRectIndexBuffer) {
1028 #if GR_DEBUG
1029 bool updated =
1030 #endif
1031 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1032 sizeof(gStrokeAARectIdx));
1033 GR_DEBUGASSERT(updated);
1034 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001035 }
1036 return fAAStrokeRectIndexBuffer;
1037}
1038
bsalomon@google.coma3108262011-10-10 14:08:47 +00001039static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1040 bool useCoverage) {
1041 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001042 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001043 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001044 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1045 }
1046 }
1047 if (useCoverage) {
1048 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1049 } else {
1050 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1051 }
1052 return layout;
1053}
1054
bsalomon@google.com205d4602011-04-25 12:43:45 +00001055void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001056 const GrRect& devRect,
1057 bool useVertexCoverage) {
1058 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001059
1060 size_t vsize = GrDrawTarget::VertexSize(layout);
1061
1062 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001063 if (!geo.succeeded()) {
1064 GrPrintf("Failed to get space for vertices!\n");
1065 return;
1066 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001067 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1068 if (NULL == indexBuffer) {
1069 GrPrintf("Failed to create index buffer!\n");
1070 return;
1071 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001072
1073 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1074
1075 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1076 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1077
1078 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1079 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1080
1081 verts += sizeof(GrPoint);
1082 for (int i = 0; i < 4; ++i) {
1083 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1084 }
1085
bsalomon@google.coma3108262011-10-10 14:08:47 +00001086 GrColor innerColor;
1087 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001088 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001089 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001090 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001091 }
1092
bsalomon@google.com205d4602011-04-25 12:43:45 +00001093 verts += 4 * vsize;
1094 for (int i = 0; i < 4; ++i) {
1095 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1096 }
1097
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001098 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001099
1100 target->drawIndexed(kTriangles_PrimitiveType, 0,
1101 0, 8, this->aaFillRectIndexCount());
1102}
1103
bsalomon@google.coma3108262011-10-10 14:08:47 +00001104void GrContext::strokeAARect(GrDrawTarget* target,
1105 const GrRect& devRect,
1106 const GrVec& devStrokeSize,
1107 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001108 const GrScalar& dx = devStrokeSize.fX;
1109 const GrScalar& dy = devStrokeSize.fY;
1110 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1111 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1112
bsalomon@google.com205d4602011-04-25 12:43:45 +00001113 GrScalar spare;
1114 {
1115 GrScalar w = devRect.width() - dx;
1116 GrScalar h = devRect.height() - dy;
1117 spare = GrMin(w, h);
1118 }
1119
1120 if (spare <= 0) {
1121 GrRect r(devRect);
1122 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001123 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001124 return;
1125 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001126 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001127 size_t vsize = GrDrawTarget::VertexSize(layout);
1128
1129 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001130 if (!geo.succeeded()) {
1131 GrPrintf("Failed to get space for vertices!\n");
1132 return;
1133 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001134 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1135 if (NULL == indexBuffer) {
1136 GrPrintf("Failed to create index buffer!\n");
1137 return;
1138 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001139
1140 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1141
1142 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1143 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1144 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1145 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1146
1147 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1148 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1149 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1150 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1151
1152 verts += sizeof(GrPoint);
1153 for (int i = 0; i < 4; ++i) {
1154 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1155 }
1156
bsalomon@google.coma3108262011-10-10 14:08:47 +00001157 GrColor innerColor;
1158 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001159 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001160 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001161 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001162 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001163 verts += 4 * vsize;
1164 for (int i = 0; i < 8; ++i) {
1165 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1166 }
1167
1168 verts += 8 * vsize;
1169 for (int i = 0; i < 8; ++i) {
1170 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1171 }
1172
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001173 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001174 target->drawIndexed(kTriangles_PrimitiveType,
1175 0, 0, 16, aaStrokeRectIndexCount());
1176}
1177
reed@google.com20efde72011-05-09 17:00:02 +00001178/**
1179 * Returns true if the rects edges are integer-aligned.
1180 */
1181static bool isIRect(const GrRect& r) {
1182 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1183 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1184}
1185
bsalomon@google.com205d4602011-04-25 12:43:45 +00001186static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001187 const GrRect& rect,
1188 GrScalar width,
1189 const GrMatrix* matrix,
1190 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001191 GrRect* devRect,
1192 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001193 // we use a simple alpha ramp to do aa on axis-aligned rects
1194 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001195 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001196
bsalomon@google.coma3108262011-10-10 14:08:47 +00001197 // we are keeping around the "tweak the alpha" trick because
1198 // it is our only hope for the fixed-pipe implementation.
1199 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001200 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001201 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001202 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001203 if (target->getCaps().fSupportPerVertexCoverage) {
1204 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001205#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001206 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001207#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001208 return false;
1209 } else {
1210 *useVertexCoverage = true;
1211 }
1212 } else {
1213 GrPrintf("Rect AA dropped because no support for coverage.\n");
1214 return false;
1215 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001216 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001217 const GrDrawState& drawState = target->getDrawState();
1218 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001219 return false;
1220 }
1221
bsalomon@google.com471d4712011-08-23 15:45:25 +00001222 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001223 return false;
1224 }
1225
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001226 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001227 return false;
1228 }
1229
1230 if (NULL != matrix &&
1231 !matrix->preservesAxisAlignment()) {
1232 return false;
1233 }
1234
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001235 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001236 if (NULL != matrix) {
1237 combinedMatrix->preConcat(*matrix);
1238 GrAssert(combinedMatrix->preservesAxisAlignment());
1239 }
1240
1241 combinedMatrix->mapRect(devRect, rect);
1242 devRect->sort();
1243
1244 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001245 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001246 } else {
1247 return true;
1248 }
1249}
1250
bsalomon@google.com27847de2011-02-22 20:59:41 +00001251void GrContext::drawRect(const GrPaint& paint,
1252 const GrRect& rect,
1253 GrScalar width,
1254 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001255 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001256
1257 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001258 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001259
bsalomon@google.com205d4602011-04-25 12:43:45 +00001260 GrRect devRect = rect;
1261 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001262 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001263 bool needAA = paint.fAntiAlias &&
1264 !this->getRenderTarget()->isMultisampled();
1265 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1266 &combinedMatrix, &devRect,
1267 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001268
1269 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001270 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001271 if (width >= 0) {
1272 GrVec strokeSize;;
1273 if (width > 0) {
1274 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001275 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001276 strokeSize.setAbs(strokeSize);
1277 } else {
1278 strokeSize.set(GR_Scalar1, GR_Scalar1);
1279 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001280 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001281 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001282 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001283 }
1284 return;
1285 }
1286
bsalomon@google.com27847de2011-02-22 20:59:41 +00001287 if (width >= 0) {
1288 // TODO: consider making static vertex buffers for these cases.
1289 // Hairline could be done by just adding closing vertex to
1290 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001291 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1292
bsalomon@google.com27847de2011-02-22 20:59:41 +00001293 static const int worstCaseVertCount = 10;
1294 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1295
1296 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001297 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001298 return;
1299 }
1300
1301 GrPrimitiveType primType;
1302 int vertCount;
1303 GrPoint* vertex = geo.positions();
1304
1305 if (width > 0) {
1306 vertCount = 10;
1307 primType = kTriangleStrip_PrimitiveType;
1308 setStrokeRectStrip(vertex, rect, width);
1309 } else {
1310 // hairline
1311 vertCount = 5;
1312 primType = kLineStrip_PrimitiveType;
1313 vertex[0].set(rect.fLeft, rect.fTop);
1314 vertex[1].set(rect.fRight, rect.fTop);
1315 vertex[2].set(rect.fRight, rect.fBottom);
1316 vertex[3].set(rect.fLeft, rect.fBottom);
1317 vertex[4].set(rect.fLeft, rect.fTop);
1318 }
1319
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001320 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001321 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001322 GrDrawState* drawState = target->drawState();
1323 avmr.set(drawState);
1324 drawState->preConcatViewMatrix(*matrix);
1325 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001326 }
1327
1328 target->drawNonIndexed(primType, 0, vertCount);
1329 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001330#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001331 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001332 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1333 if (NULL == sqVB) {
1334 GrPrintf("Failed to create static rect vb.\n");
1335 return;
1336 }
1337 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001338 GrDrawState* drawState = target->drawState();
1339 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001340 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001341 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001342 0, rect.height(), rect.fTop,
1343 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001344
1345 if (NULL != matrix) {
1346 m.postConcat(*matrix);
1347 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001348 drawState->preConcatViewMatrix(m);
1349 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001350
bsalomon@google.com27847de2011-02-22 20:59:41 +00001351 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001352#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001353 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001354#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001355 }
1356}
1357
1358void GrContext::drawRectToRect(const GrPaint& paint,
1359 const GrRect& dstRect,
1360 const GrRect& srcRect,
1361 const GrMatrix* dstMatrix,
1362 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001363 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001364
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001365 // srcRect refers to paint's first texture
1366 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001367 drawRect(paint, dstRect, -1, dstMatrix);
1368 return;
1369 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001370
bsalomon@google.com27847de2011-02-22 20:59:41 +00001371 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1372
1373#if GR_STATIC_RECT_VB
1374 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001375 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001376 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001377 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001378
1379 GrMatrix m;
1380
1381 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1382 0, dstRect.height(), dstRect.fTop,
1383 0, 0, GrMatrix::I()[8]);
1384 if (NULL != dstMatrix) {
1385 m.postConcat(*dstMatrix);
1386 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001387 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001388
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001389 // srcRect refers to first stage
1390 int otherStageMask = paint.getActiveStageMask() &
1391 (~(1 << GrPaint::kFirstTextureStage));
1392 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001393 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001394 }
1395
bsalomon@google.com27847de2011-02-22 20:59:41 +00001396 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1397 0, srcRect.height(), srcRect.fTop,
1398 0, 0, GrMatrix::I()[8]);
1399 if (NULL != srcMatrix) {
1400 m.postConcat(*srcMatrix);
1401 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001402 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001403
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001404 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1405 if (NULL == sqVB) {
1406 GrPrintf("Failed to create static rect vb.\n");
1407 return;
1408 }
1409 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001410 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1411#else
1412
1413 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001414#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001415 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001416#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001417 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1418#endif
1419
tomhudson@google.com93813632011-10-27 20:21:16 +00001420 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1421 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001422 srcRects[0] = &srcRect;
1423 srcMatrices[0] = srcMatrix;
1424
1425 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1426#endif
1427}
1428
1429void GrContext::drawVertices(const GrPaint& paint,
1430 GrPrimitiveType primitiveType,
1431 int vertexCount,
1432 const GrPoint positions[],
1433 const GrPoint texCoords[],
1434 const GrColor colors[],
1435 const uint16_t indices[],
1436 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001437 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001438
1439 GrDrawTarget::AutoReleaseGeometry geo;
1440
1441 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1442
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001443 bool hasTexCoords[GrPaint::kTotalStages] = {
1444 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1445 0 // remaining stages use positions
1446 };
1447
1448 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001449
1450 if (NULL != colors) {
1451 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001452 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001453 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001454
1455 if (sizeof(GrPoint) != vertexSize) {
1456 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001457 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001458 return;
1459 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001460 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001461 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001462 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1463 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001464 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001465 NULL,
1466 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001467 void* curVertex = geo.vertices();
1468
1469 for (int i = 0; i < vertexCount; ++i) {
1470 *((GrPoint*)curVertex) = positions[i];
1471
1472 if (texOffsets[0] > 0) {
1473 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1474 }
1475 if (colorOffset > 0) {
1476 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1477 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001478 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001479 }
1480 } else {
1481 target->setVertexSourceToArray(layout, positions, vertexCount);
1482 }
1483
bsalomon@google.com91958362011-06-13 17:58:13 +00001484 // we don't currently apply offscreen AA to this path. Need improved
1485 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001486
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001487 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001488 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001489 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001490 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001491 target->drawNonIndexed(primitiveType, 0, vertexCount);
1492 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001493}
1494
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001495///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001496
reed@google.com07f3ee12011-05-16 17:21:57 +00001497void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1498 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001499
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001500 if (path.isEmpty()) {
1501#if GR_DEBUG
1502 GrPrintf("Empty path should have been caught by canvas.\n");
1503#endif
1504 if (GrIsFillInverted(fill)) {
1505 this->drawPaint(paint);
1506 }
1507 return;
1508 }
1509
bsalomon@google.com27847de2011-02-22 20:59:41 +00001510 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001511
bsalomon@google.com289533a2011-10-27 12:34:25 +00001512 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1513
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001514 // An Assumption here is that path renderer would use some form of tweaking
1515 // the src color (either the input alpha or in the frag shader) to implement
1516 // aa. If we have some future driver-mojo path AA that can do the right
1517 // thing WRT to the blend then we'll need some query on the PR.
1518 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001519#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001520 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001521#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001522 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001523 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001524
1525 bool doOSAA = false;
1526 GrPathRenderer* pr = NULL;
1527 if (prAA) {
1528 pr = this->getPathRenderer(path, fill, true);
1529 if (NULL == pr) {
1530 prAA = false;
1531 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1532 pr = this->getPathRenderer(path, fill, false);
1533 }
1534 } else {
1535 pr = this->getPathRenderer(path, fill, false);
1536 }
1537
bsalomon@google.com30085192011-08-19 15:42:31 +00001538 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001539#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001540 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001541#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001542 return;
1543 }
1544
bsalomon@google.com289533a2011-10-27 12:34:25 +00001545 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001546 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001547
bsalomon@google.com289533a2011-10-27 12:34:25 +00001548 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001549 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001550 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001551 // compute bounds as intersection of rt size, clip, and path
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001552 GrIRect bound = SkIRect::MakeWH(rt->width(), rt->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001553 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001554 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001555 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001556 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001557 return;
1558 }
1559 }
reed@google.com07f3ee12011-05-16 17:21:57 +00001560 GrRect pathBounds = path.getBounds();
1561 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001562 if (NULL != translate) {
1563 pathBounds.offset(*translate);
1564 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001565 target->getDrawState().getViewMatrix().mapRect(&pathBounds,
1566 pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001567 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001568 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001569 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001570 return;
1571 }
1572 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001573 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001574 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1575 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001576 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1577 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1578 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001579 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001580 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1581 }
1582 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001583 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001584 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001585 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1586 GrRect rect;
1587 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001588 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1589 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001590 target->drawSimpleRect(rect, NULL, stageMask);
1591 }
1592 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001593 rect.iset(clipIBounds.fLeft, bound.fTop,
1594 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001595 target->drawSimpleRect(rect, NULL, stageMask);
1596 }
1597 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001598 rect.iset(bound.fRight, bound.fTop,
1599 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001600 target->drawSimpleRect(rect, NULL, stageMask);
1601 }
1602 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001603 rect.iset(clipIBounds.fLeft, bound.fBottom,
1604 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001605 target->drawSimpleRect(rect, NULL, stageMask);
1606 }
1607 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001608 return;
1609 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001610 }
1611 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001612}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001613
bsalomon@google.com27847de2011-02-22 20:59:41 +00001614////////////////////////////////////////////////////////////////////////////////
1615
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001616bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001617 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001618}
1619
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001620void GrContext::flush(int flagsBitfield) {
1621 if (kDiscard_FlushBit & flagsBitfield) {
1622 fDrawBuffer->reset();
1623 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001624 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001625 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001626 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001627 fGpu->forceRenderTargetFlush();
1628 }
1629}
1630
1631void GrContext::flushText() {
1632 if (kText_DrawCategory == fLastDrawCategory) {
1633 flushDrawBuffer();
1634 }
1635}
1636
1637void GrContext::flushDrawBuffer() {
1638#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001639 if (fDrawBuffer) {
1640 fDrawBuffer->playback(fGpu);
1641 fDrawBuffer->reset();
1642 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001643#endif
1644}
1645
bsalomon@google.com6f379512011-11-16 20:36:03 +00001646void GrContext::internalWriteTexturePixels(GrTexture* texture,
1647 int left, int top,
1648 int width, int height,
1649 GrPixelConfig config,
1650 const void* buffer,
1651 size_t rowBytes,
1652 uint32_t flags) {
1653 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001654 ASSERT_OWNED_RESOURCE(texture);
1655
bsalomon@google.com6f379512011-11-16 20:36:03 +00001656 if (!(kDontFlush_PixelOpsFlag & flags)) {
1657 this->flush();
1658 }
1659 // TODO: use scratch texture to perform conversion
1660 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1661 GrPixelConfigIsUnpremultiplied(config)) {
1662 return;
1663 }
1664
1665 fGpu->writeTexturePixels(texture, left, top, width, height,
1666 config, buffer, rowBytes);
1667}
1668
1669bool GrContext::internalReadTexturePixels(GrTexture* texture,
1670 int left, int top,
1671 int width, int height,
1672 GrPixelConfig config,
1673 void* buffer,
1674 size_t rowBytes,
1675 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001676 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001677 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001678
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001679 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001680 GrRenderTarget* target = texture->asRenderTarget();
1681 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001682 return this->internalReadRenderTargetPixels(target,
1683 left, top, width, height,
1684 config, buffer, rowBytes,
1685 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001686 } else {
1687 return false;
1688 }
1689}
1690
bsalomon@google.com6f379512011-11-16 20:36:03 +00001691bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1692 int left, int top,
1693 int width, int height,
1694 GrPixelConfig config,
1695 void* buffer,
1696 size_t rowBytes,
1697 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001698 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001699 ASSERT_OWNED_RESOURCE(target);
1700
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001701 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001702 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001703 if (NULL == target) {
1704 return false;
1705 }
1706 }
1707
1708 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1709 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1710 // not supported at this time.
1711 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1712 !GrPixelConfigIsUnpremultiplied(config)) {
1713 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001714 }
1715
bsalomon@google.com6f379512011-11-16 20:36:03 +00001716 if (!(kDontFlush_PixelOpsFlag & flags)) {
1717 this->flush();
1718 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001719
1720 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001721 bool swapRAndB = NULL != src &&
1722 fGpu->preferredReadPixelsConfig(config) ==
1723 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001724
1725 bool flipY = NULL != src &&
1726 fGpu->readPixelsWillPayForYFlip(target, left, top,
1727 width, height, config,
1728 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001729 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1730 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001731
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001732 if (NULL == src && alphaConversion) {
1733 // we should fallback to cpu conversion here. This could happen when
1734 // we were given an external render target by the client that is not
1735 // also a texture (e.g. FBO 0 in GL)
1736 return false;
1737 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001738 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001739 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001740 if (flipY || swapRAndB || alphaConversion) {
1741 GrAssert(NULL != src);
1742 if (swapRAndB) {
1743 config = GrPixelConfigSwapRAndB(config);
1744 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001745 }
1746 // Make the scratch a render target because we don't have a robust
1747 // readTexturePixels as of yet (it calls this function).
1748 const GrTextureDesc desc = {
1749 kRenderTarget_GrTextureFlagBit,
1750 kNone_GrAALevel,
1751 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001752 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001753 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001754
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001755 // When a full readback is faster than a partial we could always make
1756 // the scratch exactly match the passed rect. However, if we see many
1757 // different size rectangles we will trash our texture cache and pay the
1758 // cost of creating and destroying many textures. So, we only request
1759 // an exact match when the caller is reading an entire RT.
1760 ScratchTexMatch match = kApprox_ScratchTexMatch;
1761 if (0 == left &&
1762 0 == top &&
1763 target->width() == width &&
1764 target->height() == height &&
1765 fGpu->fullReadPixelsIsFasterThanPartial()) {
1766 match = kExact_ScratchTexMatch;
1767 }
1768 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001769 GrTexture* texture = ast.texture();
1770 if (!texture) {
1771 return false;
1772 }
1773 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001774 GrAssert(NULL != target);
1775
1776 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001777 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001778 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001779 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001780
bsalomon@google.comc4364992011-11-07 15:54:49 +00001781 GrMatrix matrix;
1782 if (flipY) {
1783 matrix.setTranslate(SK_Scalar1 * left,
1784 SK_Scalar1 * (top + height));
1785 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1786 } else {
1787 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1788 }
1789 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com97912912011-12-06 16:30:36 +00001790 GrSamplerState sampler;
1791 sampler.reset(GrSamplerState::kClamp_WrapMode,
1792 GrSamplerState::kNearest_Filter,
1793 matrix);
1794 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001795 drawState->setSampler(0, sampler);
1796 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001797 GrRect rect;
1798 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1799 fGpu->drawSimpleRect(rect, NULL, 0x1);
1800 left = 0;
1801 top = 0;
1802 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001803 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001804 left, top, width, height,
1805 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001806}
1807
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001808void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1809 if (NULL == src || NULL == dst) {
1810 return;
1811 }
1812 ASSERT_OWNED_RESOURCE(src);
1813
1814 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001815 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001816 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001817 drawState->setRenderTarget(dst);
bsalomon@google.com97912912011-12-06 16:30:36 +00001818 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001819 GrSamplerState::kNearest_Filter);
1820 GrMatrix sampleM;
1821 sampleM.setIDiv(src->width(), src->height());
1822 sampler.setMatrix(sampleM);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001823 drawState->setTexture(0, src);
1824 drawState->setSampler(0, sampler);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001825 SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height());
1826 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1827}
1828
bsalomon@google.com6f379512011-11-16 20:36:03 +00001829void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1830 int left, int top,
1831 int width, int height,
1832 GrPixelConfig config,
1833 const void* buffer,
1834 size_t rowBytes,
1835 uint32_t flags) {
1836 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001837 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001838
1839 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001840 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001841 if (NULL == target) {
1842 return;
1843 }
1844 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001845
1846 // TODO: when underlying api has a direct way to do this we should use it
1847 // (e.g. glDrawPixels on desktop GL).
1848
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001849 // If the RT is also a texture and we don't have to do PM/UPM conversion
1850 // then take the texture path, which we expect to be at least as fast or
1851 // faster since it doesn't use an intermediate texture as we do below.
1852
1853#if !GR_MAC_BUILD
1854 // At least some drivers on the Mac get confused when glTexImage2D is called
1855 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1856 // determine what OS versions and/or HW is affected.
1857 if (NULL != target->asTexture() &&
1858 GrPixelConfigIsUnpremultiplied(target->config()) ==
1859 GrPixelConfigIsUnpremultiplied(config)) {
1860
1861 this->internalWriteTexturePixels(target->asTexture(),
1862 left, top, width, height,
1863 config, buffer, rowBytes, flags);
1864 return;
1865 }
1866#endif
1867
1868 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1869 GrPixelConfigSwapRAndB(config);
1870 if (swapRAndB) {
1871 config = GrPixelConfigSwapRAndB(config);
1872 }
1873
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001874 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001875 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001876 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001877 GrAutoScratchTexture ast(this, desc);
1878 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001879 if (NULL == texture) {
1880 return;
1881 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001882 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1883 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001884
bsalomon@google.com27847de2011-02-22 20:59:41 +00001885 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001886 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001887 reset_draw_state(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001888
1889 GrMatrix matrix;
1890 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001891 drawState->setViewMatrix(matrix);
1892 drawState->setRenderTarget(target);
1893 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001894
bsalomon@google.com5c638652011-07-18 19:31:59 +00001895 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com97912912011-12-06 16:30:36 +00001896 GrSamplerState sampler;
1897 sampler.reset(GrSamplerState::kClamp_WrapMode,
1898 GrSamplerState::kNearest_Filter,
1899 matrix);
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001900 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001901 drawState->setSampler(0, sampler);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001902
1903 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1904 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001905 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001906 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1907 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001908 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001909 return;
1910 }
1911 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1912 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1913}
1914////////////////////////////////////////////////////////////////////////////////
1915
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001916void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001917 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001918
1919 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1920 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001921 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001922 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001923 drawState->setSampler(s, paint.getTextureSampler(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001924 }
1925
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001926 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001927
1928 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1929 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001930 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001931 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001932 drawState->setSampler(s, paint.getMaskSampler(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001933 }
1934
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001935 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001936
1937 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001938 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001939 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001940 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001941 }
1942 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001943 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001944 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001945 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001946 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001947 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001948 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001949
1950 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1951 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1952 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001953}
1954
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001955GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001956 DrawCategory category) {
1957 if (category != fLastDrawCategory) {
1958 flushDrawBuffer();
1959 fLastDrawCategory = category;
1960 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001961 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001962 GrDrawTarget* target = fGpu;
1963 switch (category) {
1964 case kText_DrawCategory:
1965#if DEFER_TEXT_RENDERING
1966 target = fDrawBuffer;
1967 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1968#else
1969 target = fGpu;
1970#endif
1971 break;
1972 case kUnbuffered_DrawCategory:
1973 target = fGpu;
1974 break;
1975 case kBuffered_DrawCategory:
1976 target = fDrawBuffer;
1977 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1978 break;
1979 }
1980 return target;
1981}
1982
bsalomon@google.com289533a2011-10-27 12:34:25 +00001983GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1984 GrPathFill fill,
1985 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001986 if (NULL == fPathRendererChain) {
1987 fPathRendererChain =
1988 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1989 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001990 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1991 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001992}
1993
bsalomon@google.com27847de2011-02-22 20:59:41 +00001994////////////////////////////////////////////////////////////////////////////////
1995
bsalomon@google.com27847de2011-02-22 20:59:41 +00001996void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001997 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001998 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001999 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002000}
2001
2002GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002003 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002004}
2005
2006const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002007 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002008}
2009
2010const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002011 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002012}
2013
2014void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002015 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002016}
2017
2018void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002019 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002020}
2021
2022static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2023 intptr_t mask = 1 << shift;
2024 if (pred) {
2025 bits |= mask;
2026 } else {
2027 bits &= ~mask;
2028 }
2029 return bits;
2030}
2031
2032void GrContext::resetStats() {
2033 fGpu->resetStats();
2034}
2035
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002036const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002037 return fGpu->getStats();
2038}
2039
2040void GrContext::printStats() const {
2041 fGpu->printStats();
2042}
2043
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002044GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002045 fGpu = gpu;
2046 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002047 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002048
bsalomon@google.com30085192011-08-19 15:42:31 +00002049 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002050
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002051 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2052 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002053 fFontCache = new GrFontCache(fGpu);
2054
2055 fLastDrawCategory = kUnbuffered_DrawCategory;
2056
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002057 fDrawBuffer = NULL;
2058 fDrawBufferVBAllocPool = NULL;
2059 fDrawBufferIBAllocPool = NULL;
2060
bsalomon@google.com205d4602011-04-25 12:43:45 +00002061 fAAFillRectIndexBuffer = NULL;
2062 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002063
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002064 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2065 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002066 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2067 }
2068 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002069
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002070 this->setupDrawBuffer();
2071}
2072
2073void GrContext::setupDrawBuffer() {
2074
2075 GrAssert(NULL == fDrawBuffer);
2076 GrAssert(NULL == fDrawBufferVBAllocPool);
2077 GrAssert(NULL == fDrawBufferIBAllocPool);
2078
bsalomon@google.com27847de2011-02-22 20:59:41 +00002079#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002080 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002081 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002082 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2083 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002084 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002085 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002086 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002087 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2088
bsalomon@google.com471d4712011-08-23 15:45:25 +00002089 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2090 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002091 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002092#endif
2093
2094#if BATCH_RECT_TO_RECT
2095 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2096#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002097}
2098
bsalomon@google.com27847de2011-02-22 20:59:41 +00002099GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2100 GrDrawTarget* target;
2101#if DEFER_TEXT_RENDERING
2102 target = prepareToDraw(paint, kText_DrawCategory);
2103#else
2104 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2105#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002106 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002107 return target;
2108}
2109
2110const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2111 return fGpu->getQuadIndexBuffer();
2112}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002113
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002114void GrContext::convolveInX(GrTexture* texture,
2115 const SkRect& rect,
2116 const float* kernel,
2117 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002118 ASSERT_OWNED_RESOURCE(texture);
2119
bsalomon@google.com99621082011-11-15 16:47:16 +00002120 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002121 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2122}
2123
2124void GrContext::convolveInY(GrTexture* texture,
2125 const SkRect& rect,
2126 const float* kernel,
2127 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002128 ASSERT_OWNED_RESOURCE(texture);
2129
bsalomon@google.com99621082011-11-15 16:47:16 +00002130 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002131 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2132}
2133
2134void GrContext::convolve(GrTexture* texture,
2135 const SkRect& rect,
2136 float imageIncrement[2],
2137 const float* kernel,
2138 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002139 ASSERT_OWNED_RESOURCE(texture);
2140
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002141 GrDrawTarget::AutoStateRestore asr(fGpu);
2142 GrMatrix sampleM;
bsalomon@google.com97912912011-12-06 16:30:36 +00002143 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002144 GrSamplerState::kConvolution_Filter);
2145 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002146 sampleM.setIDiv(texture->width(), texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002147 sampler.setMatrix(sampleM);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002148 GrDrawState* drawState = fGpu->drawState();
2149 drawState->setSampler(0, sampler);
2150 drawState->setViewMatrix(GrMatrix::I());
2151 drawState->setTexture(0, texture);
2152 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002153 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002154 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2155}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002156
2157///////////////////////////////////////////////////////////////////////////////