blob: 70c9f6de2f73ebbc1335e9cc7231e8f2962c2b99 [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.
220void reset_target_state(GrDrawTarget* target){
221 target->setViewMatrix(GrMatrix::I());
222 target->setColorFilter(0, SkXfermode::kDst_Mode);
223 target->disableState(GrDrawTarget::kDither_StateBit |
224 GrDrawTarget::kHWAntialias_StateBit |
225 GrDrawTarget::kClip_StateBit |
226 GrDrawTarget::kNoColorWrites_StateBit |
227 GrDrawTarget::kEdgeAAConcave_StateBit);
228 target->setEdgeAAData(NULL, 0);
229 target->disableStencil();
230 target->setAlpha(0xFF);
231 target->setBlendFunc(kOne_BlendCoeff,
232 kZero_BlendCoeff);
233 target->setFirstCoverageStage(GrDrawState::kNumStages);
234 target->setDrawFace(GrDrawState::kBoth_DrawFace);
235}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000236}
237
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000238GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
239 int width,
240 int height,
241 const GrSamplerState& sampler) {
242 uint32_t v[4];
243 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
244 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000245 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
246 GrResourceCache::kNested_LockType));
247}
248
bsalomon@google.comfb309512011-11-30 14:13:48 +0000249bool GrContext::isTextureInCache(TextureKey key,
250 int width,
251 int height,
252 const GrSamplerState& sampler) const {
253 uint32_t v[4];
254 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
255 GrResourceKey resourceKey(v);
256 return fTextureCache->hasKey(resourceKey);
257}
258
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000259GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000260 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000261 uint32_t v[4];
262 gen_stencil_key_values(sb, v);
263 GrResourceKey resourceKey(v);
264 return fTextureCache->createAndLock(resourceKey, sb);
265}
266
267GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
268 int sampleCnt) {
269 uint32_t v[4];
270 gen_stencil_key_values(width, height, sampleCnt, v);
271 GrResourceKey resourceKey(v);
272 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
273 GrResourceCache::kSingle_LockType);
274 if (NULL != entry) {
275 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
276 return sb;
277 } else {
278 return NULL;
279 }
280}
281
282void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000283 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000284 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000285}
286
287static void stretchImage(void* dst,
288 int dstW,
289 int dstH,
290 void* src,
291 int srcW,
292 int srcH,
293 int bpp) {
294 GrFixed dx = (srcW << 16) / dstW;
295 GrFixed dy = (srcH << 16) / dstH;
296
297 GrFixed y = dy >> 1;
298
299 int dstXLimit = dstW*bpp;
300 for (int j = 0; j < dstH; ++j) {
301 GrFixed x = dx >> 1;
302 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
303 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
304 for (int i = 0; i < dstXLimit; i += bpp) {
305 memcpy((uint8_t*) dstRow + i,
306 (uint8_t*) srcRow + (x>>16)*bpp,
307 bpp);
308 x += dx;
309 }
310 y += dy;
311 }
312}
313
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000314GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000315 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000316 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000317 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000318 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000319
320#if GR_DUMP_TEXTURE_UPLOAD
321 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
322#endif
323
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000324 TextureCacheEntry entry;
325 uint32_t v[4];
326 bool special = gen_texture_key_values(fGpu, sampler, key,
327 desc.fWidth, desc.fHeight, false, v);
328 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000329
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000330 if (special) {
331 TextureCacheEntry clampEntry =
332 findAndLockTexture(key, desc.fWidth, desc.fHeight,
333 GrSamplerState::ClampNoFilter());
334
335 if (NULL == clampEntry.texture()) {
336 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000337 GrSamplerState::ClampNoFilter(),
338 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000339 GrAssert(NULL != clampEntry.texture());
340 if (NULL == clampEntry.texture()) {
341 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000342 }
343 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000344 GrTextureDesc rtDesc = desc;
345 rtDesc.fFlags = rtDesc.fFlags |
346 kRenderTarget_GrTextureFlagBit |
347 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000348 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
349 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000350
351 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
352
353 if (NULL != texture) {
354 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000355 reset_target_state(fGpu);
356
bsalomon@google.com27847de2011-02-22 20:59:41 +0000357 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000358 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000359
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000360 GrSamplerState::Filter filter;
361 // if filtering is not desired then we want to ensure all
362 // texels in the resampled image are copies of texels from
363 // the original.
364 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
365 filter = GrSamplerState::kNearest_Filter;
366 } else {
367 filter = GrSamplerState::kBilinear_Filter;
368 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000369 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
370 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000371 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000372 fGpu->setSamplerState(0, stretchSampler);
373
374 static const GrVertexLayout layout =
375 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
376 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
377
378 if (arg.succeeded()) {
379 GrPoint* verts = (GrPoint*) arg.vertices();
380 verts[0].setIRectFan(0, 0,
381 texture->width(),
382 texture->height(),
383 2*sizeof(GrPoint));
384 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
385 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
386 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000387 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000388 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000389 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000390 } else {
391 // TODO: Our CPU stretch doesn't filter. But we create separate
392 // stretched textures when the sampler state is either filtered or
393 // not. Either implement filtered stretch blit on CPU or just create
394 // one when FBO case fails.
395
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000396 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000397 // no longer need to clamp at min RT size.
398 rtDesc.fWidth = GrNextPow2(desc.fWidth);
399 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000400 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000401 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000402 rtDesc.fWidth *
403 rtDesc.fHeight);
404 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
405 srcData, desc.fWidth, desc.fHeight, bpp);
406
407 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
408
409 GrTexture* texture = fGpu->createTexture(rtDesc,
410 stretchedPixels.get(),
411 stretchedRowBytes);
412 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000413 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000414 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000415 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000416
417 } else {
418 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
419 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000420 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000421 }
422 }
423 return entry;
424}
425
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000426namespace {
427inline void gen_scratch_tex_key_values(const GrGpu* gpu,
428 const GrTextureDesc& desc,
429 uint32_t v[4]) {
430 // Instead of a client-provided key of the texture contents
431 // we create a key of from the descriptor.
432 GrContext::TextureKey descKey = desc.fAALevel |
433 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000434 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000435 // this code path isn't friendly to tiling with NPOT restricitons
436 // We just pass ClampNoFilter()
437 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
438 desc.fWidth, desc.fHeight, true, v);
439}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000440}
441
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000442GrContext::TextureCacheEntry GrContext::lockScratchTexture(
443 const GrTextureDesc& inDesc,
444 ScratchTexMatch match) {
445
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000446 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000447 if (kExact_ScratchTexMatch != match) {
448 // bin by pow2 with a reasonable min
449 static const int MIN_SIZE = 256;
450 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
451 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
452 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000453
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000454 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000455 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
456
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000457 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000458 int origWidth = desc.fWidth;
459 int origHeight = desc.fHeight;
460 bool doubledW = false;
461 bool doubledH = false;
462
463 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000464 uint32_t v[4];
465 gen_scratch_tex_key_values(fGpu, desc, v);
466 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000467 entry = fTextureCache->findAndLock(key,
468 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000469 // if we miss, relax the fit of the flags...
470 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000471 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000472 break;
473 }
474 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
475 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
476 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
477 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
478 } else if (!doubledW) {
479 desc.fFlags = inDesc.fFlags;
480 desc.fWidth *= 2;
481 doubledW = true;
482 } else if (!doubledH) {
483 desc.fFlags = inDesc.fFlags;
484 desc.fWidth = origWidth;
485 desc.fHeight *= 2;
486 doubledH = true;
487 } else {
488 break;
489 }
490
491 } while (true);
492
493 if (NULL == entry) {
494 desc.fFlags = inDesc.fFlags;
495 desc.fWidth = origWidth;
496 desc.fHeight = origHeight;
497 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
498 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000499 uint32_t v[4];
500 gen_scratch_tex_key_values(fGpu, desc, v);
501 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000502 entry = fTextureCache->createAndLock(key, texture);
503 }
504 }
505
506 // If the caller gives us the same desc/sampler twice we don't want
507 // to return the same texture the second time (unless it was previously
508 // released). So we detach the entry from the cache and reattach at release.
509 if (NULL != entry) {
510 fTextureCache->detach(entry);
511 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000512 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000513}
514
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000515void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000516 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000517 // If this is a scratch texture we detached it from the cache
518 // while it was locked (to avoid two callers simultaneously getting
519 // the same texture).
520 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
521 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000522 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000523 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000524 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000525}
526
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000527GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000528 void* srcData,
529 size_t rowBytes) {
530 return fGpu->createTexture(desc, srcData, rowBytes);
531}
532
533void GrContext::getTextureCacheLimits(int* maxTextures,
534 size_t* maxTextureBytes) const {
535 fTextureCache->getLimits(maxTextures, maxTextureBytes);
536}
537
538void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
539 fTextureCache->setLimits(maxTextures, maxTextureBytes);
540}
541
bsalomon@google.com91958362011-06-13 17:58:13 +0000542int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000543 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000544}
545
546int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000547 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000548}
549
550///////////////////////////////////////////////////////////////////////////////
551
bsalomon@google.come269f212011-11-07 13:29:52 +0000552GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
553 return fGpu->createPlatformTexture(desc);
554}
555
556GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
557 return fGpu->createPlatformRenderTarget(desc);
558}
559
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000560GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
561 // validate flags here so that GrGpu subclasses don't have to check
562 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
563 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000564 return NULL;
565 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000566 if (desc.fSampleCnt &&
567 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000568 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000569 }
570 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
571 desc.fSampleCnt &&
572 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
573 return NULL;
574 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000575 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000576}
577
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000578///////////////////////////////////////////////////////////////////////////////
579
bsalomon@google.com27847de2011-02-22 20:59:41 +0000580bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000581 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000582 const GrDrawTarget::Caps& caps = fGpu->getCaps();
583 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000584 return false;
585 }
586
bsalomon@google.com27847de2011-02-22 20:59:41 +0000587 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
588
589 if (!isPow2) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000590 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
591 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000592 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000593 return false;
594 }
595 }
596 return true;
597}
598
599////////////////////////////////////////////////////////////////////////////////
600
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000601const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
602
bsalomon@google.com27847de2011-02-22 20:59:41 +0000603void GrContext::setClip(const GrClip& clip) {
604 fGpu->setClip(clip);
605 fGpu->enableState(GrDrawTarget::kClip_StateBit);
606}
607
608void GrContext::setClip(const GrIRect& rect) {
609 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000610 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000611 fGpu->setClip(clip);
612}
613
614////////////////////////////////////////////////////////////////////////////////
615
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000616void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000617 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000618 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000619}
620
621void GrContext::drawPaint(const GrPaint& paint) {
622 // set rect to be big enough to fill the space, but not super-huge, so we
623 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000624 GrRect r;
625 r.setLTRB(0, 0,
626 GrIntToScalar(getRenderTarget()->width()),
627 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000628 GrAutoMatrix am;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000629 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000630 SkTLazy<GrPaint> tmpPaint;
631 const GrPaint* p = &paint;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000632 // We attempt to map r by the inverse matrix and draw that. mapRect will
633 // map the four corners and bound them with a new rect. This will not
634 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000635 if (!this->getMatrix().hasPerspective()) {
636 if (!fGpu->getViewInverse(&inverse)) {
637 GrPrintf("Could not invert matrix");
638 return;
639 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000640 inverse.mapRect(&r);
641 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000642 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
643 if (!fGpu->getViewInverse(&inverse)) {
644 GrPrintf("Could not invert matrix");
645 return;
646 }
647 tmpPaint.set(paint);
648 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
649 p = tmpPaint.get();
650 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000651 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000652 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000653 // by definition this fills the entire clip, no need for AA
654 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000655 if (!tmpPaint.isValid()) {
656 tmpPaint.set(paint);
657 p = tmpPaint.get();
658 }
659 GrAssert(p == tmpPaint.get());
660 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000661 }
662 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000663}
664
bsalomon@google.com205d4602011-04-25 12:43:45 +0000665////////////////////////////////////////////////////////////////////////////////
666
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000667namespace {
668inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
669 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
670}
671}
672
bsalomon@google.com91958362011-06-13 17:58:13 +0000673struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000674 enum Downsample {
675 k4x4TwoPass_Downsample,
676 k4x4SinglePass_Downsample,
677 kFSAA_Downsample
678 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000679 int fTileSizeX;
680 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000681 int fTileCountX;
682 int fTileCountY;
683 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000684 GrAutoScratchTexture fOffscreen0;
685 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000686 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000687 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000688};
689
bsalomon@google.com471d4712011-08-23 15:45:25 +0000690bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000691 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000692#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000693 return false;
694#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000695 // Line primitves are always rasterized as 1 pixel wide.
696 // Super-sampling would make them too thin but MSAA would be OK.
697 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000698 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000699 return false;
700 }
701 if (target->getRenderTarget()->isMultisampled()) {
702 return false;
703 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000704 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000705#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000706 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000707#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000708 return false;
709 }
710 return true;
711#endif
712}
713
bsalomon@google.com91958362011-06-13 17:58:13 +0000714bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000715 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000716 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000717 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000718 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000719
720 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000721
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000722 GrAssert(NULL == record->fOffscreen0.texture());
723 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000724 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000725
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000726 int boundW = boundRect.width();
727 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000728
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000729 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000730
731 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
732 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
733
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000734 if (requireStencil) {
735 desc.fFlags = kRenderTarget_GrTextureFlagBit;
736 } else {
737 desc.fFlags = kRenderTarget_GrTextureFlagBit |
738 kNoStencil_GrTextureFlagBit;
739 }
740
bsalomon@google.comc4364992011-11-07 15:54:49 +0000741 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000742
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000743 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000744 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000745 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000746 desc.fAALevel = kMed_GrAALevel;
747 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000748 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000749 OffscreenRecord::k4x4SinglePass_Downsample :
750 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000751 record->fScale = OFFSCREEN_SSAA_SCALE;
752 // both downsample paths assume this
753 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000754 desc.fAALevel = kNone_GrAALevel;
755 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000756
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000757 desc.fWidth *= record->fScale;
758 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000759 record->fOffscreen0.set(this, desc);
760 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000761 return false;
762 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000763 // the approximate lookup might have given us some slop space, might as well
764 // use it when computing the tiles size.
765 // these are scale values, will adjust after considering
766 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000767 record->fTileSizeX = record->fOffscreen0.texture()->width();
768 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000769
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000770 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000771 desc.fWidth /= 2;
772 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000773 record->fOffscreen1.set(this, desc);
774 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000775 return false;
776 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000777 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000778 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000779 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000780 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000781 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000782 record->fTileSizeX /= record->fScale;
783 record->fTileSizeY /= record->fScale;
784
785 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
786 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
787
tomhudson@google.com237a4612011-07-19 15:44:00 +0000788 record->fClip = target->getClip();
789
bsalomon@google.com91958362011-06-13 17:58:13 +0000790 target->saveCurrentDrawState(&record->fSavedState);
791 return true;
792}
793
794void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
795 const GrIRect& boundRect,
796 int tileX, int tileY,
797 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000798
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000799 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000800 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000801
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000802 GrPaint tempPaint;
803 tempPaint.reset();
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000804 this->setPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000805 target->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000806#if PREFER_MSAA_OFFSCREEN_AA
807 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
808#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000809
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000810 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000811 int left = boundRect.fLeft + tileX * record->fTileSizeX;
812 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000813 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000814 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000815 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000816 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000817 target->postConcatViewMatrix(scaleM);
818
bsalomon@google.com91958362011-06-13 17:58:13 +0000819 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000820 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000821 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000822 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000823 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
824 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000825 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000826#if 0
827 // visualize tile boundaries by setting edges of offscreen to white
828 // and interior to tranparent. black.
829 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000830
bsalomon@google.com91958362011-06-13 17:58:13 +0000831 static const int gOffset = 2;
832 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
833 record->fScale * w - gOffset,
834 record->fScale * h - gOffset);
835 target->clear(&clear2, 0x0);
836#else
837 target->clear(&clear, 0x0);
838#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000839}
840
bsalomon@google.com91958362011-06-13 17:58:13 +0000841void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000842 const GrPaint& paint,
843 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000844 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000845 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000846 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000847 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000848 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000849 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000850 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
851 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000852 tileRect.fRight = (tileX == record->fTileCountX-1) ?
853 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000854 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000855 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
856 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000857 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000858
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000859 GrSamplerState::Filter filter;
860 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
861 filter = GrSamplerState::k4x4Downsample_Filter;
862 } else {
863 filter = GrSamplerState::kBilinear_Filter;
864 }
865
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000866 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000867 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000868 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000869
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000870 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000871 int scale;
872
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000873 enum {
874 kOffscreenStage = GrPaint::kTotalStages,
875 };
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.com8295dc12011-05-02 12:53:34 +0000881
882 // Do 2x2 downsample from first to second
883 target->setTexture(kOffscreenStage, src);
884 target->setRenderTarget(dst);
885 target->setViewMatrix(GrMatrix::I());
886 sampleM.setScale(scale * GR_Scalar1 / src->width(),
887 scale * GR_Scalar1 / src->height());
888 sampler.setMatrix(sampleM);
889 target->setSamplerState(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;
916 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000917 target->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.
922 GrDrawTarget::AutoViewMatrixRestore avmr(target);
923
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000924 target->setViewMatrix(GrMatrix::I());
925
926 target->setTexture(kOffscreenStage, src);
927 sampleM.setScale(scale * GR_Scalar1 / src->width(),
928 scale * GR_Scalar1 / src->height());
929 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000930 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
931 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000932 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000933 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000934
reed@google.com20efde72011-05-09 17:00:02 +0000935 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000936 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000937 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000938 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000939}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000940
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000941void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
942 GrPathRenderer* pr,
943 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000944 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000945}
946
947////////////////////////////////////////////////////////////////////////////////
948
bsalomon@google.com27847de2011-02-22 20:59:41 +0000949/* create a triangle strip that strokes the specified triangle. There are 8
950 unique vertices, but we repreat the last 2 to close up. Alternatively we
951 could use an indices array, and then only send 8 verts, but not sure that
952 would be faster.
953 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000954static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000955 GrScalar width) {
956 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000957 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000958
959 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
960 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
961 verts[2].set(rect.fRight - rad, rect.fTop + rad);
962 verts[3].set(rect.fRight + rad, rect.fTop - rad);
963 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
964 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
965 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
966 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
967 verts[8] = verts[0];
968 verts[9] = verts[1];
969}
970
bsalomon@google.com205d4602011-04-25 12:43:45 +0000971static void setInsetFan(GrPoint* pts, size_t stride,
972 const GrRect& r, GrScalar dx, GrScalar dy) {
973 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
974}
975
976static const uint16_t gFillAARectIdx[] = {
977 0, 1, 5, 5, 4, 0,
978 1, 2, 6, 6, 5, 1,
979 2, 3, 7, 7, 6, 2,
980 3, 0, 4, 4, 7, 3,
981 4, 5, 6, 6, 7, 4,
982};
983
984int GrContext::aaFillRectIndexCount() const {
985 return GR_ARRAY_COUNT(gFillAARectIdx);
986}
987
988GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
989 if (NULL == fAAFillRectIndexBuffer) {
990 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
991 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000992 if (NULL != fAAFillRectIndexBuffer) {
993 #if GR_DEBUG
994 bool updated =
995 #endif
996 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
997 sizeof(gFillAARectIdx));
998 GR_DEBUGASSERT(updated);
999 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001000 }
1001 return fAAFillRectIndexBuffer;
1002}
1003
1004static const uint16_t gStrokeAARectIdx[] = {
1005 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
1006 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
1007 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
1008 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
1009
1010 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1011 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
1012 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
1013 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
1014
1015 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1016 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
1017 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
1018 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1019};
1020
1021int GrContext::aaStrokeRectIndexCount() const {
1022 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1023}
1024
1025GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1026 if (NULL == fAAStrokeRectIndexBuffer) {
1027 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1028 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001029 if (NULL != fAAStrokeRectIndexBuffer) {
1030 #if GR_DEBUG
1031 bool updated =
1032 #endif
1033 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1034 sizeof(gStrokeAARectIdx));
1035 GR_DEBUGASSERT(updated);
1036 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001037 }
1038 return fAAStrokeRectIndexBuffer;
1039}
1040
bsalomon@google.coma3108262011-10-10 14:08:47 +00001041static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1042 bool useCoverage) {
1043 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001044 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001045 if (NULL != target->getTexture(s)) {
1046 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1047 }
1048 }
1049 if (useCoverage) {
1050 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1051 } else {
1052 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1053 }
1054 return layout;
1055}
1056
bsalomon@google.com205d4602011-04-25 12:43:45 +00001057void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001058 const GrRect& devRect,
1059 bool useVertexCoverage) {
1060 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001061
1062 size_t vsize = GrDrawTarget::VertexSize(layout);
1063
1064 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001065 if (!geo.succeeded()) {
1066 GrPrintf("Failed to get space for vertices!\n");
1067 return;
1068 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001069 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1070 if (NULL == indexBuffer) {
1071 GrPrintf("Failed to create index buffer!\n");
1072 return;
1073 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001074
1075 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1076
1077 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1078 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1079
1080 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1081 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1082
1083 verts += sizeof(GrPoint);
1084 for (int i = 0; i < 4; ++i) {
1085 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1086 }
1087
bsalomon@google.coma3108262011-10-10 14:08:47 +00001088 GrColor innerColor;
1089 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001090 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001091 } else {
1092 innerColor = target->getColor();
1093 }
1094
bsalomon@google.com205d4602011-04-25 12:43:45 +00001095 verts += 4 * vsize;
1096 for (int i = 0; i < 4; ++i) {
1097 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1098 }
1099
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001100 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001101
1102 target->drawIndexed(kTriangles_PrimitiveType, 0,
1103 0, 8, this->aaFillRectIndexCount());
1104}
1105
bsalomon@google.coma3108262011-10-10 14:08:47 +00001106void GrContext::strokeAARect(GrDrawTarget* target,
1107 const GrRect& devRect,
1108 const GrVec& devStrokeSize,
1109 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001110 const GrScalar& dx = devStrokeSize.fX;
1111 const GrScalar& dy = devStrokeSize.fY;
1112 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1113 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1114
bsalomon@google.com205d4602011-04-25 12:43:45 +00001115 GrScalar spare;
1116 {
1117 GrScalar w = devRect.width() - dx;
1118 GrScalar h = devRect.height() - dy;
1119 spare = GrMin(w, h);
1120 }
1121
1122 if (spare <= 0) {
1123 GrRect r(devRect);
1124 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001125 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001126 return;
1127 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001128 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001129 size_t vsize = GrDrawTarget::VertexSize(layout);
1130
1131 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001132 if (!geo.succeeded()) {
1133 GrPrintf("Failed to get space for vertices!\n");
1134 return;
1135 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001136 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1137 if (NULL == indexBuffer) {
1138 GrPrintf("Failed to create index buffer!\n");
1139 return;
1140 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001141
1142 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1143
1144 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1145 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1146 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1147 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1148
1149 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1150 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1151 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1152 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1153
1154 verts += sizeof(GrPoint);
1155 for (int i = 0; i < 4; ++i) {
1156 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1157 }
1158
bsalomon@google.coma3108262011-10-10 14:08:47 +00001159 GrColor innerColor;
1160 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001161 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001162 } else {
1163 innerColor = target->getColor();
1164 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001165 verts += 4 * vsize;
1166 for (int i = 0; i < 8; ++i) {
1167 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1168 }
1169
1170 verts += 8 * vsize;
1171 for (int i = 0; i < 8; ++i) {
1172 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1173 }
1174
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001175 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001176 target->drawIndexed(kTriangles_PrimitiveType,
1177 0, 0, 16, aaStrokeRectIndexCount());
1178}
1179
reed@google.com20efde72011-05-09 17:00:02 +00001180/**
1181 * Returns true if the rects edges are integer-aligned.
1182 */
1183static bool isIRect(const GrRect& r) {
1184 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1185 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1186}
1187
bsalomon@google.com205d4602011-04-25 12:43:45 +00001188static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001189 const GrRect& rect,
1190 GrScalar width,
1191 const GrMatrix* matrix,
1192 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001193 GrRect* devRect,
1194 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001195 // we use a simple alpha ramp to do aa on axis-aligned rects
1196 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001197 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001198
bsalomon@google.coma3108262011-10-10 14:08:47 +00001199 // we are keeping around the "tweak the alpha" trick because
1200 // it is our only hope for the fixed-pipe implementation.
1201 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001202 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001203 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001204 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001205 if (target->getCaps().fSupportPerVertexCoverage) {
1206 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001207#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001208 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001209#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001210 return false;
1211 } else {
1212 *useVertexCoverage = true;
1213 }
1214 } else {
1215 GrPrintf("Rect AA dropped because no support for coverage.\n");
1216 return false;
1217 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001218 }
1219
1220 if (target->getRenderTarget()->isMultisampled()) {
1221 return false;
1222 }
1223
bsalomon@google.com471d4712011-08-23 15:45:25 +00001224 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001225 return false;
1226 }
1227
1228 if (!target->getViewMatrix().preservesAxisAlignment()) {
1229 return false;
1230 }
1231
1232 if (NULL != matrix &&
1233 !matrix->preservesAxisAlignment()) {
1234 return false;
1235 }
1236
1237 *combinedMatrix = target->getViewMatrix();
1238 if (NULL != matrix) {
1239 combinedMatrix->preConcat(*matrix);
1240 GrAssert(combinedMatrix->preservesAxisAlignment());
1241 }
1242
1243 combinedMatrix->mapRect(devRect, rect);
1244 devRect->sort();
1245
1246 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001247 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001248 } else {
1249 return true;
1250 }
1251}
1252
bsalomon@google.com27847de2011-02-22 20:59:41 +00001253void GrContext::drawRect(const GrPaint& paint,
1254 const GrRect& rect,
1255 GrScalar width,
1256 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001257 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001258
1259 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001260 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001261
bsalomon@google.com205d4602011-04-25 12:43:45 +00001262 GrRect devRect = rect;
1263 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001264 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001265 bool needAA = paint.fAntiAlias &&
1266 !this->getRenderTarget()->isMultisampled();
1267 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1268 &combinedMatrix, &devRect,
1269 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001270
1271 if (doAA) {
1272 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001273 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001274 GrMatrix inv;
1275 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001276 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001277 }
1278 }
1279 target->setViewMatrix(GrMatrix::I());
1280 if (width >= 0) {
1281 GrVec strokeSize;;
1282 if (width > 0) {
1283 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001284 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001285 strokeSize.setAbs(strokeSize);
1286 } else {
1287 strokeSize.set(GR_Scalar1, GR_Scalar1);
1288 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001289 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001290 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001291 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001292 }
1293 return;
1294 }
1295
bsalomon@google.com27847de2011-02-22 20:59:41 +00001296 if (width >= 0) {
1297 // TODO: consider making static vertex buffers for these cases.
1298 // Hairline could be done by just adding closing vertex to
1299 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001300 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1301
bsalomon@google.com27847de2011-02-22 20:59:41 +00001302 static const int worstCaseVertCount = 10;
1303 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1304
1305 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001306 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001307 return;
1308 }
1309
1310 GrPrimitiveType primType;
1311 int vertCount;
1312 GrPoint* vertex = geo.positions();
1313
1314 if (width > 0) {
1315 vertCount = 10;
1316 primType = kTriangleStrip_PrimitiveType;
1317 setStrokeRectStrip(vertex, rect, width);
1318 } else {
1319 // hairline
1320 vertCount = 5;
1321 primType = kLineStrip_PrimitiveType;
1322 vertex[0].set(rect.fLeft, rect.fTop);
1323 vertex[1].set(rect.fRight, rect.fTop);
1324 vertex[2].set(rect.fRight, rect.fBottom);
1325 vertex[3].set(rect.fLeft, rect.fBottom);
1326 vertex[4].set(rect.fLeft, rect.fTop);
1327 }
1328
1329 GrDrawTarget::AutoViewMatrixRestore avmr;
1330 if (NULL != matrix) {
1331 avmr.set(target);
1332 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001333 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001334 }
1335
1336 target->drawNonIndexed(primType, 0, vertCount);
1337 } else {
1338 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001339 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001340 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1341 if (NULL == sqVB) {
1342 GrPrintf("Failed to create static rect vb.\n");
1343 return;
1344 }
1345 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001346 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1347 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001348 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001349 0, rect.height(), rect.fTop,
1350 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001351
1352 if (NULL != matrix) {
1353 m.postConcat(*matrix);
1354 }
1355
1356 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001357 target->preConcatSamplerMatrices(stageMask, m);
1358
bsalomon@google.com27847de2011-02-22 20:59:41 +00001359 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1360 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001361 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001362 #endif
1363 }
1364}
1365
1366void GrContext::drawRectToRect(const GrPaint& paint,
1367 const GrRect& dstRect,
1368 const GrRect& srcRect,
1369 const GrMatrix* dstMatrix,
1370 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001371 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001372
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001373 // srcRect refers to paint's first texture
1374 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001375 drawRect(paint, dstRect, -1, dstMatrix);
1376 return;
1377 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001378
bsalomon@google.com27847de2011-02-22 20:59:41 +00001379 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1380
1381#if GR_STATIC_RECT_VB
1382 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001383
1384 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001385 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1386
1387 GrMatrix m;
1388
1389 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1390 0, dstRect.height(), dstRect.fTop,
1391 0, 0, GrMatrix::I()[8]);
1392 if (NULL != dstMatrix) {
1393 m.postConcat(*dstMatrix);
1394 }
1395 target->preConcatViewMatrix(m);
1396
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001397 // srcRect refers to first stage
1398 int otherStageMask = paint.getActiveStageMask() &
1399 (~(1 << GrPaint::kFirstTextureStage));
1400 if (otherStageMask) {
1401 target->preConcatSamplerMatrices(otherStageMask, m);
1402 }
1403
bsalomon@google.com27847de2011-02-22 20:59:41 +00001404 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1405 0, srcRect.height(), srcRect.fTop,
1406 0, 0, GrMatrix::I()[8]);
1407 if (NULL != srcMatrix) {
1408 m.postConcat(*srcMatrix);
1409 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001410 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001411
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001412 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1413 if (NULL == sqVB) {
1414 GrPrintf("Failed to create static rect vb.\n");
1415 return;
1416 }
1417 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001418 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1419#else
1420
1421 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001422#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001423 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001424#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001425 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1426#endif
1427
tomhudson@google.com93813632011-10-27 20:21:16 +00001428 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1429 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001430 srcRects[0] = &srcRect;
1431 srcMatrices[0] = srcMatrix;
1432
1433 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1434#endif
1435}
1436
1437void GrContext::drawVertices(const GrPaint& paint,
1438 GrPrimitiveType primitiveType,
1439 int vertexCount,
1440 const GrPoint positions[],
1441 const GrPoint texCoords[],
1442 const GrColor colors[],
1443 const uint16_t indices[],
1444 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001445 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001446
1447 GrDrawTarget::AutoReleaseGeometry geo;
1448
1449 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1450
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001451 bool hasTexCoords[GrPaint::kTotalStages] = {
1452 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1453 0 // remaining stages use positions
1454 };
1455
1456 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001457
1458 if (NULL != colors) {
1459 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001460 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001461 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001462
1463 if (sizeof(GrPoint) != vertexSize) {
1464 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001465 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001466 return;
1467 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001468 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001469 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001470 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1471 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001472 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001473 NULL,
1474 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001475 void* curVertex = geo.vertices();
1476
1477 for (int i = 0; i < vertexCount; ++i) {
1478 *((GrPoint*)curVertex) = positions[i];
1479
1480 if (texOffsets[0] > 0) {
1481 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1482 }
1483 if (colorOffset > 0) {
1484 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1485 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001486 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001487 }
1488 } else {
1489 target->setVertexSourceToArray(layout, positions, vertexCount);
1490 }
1491
bsalomon@google.com91958362011-06-13 17:58:13 +00001492 // we don't currently apply offscreen AA to this path. Need improved
1493 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001494
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001495 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001496 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001497 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001498 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001499 target->drawNonIndexed(primitiveType, 0, vertexCount);
1500 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001501}
1502
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001503///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001504
reed@google.com07f3ee12011-05-16 17:21:57 +00001505void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1506 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001507
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001508 if (path.isEmpty()) {
1509#if GR_DEBUG
1510 GrPrintf("Empty path should have been caught by canvas.\n");
1511#endif
1512 if (GrIsFillInverted(fill)) {
1513 this->drawPaint(paint);
1514 }
1515 return;
1516 }
1517
bsalomon@google.com27847de2011-02-22 20:59:41 +00001518 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001519
bsalomon@google.com289533a2011-10-27 12:34:25 +00001520 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1521
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001522 // An Assumption here is that path renderer would use some form of tweaking
1523 // the src color (either the input alpha or in the frag shader) to implement
1524 // aa. If we have some future driver-mojo path AA that can do the right
1525 // thing WRT to the blend then we'll need some query on the PR.
1526 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001527#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001528 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001529#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001530 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001531 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001532
1533 bool doOSAA = false;
1534 GrPathRenderer* pr = NULL;
1535 if (prAA) {
1536 pr = this->getPathRenderer(path, fill, true);
1537 if (NULL == pr) {
1538 prAA = false;
1539 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1540 pr = this->getPathRenderer(path, fill, false);
1541 }
1542 } else {
1543 pr = this->getPathRenderer(path, fill, false);
1544 }
1545
bsalomon@google.com30085192011-08-19 15:42:31 +00001546 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001547#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001548 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001549#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001550 return;
1551 }
1552
bsalomon@google.com289533a2011-10-27 12:34:25 +00001553 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.comee435122011-07-01 14:57:55 +00001554 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001555
bsalomon@google.com289533a2011-10-27 12:34:25 +00001556 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001557 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001558
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001559 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001560 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1561 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001562 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001563 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001564 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001565 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001566 return;
1567 }
1568 }
reed@google.com70c136e2011-06-03 19:51:26 +00001569
reed@google.com07f3ee12011-05-16 17:21:57 +00001570 GrRect pathBounds = path.getBounds();
1571 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001572 if (NULL != translate) {
1573 pathBounds.offset(*translate);
1574 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001575 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001576 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001577 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001578 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001579 return;
1580 }
1581 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001582 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001583 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1584 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001585 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1586 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1587 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001588 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001589 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1590 }
1591 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001592 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001593 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001594 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1595 GrRect rect;
1596 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001597 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1598 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001599 target->drawSimpleRect(rect, NULL, stageMask);
1600 }
1601 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001602 rect.iset(clipIBounds.fLeft, bound.fTop,
1603 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001604 target->drawSimpleRect(rect, NULL, stageMask);
1605 }
1606 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001607 rect.iset(bound.fRight, bound.fTop,
1608 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001609 target->drawSimpleRect(rect, NULL, stageMask);
1610 }
1611 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001612 rect.iset(clipIBounds.fLeft, bound.fBottom,
1613 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001614 target->drawSimpleRect(rect, NULL, stageMask);
1615 }
1616 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001617 return;
1618 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001619 }
1620 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001621}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001622
bsalomon@google.com27847de2011-02-22 20:59:41 +00001623////////////////////////////////////////////////////////////////////////////////
1624
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001625bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001626 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001627}
1628
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001629void GrContext::flush(int flagsBitfield) {
1630 if (kDiscard_FlushBit & flagsBitfield) {
1631 fDrawBuffer->reset();
1632 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001633 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001634 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001635 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001636 fGpu->forceRenderTargetFlush();
1637 }
1638}
1639
1640void GrContext::flushText() {
1641 if (kText_DrawCategory == fLastDrawCategory) {
1642 flushDrawBuffer();
1643 }
1644}
1645
1646void GrContext::flushDrawBuffer() {
1647#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001648 if (fDrawBuffer) {
1649 fDrawBuffer->playback(fGpu);
1650 fDrawBuffer->reset();
1651 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001652#endif
1653}
1654
bsalomon@google.com6f379512011-11-16 20:36:03 +00001655void GrContext::internalWriteTexturePixels(GrTexture* texture,
1656 int left, int top,
1657 int width, int height,
1658 GrPixelConfig config,
1659 const void* buffer,
1660 size_t rowBytes,
1661 uint32_t flags) {
1662 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001663 ASSERT_OWNED_RESOURCE(texture);
1664
bsalomon@google.com6f379512011-11-16 20:36:03 +00001665 if (!(kDontFlush_PixelOpsFlag & flags)) {
1666 this->flush();
1667 }
1668 // TODO: use scratch texture to perform conversion
1669 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1670 GrPixelConfigIsUnpremultiplied(config)) {
1671 return;
1672 }
1673
1674 fGpu->writeTexturePixels(texture, left, top, width, height,
1675 config, buffer, rowBytes);
1676}
1677
1678bool GrContext::internalReadTexturePixels(GrTexture* texture,
1679 int left, int top,
1680 int width, int height,
1681 GrPixelConfig config,
1682 void* buffer,
1683 size_t rowBytes,
1684 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001685 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001686 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001687
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001688 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001689 GrRenderTarget* target = texture->asRenderTarget();
1690 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001691 return this->internalReadRenderTargetPixels(target,
1692 left, top, width, height,
1693 config, buffer, rowBytes,
1694 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001695 } else {
1696 return false;
1697 }
1698}
1699
bsalomon@google.com6f379512011-11-16 20:36:03 +00001700bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1701 int left, int top,
1702 int width, int height,
1703 GrPixelConfig config,
1704 void* buffer,
1705 size_t rowBytes,
1706 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001707 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001708 ASSERT_OWNED_RESOURCE(target);
1709
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001710 if (NULL == target) {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001711 target = fGpu->getRenderTarget();
1712 if (NULL == target) {
1713 return false;
1714 }
1715 }
1716
1717 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1718 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1719 // not supported at this time.
1720 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1721 !GrPixelConfigIsUnpremultiplied(config)) {
1722 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001723 }
1724
bsalomon@google.com6f379512011-11-16 20:36:03 +00001725 if (!(kDontFlush_PixelOpsFlag & flags)) {
1726 this->flush();
1727 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001728
1729 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001730 bool swapRAndB = NULL != src &&
1731 fGpu->preferredReadPixelsConfig(config) ==
1732 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001733
1734 bool flipY = NULL != src &&
1735 fGpu->readPixelsWillPayForYFlip(target, left, top,
1736 width, height, config,
1737 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001738 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1739 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001740
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001741 if (NULL == src && alphaConversion) {
1742 // we should fallback to cpu conversion here. This could happen when
1743 // we were given an external render target by the client that is not
1744 // also a texture (e.g. FBO 0 in GL)
1745 return false;
1746 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001747 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001748 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001749 if (flipY || swapRAndB || alphaConversion) {
1750 GrAssert(NULL != src);
1751 if (swapRAndB) {
1752 config = GrPixelConfigSwapRAndB(config);
1753 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001754 }
1755 // Make the scratch a render target because we don't have a robust
1756 // readTexturePixels as of yet (it calls this function).
1757 const GrTextureDesc desc = {
1758 kRenderTarget_GrTextureFlagBit,
1759 kNone_GrAALevel,
1760 width, height,
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001761 { config }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001762 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001763
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001764 // When a full readback is faster than a partial we could always make
1765 // the scratch exactly match the passed rect. However, if we see many
1766 // different size rectangles we will trash our texture cache and pay the
1767 // cost of creating and destroying many textures. So, we only request
1768 // an exact match when the caller is reading an entire RT.
1769 ScratchTexMatch match = kApprox_ScratchTexMatch;
1770 if (0 == left &&
1771 0 == top &&
1772 target->width() == width &&
1773 target->height() == height &&
1774 fGpu->fullReadPixelsIsFasterThanPartial()) {
1775 match = kExact_ScratchTexMatch;
1776 }
1777 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001778 GrTexture* texture = ast.texture();
1779 if (!texture) {
1780 return false;
1781 }
1782 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001783 GrAssert(NULL != target);
1784
1785 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001786 reset_target_state(fGpu);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001787
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001788 fGpu->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001789
1790 GrSamplerState sampler;
1791 sampler.setClampNoFilter();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001792 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001793 GrMatrix matrix;
1794 if (flipY) {
1795 matrix.setTranslate(SK_Scalar1 * left,
1796 SK_Scalar1 * (top + height));
1797 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1798 } else {
1799 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1800 }
1801 matrix.postIDiv(src->width(), src->height());
1802 sampler.setMatrix(matrix);
1803 fGpu->setSamplerState(0, sampler);
1804 fGpu->setTexture(0, src);
1805 GrRect rect;
1806 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1807 fGpu->drawSimpleRect(rect, NULL, 0x1);
1808 left = 0;
1809 top = 0;
1810 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001811 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001812 left, top, width, height,
1813 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001814}
1815
bsalomon@google.com6f379512011-11-16 20:36:03 +00001816void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1817 int left, int top,
1818 int width, int height,
1819 GrPixelConfig config,
1820 const void* buffer,
1821 size_t rowBytes,
1822 uint32_t flags) {
1823 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001824 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001825
1826 if (NULL == target) {
1827 target = fGpu->getRenderTarget();
1828 if (NULL == target) {
1829 return;
1830 }
1831 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001832
1833 // TODO: when underlying api has a direct way to do this we should use it
1834 // (e.g. glDrawPixels on desktop GL).
1835
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001836 // If the RT is also a texture and we don't have to do PM/UPM conversion
1837 // then take the texture path, which we expect to be at least as fast or
1838 // faster since it doesn't use an intermediate texture as we do below.
1839
1840#if !GR_MAC_BUILD
1841 // At least some drivers on the Mac get confused when glTexImage2D is called
1842 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1843 // determine what OS versions and/or HW is affected.
1844 if (NULL != target->asTexture() &&
1845 GrPixelConfigIsUnpremultiplied(target->config()) ==
1846 GrPixelConfigIsUnpremultiplied(config)) {
1847
1848 this->internalWriteTexturePixels(target->asTexture(),
1849 left, top, width, height,
1850 config, buffer, rowBytes, flags);
1851 return;
1852 }
1853#endif
1854
1855 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1856 GrPixelConfigSwapRAndB(config);
1857 if (swapRAndB) {
1858 config = GrPixelConfigSwapRAndB(config);
1859 }
1860
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001861 const GrTextureDesc desc = {
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001862 kNone_GrTextureFlags, kNone_GrAALevel, width, height, { config }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001863 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001864 GrAutoScratchTexture ast(this, desc);
1865 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001866 if (NULL == texture) {
1867 return;
1868 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001869 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1870 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001871
bsalomon@google.com27847de2011-02-22 20:59:41 +00001872 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001873 reset_target_state(fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001874
1875 GrMatrix matrix;
1876 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1877 fGpu->setViewMatrix(matrix);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001878 fGpu->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001879 fGpu->setTexture(0, texture);
1880
1881 GrSamplerState sampler;
1882 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001883 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001884 sampler.setMatrix(matrix);
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001885 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001886 fGpu->setSamplerState(0, sampler);
1887
1888 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1889 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001890 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001891 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1892 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001893 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001894 return;
1895 }
1896 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1897 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1898}
1899////////////////////////////////////////////////////////////////////////////////
1900
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001901void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001902
1903 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1904 int s = i + GrPaint::kFirstTextureStage;
1905 target->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001906 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001907 target->setSamplerState(s, *paint.getTextureSampler(i));
1908 }
1909
1910 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1911
1912 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1913 int s = i + GrPaint::kFirstMaskStage;
1914 target->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001915 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001916 target->setSamplerState(s, *paint.getMaskSampler(i));
1917 }
1918
bsalomon@google.com27847de2011-02-22 20:59:41 +00001919 target->setColor(paint.fColor);
1920
1921 if (paint.fDither) {
1922 target->enableState(GrDrawTarget::kDither_StateBit);
1923 } else {
1924 target->disableState(GrDrawTarget::kDither_StateBit);
1925 }
1926 if (paint.fAntiAlias) {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001927 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001928 } else {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001929 target->disableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001930 }
1931 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001932 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001933
1934 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1935 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1936 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001937}
1938
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001939GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001940 DrawCategory category) {
1941 if (category != fLastDrawCategory) {
1942 flushDrawBuffer();
1943 fLastDrawCategory = category;
1944 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001945 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001946 GrDrawTarget* target = fGpu;
1947 switch (category) {
1948 case kText_DrawCategory:
1949#if DEFER_TEXT_RENDERING
1950 target = fDrawBuffer;
1951 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1952#else
1953 target = fGpu;
1954#endif
1955 break;
1956 case kUnbuffered_DrawCategory:
1957 target = fGpu;
1958 break;
1959 case kBuffered_DrawCategory:
1960 target = fDrawBuffer;
1961 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1962 break;
1963 }
1964 return target;
1965}
1966
bsalomon@google.com289533a2011-10-27 12:34:25 +00001967GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1968 GrPathFill fill,
1969 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001970 if (NULL == fPathRendererChain) {
1971 fPathRendererChain =
1972 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1973 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001974 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1975 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001976}
1977
bsalomon@google.com27847de2011-02-22 20:59:41 +00001978////////////////////////////////////////////////////////////////////////////////
1979
bsalomon@google.com27847de2011-02-22 20:59:41 +00001980void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001981 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001982 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001983 fGpu->setRenderTarget(target);
1984}
1985
1986GrRenderTarget* GrContext::getRenderTarget() {
1987 return fGpu->getRenderTarget();
1988}
1989
1990const GrRenderTarget* GrContext::getRenderTarget() const {
1991 return fGpu->getRenderTarget();
1992}
1993
1994const GrMatrix& GrContext::getMatrix() const {
1995 return fGpu->getViewMatrix();
1996}
1997
1998void GrContext::setMatrix(const GrMatrix& m) {
1999 fGpu->setViewMatrix(m);
2000}
2001
2002void GrContext::concatMatrix(const GrMatrix& m) const {
2003 fGpu->preConcatViewMatrix(m);
2004}
2005
2006static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2007 intptr_t mask = 1 << shift;
2008 if (pred) {
2009 bits |= mask;
2010 } else {
2011 bits &= ~mask;
2012 }
2013 return bits;
2014}
2015
2016void GrContext::resetStats() {
2017 fGpu->resetStats();
2018}
2019
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002020const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002021 return fGpu->getStats();
2022}
2023
2024void GrContext::printStats() const {
2025 fGpu->printStats();
2026}
2027
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002028GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002029 fGpu = gpu;
2030 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002031 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002032
bsalomon@google.com30085192011-08-19 15:42:31 +00002033 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002034
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002035 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2036 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002037 fFontCache = new GrFontCache(fGpu);
2038
2039 fLastDrawCategory = kUnbuffered_DrawCategory;
2040
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002041 fDrawBuffer = NULL;
2042 fDrawBufferVBAllocPool = NULL;
2043 fDrawBufferIBAllocPool = NULL;
2044
bsalomon@google.com205d4602011-04-25 12:43:45 +00002045 fAAFillRectIndexBuffer = NULL;
2046 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002047
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002048 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2049 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002050 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2051 }
2052 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002053
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002054 this->setupDrawBuffer();
2055}
2056
2057void GrContext::setupDrawBuffer() {
2058
2059 GrAssert(NULL == fDrawBuffer);
2060 GrAssert(NULL == fDrawBufferVBAllocPool);
2061 GrAssert(NULL == fDrawBufferIBAllocPool);
2062
bsalomon@google.com27847de2011-02-22 20:59:41 +00002063#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002064 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002065 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002066 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2067 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002068 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002069 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002070 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002071 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2072
bsalomon@google.com471d4712011-08-23 15:45:25 +00002073 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2074 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002075 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002076#endif
2077
2078#if BATCH_RECT_TO_RECT
2079 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2080#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002081}
2082
bsalomon@google.com27847de2011-02-22 20:59:41 +00002083GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2084 GrDrawTarget* target;
2085#if DEFER_TEXT_RENDERING
2086 target = prepareToDraw(paint, kText_DrawCategory);
2087#else
2088 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2089#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002090 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002091 return target;
2092}
2093
2094const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2095 return fGpu->getQuadIndexBuffer();
2096}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002097
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002098void GrContext::convolveInX(GrTexture* texture,
2099 const SkRect& rect,
2100 const float* kernel,
2101 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002102 ASSERT_OWNED_RESOURCE(texture);
2103
bsalomon@google.com99621082011-11-15 16:47:16 +00002104 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002105 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2106}
2107
2108void GrContext::convolveInY(GrTexture* texture,
2109 const SkRect& rect,
2110 const float* kernel,
2111 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002112 ASSERT_OWNED_RESOURCE(texture);
2113
bsalomon@google.com99621082011-11-15 16:47:16 +00002114 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002115 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2116}
2117
2118void GrContext::convolve(GrTexture* texture,
2119 const SkRect& rect,
2120 float imageIncrement[2],
2121 const float* kernel,
2122 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002123 ASSERT_OWNED_RESOURCE(texture);
2124
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002125 GrDrawTarget::AutoStateRestore asr(fGpu);
2126 GrMatrix sampleM;
2127 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
2128 GrSamplerState::kClamp_WrapMode,
2129 GrSamplerState::kConvolution_Filter);
2130 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002131 sampleM.setIDiv(texture->width(), texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002132 sampler.setMatrix(sampleM);
2133 fGpu->setSamplerState(0, sampler);
2134 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002135 fGpu->setTexture(0, texture);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002136 fGpu->setColor(0xFFFFFFFF);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00002137 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002138 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2139}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002140
2141///////////////////////////////////////////////////////////////////////////////