blob: a2b2a1649763d6c806e7e0ab356fd08d90227e54 [file] [log] [blame]
bsalomon@google.com27847de2011-02-22 20:59:41 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
bsalomon@google.com27847de2011-02-22 20:59:41 +00003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000018#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000019#include "GrTextureCache.h"
20#include "GrTextStrike.h"
21#include "GrMemory.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000022#include "GrClipIterator.h"
23#include "GrIndexBuffer.h"
24#include "GrInOrderDrawBuffer.h"
25#include "GrBufferAllocPool.h"
26#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000027#include "GrPathUtils.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000028
bsalomon@google.com91958362011-06-13 17:58:13 +000029// Using MSAA seems to be slower for some yet unknown reason.
30#define PREFER_MSAA_OFFSCREEN_AA 0
31#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000032
bsalomon@google.com27847de2011-02-22 20:59:41 +000033#define DEFER_TEXT_RENDERING 1
34
35#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
36
37static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
38static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
39
40static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
41static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
42
43// We are currently only batching Text and drawRectToRect, both
44// of which use the quad index buffer.
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
47
bsalomon@google.com05ef5102011-05-02 21:14:59 +000048GrContext* GrContext::Create(GrEngine engine,
49 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000050 GrContext* ctx = NULL;
51 GrGpu* fGpu = GrGpu::Create(engine, context3D);
52 if (NULL != fGpu) {
53 ctx = new GrContext(fGpu);
54 fGpu->unref();
55 }
56 return ctx;
57}
58
59GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000060 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000061}
62
63GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000064 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000065 delete fTextureCache;
66 delete fFontCache;
67 delete fDrawBuffer;
68 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000069 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000070 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000071 GrSafeUnref(fAAFillRectIndexBuffer);
72 GrSafeUnref(fAAStrokeRectIndexBuffer);
73 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000074}
75
bsalomon@google.com8fe72472011-03-30 21:26:44 +000076void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000077 contextDestroyed();
78 this->setupDrawBuffer();
79}
80
81void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000082 // abandon first to so destructors
83 // don't try to free the resources in the API.
84 fGpu->abandonResources();
85
bsalomon@google.com8fe72472011-03-30 21:26:44 +000086 delete fDrawBuffer;
87 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000088
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089 delete fDrawBufferVBAllocPool;
90 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000091
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 delete fDrawBufferIBAllocPool;
93 fDrawBufferIBAllocPool = NULL;
94
bsalomon@google.com205d4602011-04-25 12:43:45 +000095 GrSafeSetNull(fAAFillRectIndexBuffer);
96 GrSafeSetNull(fAAStrokeRectIndexBuffer);
97
bsalomon@google.com8fe72472011-03-30 21:26:44 +000098 fTextureCache->removeAll();
99 fFontCache->freeAll();
100 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000101}
102
103void GrContext::resetContext() {
104 fGpu->markContextDirty();
105}
106
107void GrContext::freeGpuResources() {
108 this->flush();
109 fTextureCache->removeAll();
110 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000111}
112
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000113////////////////////////////////////////////////////////////////////////////////
114
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000115int GrContext::PaintStageVertexLayoutBits(
116 const GrPaint& paint,
117 const bool hasTexCoords[GrPaint::kTotalStages]) {
118 int stageMask = paint.getActiveStageMask();
119 int layout = 0;
120 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
121 if ((1 << i) & stageMask) {
122 if (NULL != hasTexCoords && hasTexCoords[i]) {
123 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
124 } else {
125 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
126 }
127 }
128 }
129 return layout;
130}
131
132
133////////////////////////////////////////////////////////////////////////////////
134
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000135enum {
136 kNPOTBit = 0x1,
137 kFilterBit = 0x2,
138 kKeylessBit = 0x4,
139};
140
141bool GrContext::finalizeTextureKey(GrTextureKey* key,
142 const GrSamplerState& sampler,
143 bool keyless) const {
144 uint32_t bits = 0;
145 uint16_t width = key->width();
146 uint16_t height = key->height();
147
148 if (!fGpu->npotTextureTileSupport()) {
149 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
150
151 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
152 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
153
154 if (tiled && !isPow2) {
155 bits |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000156 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000157 bits |= kFilterBit;
158 }
159 }
160 }
161
162 if (keyless) {
163 bits |= kKeylessBit;
164 }
165 key->finalize(bits);
166 return 0 != bits;
167}
168
bsalomon@google.com27847de2011-02-22 20:59:41 +0000169GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
170 const GrSamplerState& sampler) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000171 finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000172 return fTextureCache->findAndLock(*key);
173}
174
175static void stretchImage(void* dst,
176 int dstW,
177 int dstH,
178 void* src,
179 int srcW,
180 int srcH,
181 int bpp) {
182 GrFixed dx = (srcW << 16) / dstW;
183 GrFixed dy = (srcH << 16) / dstH;
184
185 GrFixed y = dy >> 1;
186
187 int dstXLimit = dstW*bpp;
188 for (int j = 0; j < dstH; ++j) {
189 GrFixed x = dx >> 1;
190 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
191 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
192 for (int i = 0; i < dstXLimit; i += bpp) {
193 memcpy((uint8_t*) dstRow + i,
194 (uint8_t*) srcRow + (x>>16)*bpp,
195 bpp);
196 x += dx;
197 }
198 y += dy;
199 }
200}
201
202GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
203 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000204 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000205 void* srcData, size_t rowBytes) {
206 GrAssert(key->width() == desc.fWidth);
207 GrAssert(key->height() == desc.fHeight);
208
209#if GR_DUMP_TEXTURE_UPLOAD
210 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
211#endif
212
213 GrTextureEntry* entry = NULL;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000214 bool special = finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000215 if (special) {
216 GrTextureEntry* clampEntry;
217 GrTextureKey clampKey(*key);
218 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
219
220 if (NULL == clampEntry) {
221 clampEntry = createAndLockTexture(&clampKey,
222 GrSamplerState::ClampNoFilter(),
223 desc, srcData, rowBytes);
224 GrAssert(NULL != clampEntry);
225 if (NULL == clampEntry) {
226 return NULL;
227 }
228 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000229 GrTextureDesc rtDesc = desc;
230 rtDesc.fFlags = rtDesc.fFlags |
231 kRenderTarget_GrTextureFlagBit |
232 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000233 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
234 fGpu->minRenderTargetWidth()));
235 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
236 fGpu->minRenderTargetHeight()));
237
238 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
239
240 if (NULL != texture) {
241 GrDrawTarget::AutoStateRestore asr(fGpu);
242 fGpu->setRenderTarget(texture->asRenderTarget());
243 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000244 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000245 fGpu->setViewMatrix(GrMatrix::I());
246 fGpu->setAlpha(0xff);
247 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
248 fGpu->disableState(GrDrawTarget::kDither_StateBit |
249 GrDrawTarget::kClip_StateBit |
250 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000251 GrSamplerState::Filter filter;
252 // if filtering is not desired then we want to ensure all
253 // texels in the resampled image are copies of texels from
254 // the original.
255 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
256 filter = GrSamplerState::kNearest_Filter;
257 } else {
258 filter = GrSamplerState::kBilinear_Filter;
259 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000260 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
261 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000262 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000263 fGpu->setSamplerState(0, stretchSampler);
264
265 static const GrVertexLayout layout =
266 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
267 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
268
269 if (arg.succeeded()) {
270 GrPoint* verts = (GrPoint*) arg.vertices();
271 verts[0].setIRectFan(0, 0,
272 texture->width(),
273 texture->height(),
274 2*sizeof(GrPoint));
275 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
276 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
277 0, 4);
278 entry = fTextureCache->createAndLock(*key, texture);
279 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000280 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000281 } else {
282 // TODO: Our CPU stretch doesn't filter. But we create separate
283 // stretched textures when the sampler state is either filtered or
284 // not. Either implement filtered stretch blit on CPU or just create
285 // one when FBO case fails.
286
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000287 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000288 // no longer need to clamp at min RT size.
289 rtDesc.fWidth = GrNextPow2(desc.fWidth);
290 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000291 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000292 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
293 rtDesc.fWidth *
294 rtDesc.fHeight);
295 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
296 srcData, desc.fWidth, desc.fHeight, bpp);
297
298 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
299
300 GrTexture* texture = fGpu->createTexture(rtDesc,
301 stretchedPixels.get(),
302 stretchedRowBytes);
303 GrAssert(NULL != texture);
304 entry = fTextureCache->createAndLock(*key, texture);
305 }
306 fTextureCache->unlock(clampEntry);
307
308 } else {
309 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
310 if (NULL != texture) {
311 entry = fTextureCache->createAndLock(*key, texture);
312 } else {
313 entry = NULL;
314 }
315 }
316 return entry;
317}
318
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000319GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000320 uint32_t p0 = desc.fFormat;
321 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
322 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000323 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
324
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000325 GrTextureEntry* entry = fTextureCache->findAndLock(key);
326 if (NULL == entry) {
327 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
328 if (NULL != texture) {
329 entry = fTextureCache->createAndLock(key, texture);
330 }
331 }
332 // If the caller gives us the same desc/sampler twice we don't want
333 // to return the same texture the second time (unless it was previously
334 // released). So we detach the entry from the cache and reattach at release.
335 if (NULL != entry) {
336 fTextureCache->detach(entry);
337 }
338 return entry;
339}
340
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000341GrTextureEntry* GrContext::findApproximateKeylessTexture(
342 const GrTextureDesc& inDesc) {
343 GrTextureDesc desc = inDesc;
344 // bin by pow2 with a reasonable min
345 static const int MIN_SIZE = 256;
346 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
347 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
348
349 uint32_t p0 = desc.fFormat;
350 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
351
352 GrTextureEntry* entry;
353 bool keepTrying = true;
354 int origWidth = desc.fWidth;
355 int origHeight = desc.fHeight;
356 bool doubledW = false;
357 bool doubledH = false;
358
359 do {
360 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
361 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
362 entry = fTextureCache->findAndLock(key);
363
364 // if we miss, relax the fit of the flags...
365 // then try doubling width... then height.
366 if (NULL != entry) {
367 break;
368 }
369 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
370 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
371 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
372 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
373 } else if (!doubledW) {
374 desc.fFlags = inDesc.fFlags;
375 desc.fWidth *= 2;
376 doubledW = true;
377 } else if (!doubledH) {
378 desc.fFlags = inDesc.fFlags;
379 desc.fWidth = origWidth;
380 desc.fHeight *= 2;
381 doubledH = true;
382 } else {
383 break;
384 }
385
386 } while (true);
387
388 if (NULL == entry) {
389 desc.fFlags = inDesc.fFlags;
390 desc.fWidth = origWidth;
391 desc.fHeight = origHeight;
392 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
393 if (NULL != texture) {
394 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
395 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(),
396 true);
397 entry = fTextureCache->createAndLock(key, texture);
398 }
399 }
400
401 // If the caller gives us the same desc/sampler twice we don't want
402 // to return the same texture the second time (unless it was previously
403 // released). So we detach the entry from the cache and reattach at release.
404 if (NULL != entry) {
405 fTextureCache->detach(entry);
406 }
407 return entry;
408}
409
bsalomon@google.com27847de2011-02-22 20:59:41 +0000410void GrContext::unlockTexture(GrTextureEntry* entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000411 if (kKeylessBit & entry->key().getPrivateBits()) {
412 fTextureCache->reattachAndUnlock(entry);
413 } else {
414 fTextureCache->unlock(entry);
415 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000416}
417
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000418GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000419 void* srcData,
420 size_t rowBytes) {
421 return fGpu->createTexture(desc, srcData, rowBytes);
422}
423
424void GrContext::getTextureCacheLimits(int* maxTextures,
425 size_t* maxTextureBytes) const {
426 fTextureCache->getLimits(maxTextures, maxTextureBytes);
427}
428
429void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
430 fTextureCache->setLimits(maxTextures, maxTextureBytes);
431}
432
bsalomon@google.com91958362011-06-13 17:58:13 +0000433int GrContext::getMaxTextureSize() const {
434 return fGpu->maxTextureSize();
435}
436
437int GrContext::getMaxRenderTargetSize() const {
438 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000439}
440
441///////////////////////////////////////////////////////////////////////////////
442
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000443GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
444 // validate flags here so that GrGpu subclasses don't have to check
445 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
446 0 != desc.fRenderTargetFlags) {
447 return NULL;
448 }
449 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
450 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
451 return NULL;
452 }
453 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
454 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
455 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
456 return NULL;
457 }
458 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000459}
460
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000461GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000462 return fGpu->createRenderTargetFrom3DApiState();
463}
464
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000465///////////////////////////////////////////////////////////////////////////////
466
bsalomon@google.com27847de2011-02-22 20:59:41 +0000467bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
468 int width, int height) {
469 if (!fGpu->supports8BitPalette()) {
470 return false;
471 }
472
473
474 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
475
476 if (!isPow2) {
477 if (!fGpu->npotTextureSupport()) {
478 return false;
479 }
480
481 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
482 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
483 if (tiled && !fGpu->npotTextureTileSupport()) {
484 return false;
485 }
486 }
487 return true;
488}
489
490////////////////////////////////////////////////////////////////////////////////
491
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000492const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
493
bsalomon@google.com27847de2011-02-22 20:59:41 +0000494void GrContext::setClip(const GrClip& clip) {
495 fGpu->setClip(clip);
496 fGpu->enableState(GrDrawTarget::kClip_StateBit);
497}
498
499void GrContext::setClip(const GrIRect& rect) {
500 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000501 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000502 fGpu->setClip(clip);
503}
504
505////////////////////////////////////////////////////////////////////////////////
506
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000507void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000508 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000509 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000510}
511
512void GrContext::drawPaint(const GrPaint& paint) {
513 // set rect to be big enough to fill the space, but not super-huge, so we
514 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000515 GrRect r;
516 r.setLTRB(0, 0,
517 GrIntToScalar(getRenderTarget()->width()),
518 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000519 GrMatrix inverse;
520 if (fGpu->getViewInverse(&inverse)) {
521 inverse.mapRect(&r);
522 } else {
523 GrPrintf("---- fGpu->getViewInverse failed\n");
524 }
525 this->drawRect(paint, r);
526}
527
bsalomon@google.com205d4602011-04-25 12:43:45 +0000528////////////////////////////////////////////////////////////////////////////////
529
bsalomon@google.com91958362011-06-13 17:58:13 +0000530struct GrContext::OffscreenRecord {
531 OffscreenRecord() { fEntry0 = NULL; fEntry1 = NULL; }
532 ~OffscreenRecord() { GrAssert(NULL == fEntry0 && NULL == fEntry1); }
533
534 enum Downsample {
535 k4x4TwoPass_Downsample,
536 k4x4SinglePass_Downsample,
537 kFSAA_Downsample
538 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000539 int fTileSizeX;
540 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000541 int fTileCountX;
542 int fTileCountY;
543 int fScale;
544 GrTextureEntry* fEntry0;
545 GrTextureEntry* fEntry1;
546 GrDrawTarget::SavedDrawState fSavedState;
547};
548
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000549bool GrContext::doOffscreenAA(GrDrawTarget* target,
550 const GrPaint& paint,
551 bool isLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000552#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000553 return false;
554#else
555 if (!paint.fAntiAlias) {
556 return false;
557 }
558 if (isLines && fGpu->supportsAALines()) {
559 return false;
560 }
561 if (target->getRenderTarget()->isMultisampled()) {
562 return false;
563 }
564 // we have to be sure that the blend equation is expressible
565 // as simple src / dst coeffecients when the source
566 // is already modulated by the coverage fraction.
567 // We could use dual-source blending to get the correct per-pixel
568 // dst coeffecient for the remaining cases.
569 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
570 kOne_BlendCoeff != paint.fDstBlendCoeff &&
571 kISA_BlendCoeff != paint.fDstBlendCoeff) {
572 return false;
573 }
574 return true;
575#endif
576}
577
bsalomon@google.com91958362011-06-13 17:58:13 +0000578bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000579 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000580 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000581 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000582 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000583
584 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000585
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000586 GrAssert(NULL == record->fEntry0);
587 GrAssert(NULL == record->fEntry1);
bsalomon@google.com91958362011-06-13 17:58:13 +0000588 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000589
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000590 int boundW = boundRect.width();
591 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000592
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000593 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000594
595 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
596 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
597
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000598 if (requireStencil) {
599 desc.fFlags = kRenderTarget_GrTextureFlagBit;
600 } else {
601 desc.fFlags = kRenderTarget_GrTextureFlagBit |
602 kNoStencil_GrTextureFlagBit;
603 }
604
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000605 desc.fFormat = kRGBA_8888_GrPixelConfig;
606
bsalomon@google.com91958362011-06-13 17:58:13 +0000607 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000608 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000609 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000610 desc.fAALevel = kMed_GrAALevel;
611 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000612 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
613 OffscreenRecord::k4x4SinglePass_Downsample :
614 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000615 record->fScale = OFFSCREEN_SSAA_SCALE;
616 // both downsample paths assume this
617 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000618 desc.fAALevel = kNone_GrAALevel;
619 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000620 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
621 // of simple circles?
622 if (pr) {
623 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
624 }
625
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000626 desc.fWidth *= record->fScale;
627 desc.fHeight *= record->fScale;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000628
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000629 record->fEntry0 = this->findApproximateKeylessTexture(desc);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000630 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000631 return false;
632 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000633 // the approximate lookup might have given us some slop space, might as well
634 // use it when computing the tiles size.
635 // these are scale values, will adjust after considering
636 // the possible second offscreen.
637 record->fTileSizeX = record->fEntry0->texture()->width();
638 record->fTileSizeY = record->fEntry0->texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000639
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000640 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000641 desc.fWidth /= 2;
642 desc.fHeight /= 2;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000643 record->fEntry1 = this->findApproximateKeylessTexture(desc);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000644 if (NULL == record->fEntry1) {
645 this->unlockTexture(record->fEntry0);
646 record->fEntry0 = NULL;
647 return false;
648 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000649 record->fTileSizeX = GrMin(record->fTileSizeX,
650 2 * record->fEntry0->texture()->width());
651 record->fTileSizeY = GrMin(record->fTileSizeY,
652 2 * record->fEntry0->texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000653 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000654 record->fTileSizeX /= record->fScale;
655 record->fTileSizeY /= record->fScale;
656
657 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
658 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
659
bsalomon@google.com91958362011-06-13 17:58:13 +0000660 target->saveCurrentDrawState(&record->fSavedState);
661 return true;
662}
663
664void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
665 const GrIRect& boundRect,
666 int tileX, int tileY,
667 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000668
669 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
670 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000671
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000672 GrPaint tempPaint;
673 tempPaint.reset();
674 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000675 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000676
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000677 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000678 int left = boundRect.fLeft + tileX * record->fTileSizeX;
679 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000680 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000681 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000682 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000683 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000684 target->postConcatViewMatrix(scaleM);
685
686 // clip gets applied in second pass
687 target->disableState(GrDrawTarget::kClip_StateBit);
688
bsalomon@google.com91958362011-06-13 17:58:13 +0000689 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000690 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000691 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000692 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000693 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
694 record->fScale * h);
695#if 0
696 // visualize tile boundaries by setting edges of offscreen to white
697 // and interior to tranparent. black.
698 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000699
bsalomon@google.com91958362011-06-13 17:58:13 +0000700 static const int gOffset = 2;
701 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
702 record->fScale * w - gOffset,
703 record->fScale * h - gOffset);
704 target->clear(&clear2, 0x0);
705#else
706 target->clear(&clear, 0x0);
707#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000708}
709
bsalomon@google.com91958362011-06-13 17:58:13 +0000710void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000711 const GrPaint& paint,
712 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000713 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000714 OffscreenRecord* record) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000715
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000716 GrAssert(NULL != record->fEntry0);
bsalomon@google.com91958362011-06-13 17:58:13 +0000717
718 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000719 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
720 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000721 tileRect.fRight = (tileX == record->fTileCountX-1) ?
722 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000723 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000724 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
725 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000726 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000727
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000728 GrSamplerState::Filter filter;
729 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
730 filter = GrSamplerState::k4x4Downsample_Filter;
731 } else {
732 filter = GrSamplerState::kBilinear_Filter;
733 }
734
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000735 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000736 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000737 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000738
739 GrTexture* src = record->fEntry0->texture();
740 int scale;
741
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000742 enum {
743 kOffscreenStage = GrPaint::kTotalStages,
744 };
745
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000746 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
747 GrAssert(NULL != record->fEntry1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000748 scale = 2;
749 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
750
751 // Do 2x2 downsample from first to second
752 target->setTexture(kOffscreenStage, src);
753 target->setRenderTarget(dst);
754 target->setViewMatrix(GrMatrix::I());
755 sampleM.setScale(scale * GR_Scalar1 / src->width(),
756 scale * GR_Scalar1 / src->height());
757 sampler.setMatrix(sampleM);
758 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000759 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
760 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000761 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
762
763 src = record->fEntry1->texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000764 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000765 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000766 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000767 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000768 } else {
769 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
770 record->fDownsample);
771 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000772 }
773
bsalomon@google.com91958362011-06-13 17:58:13 +0000774 // setup for draw back to main RT, we use the original
775 // draw state setup by the caller plus an additional coverage
776 // stage to handle the AA resolve. Also, we use an identity
777 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000778 int stageMask = paint.getActiveStageMask();
779
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000780 target->restoreDrawState(record->fSavedState);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000781
782 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000783 GrMatrix invVM;
784 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000785 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000786 }
787 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000788 // This is important when tiling, otherwise second tile's
789 // pass 1 view matrix will be incorrect.
790 GrDrawTarget::AutoViewMatrixRestore avmr(target);
791
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000792 target->setViewMatrix(GrMatrix::I());
793
794 target->setTexture(kOffscreenStage, src);
795 sampleM.setScale(scale * GR_Scalar1 / src->width(),
796 scale * GR_Scalar1 / src->height());
797 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000798 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000799 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000800 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000801
reed@google.com20efde72011-05-09 17:00:02 +0000802 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000803 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000804 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000805 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000806}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000807
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000808void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
809 GrPathRenderer* pr,
810 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000811 this->unlockTexture(record->fEntry0);
812 record->fEntry0 = NULL;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000813 if (pr) {
814 // Counterpart of scale() in prepareForOffscreenAA()
815 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
816 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000817 if (NULL != record->fEntry1) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000818 this->unlockTexture(record->fEntry1);
819 record->fEntry1 = NULL;
820 }
821 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000822}
823
824////////////////////////////////////////////////////////////////////////////////
825
bsalomon@google.com27847de2011-02-22 20:59:41 +0000826/* create a triangle strip that strokes the specified triangle. There are 8
827 unique vertices, but we repreat the last 2 to close up. Alternatively we
828 could use an indices array, and then only send 8 verts, but not sure that
829 would be faster.
830 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000831static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000832 GrScalar width) {
833 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000834 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000835
836 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
837 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
838 verts[2].set(rect.fRight - rad, rect.fTop + rad);
839 verts[3].set(rect.fRight + rad, rect.fTop - rad);
840 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
841 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
842 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
843 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
844 verts[8] = verts[0];
845 verts[9] = verts[1];
846}
847
bsalomon@google.com205d4602011-04-25 12:43:45 +0000848static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000849 // FIXME: This was copied from SkGpuDevice, seems like
850 // we should have already smeared a in caller if that
851 // is what is desired.
852 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000853 unsigned a = GrColorUnpackA(paint.fColor);
854 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000855 } else {
856 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000857 }
858}
859
860static void setInsetFan(GrPoint* pts, size_t stride,
861 const GrRect& r, GrScalar dx, GrScalar dy) {
862 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
863}
864
865static const uint16_t gFillAARectIdx[] = {
866 0, 1, 5, 5, 4, 0,
867 1, 2, 6, 6, 5, 1,
868 2, 3, 7, 7, 6, 2,
869 3, 0, 4, 4, 7, 3,
870 4, 5, 6, 6, 7, 4,
871};
872
873int GrContext::aaFillRectIndexCount() const {
874 return GR_ARRAY_COUNT(gFillAARectIdx);
875}
876
877GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
878 if (NULL == fAAFillRectIndexBuffer) {
879 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
880 false);
881 GrAssert(NULL != fAAFillRectIndexBuffer);
882#if GR_DEBUG
883 bool updated =
884#endif
885 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
886 sizeof(gFillAARectIdx));
887 GR_DEBUGASSERT(updated);
888 }
889 return fAAFillRectIndexBuffer;
890}
891
892static const uint16_t gStrokeAARectIdx[] = {
893 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
894 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
895 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
896 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
897
898 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
899 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
900 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
901 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
902
903 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
904 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
905 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
906 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
907};
908
909int GrContext::aaStrokeRectIndexCount() const {
910 return GR_ARRAY_COUNT(gStrokeAARectIdx);
911}
912
913GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
914 if (NULL == fAAStrokeRectIndexBuffer) {
915 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
916 false);
917 GrAssert(NULL != fAAStrokeRectIndexBuffer);
918#if GR_DEBUG
919 bool updated =
920#endif
921 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
922 sizeof(gStrokeAARectIdx));
923 GR_DEBUGASSERT(updated);
924 }
925 return fAAStrokeRectIndexBuffer;
926}
927
928void GrContext::fillAARect(GrDrawTarget* target,
929 const GrPaint& paint,
930 const GrRect& devRect) {
931
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000932 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
933 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000934
935 size_t vsize = GrDrawTarget::VertexSize(layout);
936
937 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
938
939 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
940
941 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
942 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
943
944 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
945 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
946
947 verts += sizeof(GrPoint);
948 for (int i = 0; i < 4; ++i) {
949 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
950 }
951
952 GrColor innerColor = getColorForMesh(paint);
953 verts += 4 * vsize;
954 for (int i = 0; i < 4; ++i) {
955 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
956 }
957
958 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
959
960 target->drawIndexed(kTriangles_PrimitiveType, 0,
961 0, 8, this->aaFillRectIndexCount());
962}
963
964void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
965 const GrRect& devRect, const GrVec& devStrokeSize) {
966 const GrScalar& dx = devStrokeSize.fX;
967 const GrScalar& dy = devStrokeSize.fY;
968 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
969 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
970
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000971 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
972 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000973
974 GrScalar spare;
975 {
976 GrScalar w = devRect.width() - dx;
977 GrScalar h = devRect.height() - dy;
978 spare = GrMin(w, h);
979 }
980
981 if (spare <= 0) {
982 GrRect r(devRect);
983 r.inset(-rx, -ry);
984 fillAARect(target, paint, r);
985 return;
986 }
987
988 size_t vsize = GrDrawTarget::VertexSize(layout);
989
990 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
991
992 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
993
994 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
995 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
996 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
997 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
998
999 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1000 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1001 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1002 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1003
1004 verts += sizeof(GrPoint);
1005 for (int i = 0; i < 4; ++i) {
1006 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1007 }
1008
1009 GrColor innerColor = getColorForMesh(paint);
1010 verts += 4 * vsize;
1011 for (int i = 0; i < 8; ++i) {
1012 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1013 }
1014
1015 verts += 8 * vsize;
1016 for (int i = 0; i < 8; ++i) {
1017 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1018 }
1019
1020 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1021 target->drawIndexed(kTriangles_PrimitiveType,
1022 0, 0, 16, aaStrokeRectIndexCount());
1023}
1024
reed@google.com20efde72011-05-09 17:00:02 +00001025/**
1026 * Returns true if the rects edges are integer-aligned.
1027 */
1028static bool isIRect(const GrRect& r) {
1029 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1030 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1031}
1032
bsalomon@google.com205d4602011-04-25 12:43:45 +00001033static bool apply_aa_to_rect(GrDrawTarget* target,
1034 GrGpu* gpu,
1035 const GrPaint& paint,
1036 const GrRect& rect,
1037 GrScalar width,
1038 const GrMatrix* matrix,
1039 GrMatrix* combinedMatrix,
1040 GrRect* devRect) {
1041 // we use a simple alpha ramp to do aa on axis-aligned rects
1042 // do AA with alpha ramp if the caller requested AA, the rect
1043 // will be axis-aligned,the render target is not
1044 // multisampled, and the rect won't land on integer coords.
1045
1046 if (!paint.fAntiAlias) {
1047 return false;
1048 }
1049
1050 if (target->getRenderTarget()->isMultisampled()) {
1051 return false;
1052 }
1053
1054 if (0 == width && gpu->supportsAALines()) {
1055 return false;
1056 }
1057
1058 if (!target->getViewMatrix().preservesAxisAlignment()) {
1059 return false;
1060 }
1061
1062 if (NULL != matrix &&
1063 !matrix->preservesAxisAlignment()) {
1064 return false;
1065 }
1066
1067 *combinedMatrix = target->getViewMatrix();
1068 if (NULL != matrix) {
1069 combinedMatrix->preConcat(*matrix);
1070 GrAssert(combinedMatrix->preservesAxisAlignment());
1071 }
1072
1073 combinedMatrix->mapRect(devRect, rect);
1074 devRect->sort();
1075
1076 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001077 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001078 } else {
1079 return true;
1080 }
1081}
1082
bsalomon@google.com27847de2011-02-22 20:59:41 +00001083void GrContext::drawRect(const GrPaint& paint,
1084 const GrRect& rect,
1085 GrScalar width,
1086 const GrMatrix* matrix) {
1087
bsalomon@google.com27847de2011-02-22 20:59:41 +00001088
1089 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001090 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001091
bsalomon@google.com205d4602011-04-25 12:43:45 +00001092 GrRect devRect = rect;
1093 GrMatrix combinedMatrix;
1094 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1095 &combinedMatrix, &devRect);
1096
1097 if (doAA) {
1098 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001099 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001100 GrMatrix inv;
1101 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001102 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001103 }
1104 }
1105 target->setViewMatrix(GrMatrix::I());
1106 if (width >= 0) {
1107 GrVec strokeSize;;
1108 if (width > 0) {
1109 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001110 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001111 strokeSize.setAbs(strokeSize);
1112 } else {
1113 strokeSize.set(GR_Scalar1, GR_Scalar1);
1114 }
1115 strokeAARect(target, paint, devRect, strokeSize);
1116 } else {
1117 fillAARect(target, paint, devRect);
1118 }
1119 return;
1120 }
1121
bsalomon@google.com27847de2011-02-22 20:59:41 +00001122 if (width >= 0) {
1123 // TODO: consider making static vertex buffers for these cases.
1124 // Hairline could be done by just adding closing vertex to
1125 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001126 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1127
bsalomon@google.com27847de2011-02-22 20:59:41 +00001128 static const int worstCaseVertCount = 10;
1129 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1130
1131 if (!geo.succeeded()) {
1132 return;
1133 }
1134
1135 GrPrimitiveType primType;
1136 int vertCount;
1137 GrPoint* vertex = geo.positions();
1138
1139 if (width > 0) {
1140 vertCount = 10;
1141 primType = kTriangleStrip_PrimitiveType;
1142 setStrokeRectStrip(vertex, rect, width);
1143 } else {
1144 // hairline
1145 vertCount = 5;
1146 primType = kLineStrip_PrimitiveType;
1147 vertex[0].set(rect.fLeft, rect.fTop);
1148 vertex[1].set(rect.fRight, rect.fTop);
1149 vertex[2].set(rect.fRight, rect.fBottom);
1150 vertex[3].set(rect.fLeft, rect.fBottom);
1151 vertex[4].set(rect.fLeft, rect.fTop);
1152 }
1153
1154 GrDrawTarget::AutoViewMatrixRestore avmr;
1155 if (NULL != matrix) {
1156 avmr.set(target);
1157 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001158 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001159 }
1160
1161 target->drawNonIndexed(primType, 0, vertCount);
1162 } else {
1163 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001164 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1165
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001166 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001167 fGpu->getUnitSquareVertexBuffer());
1168 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1169 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001170 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001171 0, rect.height(), rect.fTop,
1172 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001173
1174 if (NULL != matrix) {
1175 m.postConcat(*matrix);
1176 }
1177
1178 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001179 target->preConcatSamplerMatrices(stageMask, m);
1180
bsalomon@google.com27847de2011-02-22 20:59:41 +00001181 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1182 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001183 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001184 #endif
1185 }
1186}
1187
1188void GrContext::drawRectToRect(const GrPaint& paint,
1189 const GrRect& dstRect,
1190 const GrRect& srcRect,
1191 const GrMatrix* dstMatrix,
1192 const GrMatrix* srcMatrix) {
1193
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001194 // srcRect refers to paint's first texture
1195 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001196 drawRect(paint, dstRect, -1, dstMatrix);
1197 return;
1198 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001199
bsalomon@google.com27847de2011-02-22 20:59:41 +00001200 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1201
1202#if GR_STATIC_RECT_VB
1203 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001204
1205 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001206 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1207
1208 GrMatrix m;
1209
1210 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1211 0, dstRect.height(), dstRect.fTop,
1212 0, 0, GrMatrix::I()[8]);
1213 if (NULL != dstMatrix) {
1214 m.postConcat(*dstMatrix);
1215 }
1216 target->preConcatViewMatrix(m);
1217
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001218 // srcRect refers to first stage
1219 int otherStageMask = paint.getActiveStageMask() &
1220 (~(1 << GrPaint::kFirstTextureStage));
1221 if (otherStageMask) {
1222 target->preConcatSamplerMatrices(otherStageMask, m);
1223 }
1224
bsalomon@google.com27847de2011-02-22 20:59:41 +00001225 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1226 0, srcRect.height(), srcRect.fTop,
1227 0, 0, GrMatrix::I()[8]);
1228 if (NULL != srcMatrix) {
1229 m.postConcat(*srcMatrix);
1230 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001231 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001232
1233 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1234 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1235#else
1236
1237 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001238#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001239 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001240#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001241 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1242#endif
1243
1244 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1245 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1246 srcRects[0] = &srcRect;
1247 srcMatrices[0] = srcMatrix;
1248
1249 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1250#endif
1251}
1252
1253void GrContext::drawVertices(const GrPaint& paint,
1254 GrPrimitiveType primitiveType,
1255 int vertexCount,
1256 const GrPoint positions[],
1257 const GrPoint texCoords[],
1258 const GrColor colors[],
1259 const uint16_t indices[],
1260 int indexCount) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001261
1262 GrDrawTarget::AutoReleaseGeometry geo;
1263
1264 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1265
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001266 bool hasTexCoords[GrPaint::kTotalStages] = {
1267 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1268 0 // remaining stages use positions
1269 };
1270
1271 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001272
1273 if (NULL != colors) {
1274 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001275 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001276 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001277
1278 if (sizeof(GrPoint) != vertexSize) {
1279 if (!geo.set(target, layout, vertexCount, 0)) {
1280 GrPrintf("Failed to get space for vertices!");
1281 return;
1282 }
1283 int texOffsets[GrDrawTarget::kMaxTexCoords];
1284 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001285 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1286 texOffsets,
1287 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001288 void* curVertex = geo.vertices();
1289
1290 for (int i = 0; i < vertexCount; ++i) {
1291 *((GrPoint*)curVertex) = positions[i];
1292
1293 if (texOffsets[0] > 0) {
1294 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1295 }
1296 if (colorOffset > 0) {
1297 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1298 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001299 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001300 }
1301 } else {
1302 target->setVertexSourceToArray(layout, positions, vertexCount);
1303 }
1304
bsalomon@google.com91958362011-06-13 17:58:13 +00001305 // we don't currently apply offscreen AA to this path. Need improved
1306 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001307
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001308 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001309 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001310 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001311 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001312 target->drawNonIndexed(primitiveType, 0, vertexCount);
1313 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001314}
1315
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001316///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001317
reed@google.com07f3ee12011-05-16 17:21:57 +00001318void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1319 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001320
bsalomon@google.com27847de2011-02-22 20:59:41 +00001321 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001322 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001323
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001324 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001325 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001326
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001327 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001328
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001329 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001330 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1331 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001332 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001333 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001334 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001335 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001336 return;
1337 }
1338 }
reed@google.com70c136e2011-06-03 19:51:26 +00001339
reed@google.com07f3ee12011-05-16 17:21:57 +00001340 GrRect pathBounds = path.getBounds();
1341 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001342 if (NULL != translate) {
1343 pathBounds.offset(*translate);
1344 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001345 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001346 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001347 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001348 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001349 return;
1350 }
1351 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001352 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001353 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1354 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001355 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1356 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1357 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
1358 pr->drawPath(target, 0, path, fill, translate);
1359 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1360 }
1361 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001362 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001363 if (IsFillInverted(fill) && bound != clipIBounds) {
1364 int stageMask = paint.getActiveStageMask();
1365 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1366 GrRect rect;
1367 if (clipIBounds.fTop < bound.fTop) {
1368 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1369 clipIBounds.fRight, bound.fTop);
1370 target->drawSimpleRect(rect, NULL, stageMask);
1371 }
1372 if (clipIBounds.fLeft < bound.fLeft) {
1373 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1374 bound.fLeft, bound.fBottom);
1375 target->drawSimpleRect(rect, NULL, stageMask);
1376 }
1377 if (clipIBounds.fRight > bound.fRight) {
1378 rect.setLTRB(bound.fRight, bound.fTop,
1379 clipIBounds.fRight, bound.fBottom);
1380 target->drawSimpleRect(rect, NULL, stageMask);
1381 }
1382 if (clipIBounds.fBottom > bound.fBottom) {
1383 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1384 clipIBounds.fRight, clipIBounds.fBottom);
1385 target->drawSimpleRect(rect, NULL, stageMask);
1386 }
1387 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001388 return;
1389 }
reed@google.com70c136e2011-06-03 19:51:26 +00001390 }
1391
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001392 GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001393
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001394 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001395}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001396
bsalomon@google.com27847de2011-02-22 20:59:41 +00001397////////////////////////////////////////////////////////////////////////////////
1398
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001399void GrContext::flush(int flagsBitfield) {
1400 if (kDiscard_FlushBit & flagsBitfield) {
1401 fDrawBuffer->reset();
1402 } else {
1403 flushDrawBuffer();
1404 }
1405
1406 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001407 fGpu->forceRenderTargetFlush();
1408 }
1409}
1410
1411void GrContext::flushText() {
1412 if (kText_DrawCategory == fLastDrawCategory) {
1413 flushDrawBuffer();
1414 }
1415}
1416
1417void GrContext::flushDrawBuffer() {
1418#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001419 if (fDrawBuffer) {
1420 fDrawBuffer->playback(fGpu);
1421 fDrawBuffer->reset();
1422 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001423#endif
1424}
1425
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001426bool GrContext::readTexturePixels(GrTexture* texture,
1427 int left, int top, int width, int height,
1428 GrPixelConfig config, void* buffer) {
1429
1430 // TODO: code read pixels for textures that aren't rendertargets
1431
1432 this->flush();
1433 GrRenderTarget* target = texture->asRenderTarget();
1434 if (NULL != target) {
1435 return fGpu->readPixels(target,
1436 left, top, width, height,
1437 config, buffer);
1438 } else {
1439 return false;
1440 }
1441}
1442
1443bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1444 int left, int top, int width, int height,
1445 GrPixelConfig config, void* buffer) {
1446 uint32_t flushFlags = 0;
1447 if (NULL == target) {
1448 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1449 }
1450
1451 this->flush(flushFlags);
1452 return fGpu->readPixels(target,
1453 left, top, width, height,
1454 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001455}
1456
1457void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001458 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001459 size_t stride) {
1460
1461 // TODO: when underlying api has a direct way to do this we should use it
1462 // (e.g. glDrawPixels on desktop GL).
1463
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001464 const GrTextureDesc desc = {
1465 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001466 };
1467 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1468 if (NULL == texture) {
1469 return;
1470 }
1471
1472 this->flush(true);
1473
1474 GrAutoUnref aur(texture);
1475 GrDrawTarget::AutoStateRestore asr(fGpu);
1476
1477 GrMatrix matrix;
1478 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1479 fGpu->setViewMatrix(matrix);
1480
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001481 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001482 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1483 fGpu->setAlpha(0xFF);
1484 fGpu->setBlendFunc(kOne_BlendCoeff,
1485 kZero_BlendCoeff);
1486 fGpu->setTexture(0, texture);
1487
1488 GrSamplerState sampler;
1489 sampler.setClampNoFilter();
1490 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1491 sampler.setMatrix(matrix);
1492 fGpu->setSamplerState(0, sampler);
1493
1494 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1495 static const int VCOUNT = 4;
1496
1497 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1498 if (!geo.succeeded()) {
1499 return;
1500 }
1501 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1502 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1503}
1504////////////////////////////////////////////////////////////////////////////////
1505
1506void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001507
1508 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1509 int s = i + GrPaint::kFirstTextureStage;
1510 target->setTexture(s, paint.getTexture(i));
1511 target->setSamplerState(s, *paint.getTextureSampler(i));
1512 }
1513
1514 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1515
1516 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1517 int s = i + GrPaint::kFirstMaskStage;
1518 target->setTexture(s, paint.getMask(i));
1519 target->setSamplerState(s, *paint.getMaskSampler(i));
1520 }
1521
bsalomon@google.com27847de2011-02-22 20:59:41 +00001522 target->setColor(paint.fColor);
1523
1524 if (paint.fDither) {
1525 target->enableState(GrDrawTarget::kDither_StateBit);
1526 } else {
1527 target->disableState(GrDrawTarget::kDither_StateBit);
1528 }
1529 if (paint.fAntiAlias) {
1530 target->enableState(GrDrawTarget::kAntialias_StateBit);
1531 } else {
1532 target->disableState(GrDrawTarget::kAntialias_StateBit);
1533 }
1534 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001535 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001536}
1537
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001538GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001539 DrawCategory category) {
1540 if (category != fLastDrawCategory) {
1541 flushDrawBuffer();
1542 fLastDrawCategory = category;
1543 }
1544 SetPaint(paint, fGpu);
1545 GrDrawTarget* target = fGpu;
1546 switch (category) {
1547 case kText_DrawCategory:
1548#if DEFER_TEXT_RENDERING
1549 target = fDrawBuffer;
1550 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1551#else
1552 target = fGpu;
1553#endif
1554 break;
1555 case kUnbuffered_DrawCategory:
1556 target = fGpu;
1557 break;
1558 case kBuffered_DrawCategory:
1559 target = fDrawBuffer;
1560 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1561 break;
1562 }
1563 return target;
1564}
1565
1566////////////////////////////////////////////////////////////////////////////////
1567
bsalomon@google.com27847de2011-02-22 20:59:41 +00001568void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001569 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001570 fGpu->setRenderTarget(target);
1571}
1572
1573GrRenderTarget* GrContext::getRenderTarget() {
1574 return fGpu->getRenderTarget();
1575}
1576
1577const GrRenderTarget* GrContext::getRenderTarget() const {
1578 return fGpu->getRenderTarget();
1579}
1580
1581const GrMatrix& GrContext::getMatrix() const {
1582 return fGpu->getViewMatrix();
1583}
1584
1585void GrContext::setMatrix(const GrMatrix& m) {
1586 fGpu->setViewMatrix(m);
1587}
1588
1589void GrContext::concatMatrix(const GrMatrix& m) const {
1590 fGpu->preConcatViewMatrix(m);
1591}
1592
1593static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1594 intptr_t mask = 1 << shift;
1595 if (pred) {
1596 bits |= mask;
1597 } else {
1598 bits &= ~mask;
1599 }
1600 return bits;
1601}
1602
1603void GrContext::resetStats() {
1604 fGpu->resetStats();
1605}
1606
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001607const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001608 return fGpu->getStats();
1609}
1610
1611void GrContext::printStats() const {
1612 fGpu->printStats();
1613}
1614
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001615GrContext::GrContext(GrGpu* gpu) :
1616 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1617 gpu->supportsStencilWrapOps()) {
1618
bsalomon@google.com27847de2011-02-22 20:59:41 +00001619 fGpu = gpu;
1620 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001621 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001622
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001623 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1624 fGpu->setClipPathRenderer(fCustomPathRenderer);
1625
bsalomon@google.com27847de2011-02-22 20:59:41 +00001626 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1627 MAX_TEXTURE_CACHE_BYTES);
1628 fFontCache = new GrFontCache(fGpu);
1629
1630 fLastDrawCategory = kUnbuffered_DrawCategory;
1631
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001632 fDrawBuffer = NULL;
1633 fDrawBufferVBAllocPool = NULL;
1634 fDrawBufferIBAllocPool = NULL;
1635
bsalomon@google.com205d4602011-04-25 12:43:45 +00001636 fAAFillRectIndexBuffer = NULL;
1637 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001638
1639 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1640 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1641 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1642 }
1643 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001644
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001645 this->setupDrawBuffer();
1646}
1647
1648void GrContext::setupDrawBuffer() {
1649
1650 GrAssert(NULL == fDrawBuffer);
1651 GrAssert(NULL == fDrawBufferVBAllocPool);
1652 GrAssert(NULL == fDrawBufferIBAllocPool);
1653
bsalomon@google.com27847de2011-02-22 20:59:41 +00001654#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001655 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001656 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001657 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1658 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001659 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001660 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001661 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001662 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1663
1664 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1665 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001666#endif
1667
1668#if BATCH_RECT_TO_RECT
1669 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1670#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001671}
1672
bsalomon@google.com27847de2011-02-22 20:59:41 +00001673GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1674 GrDrawTarget* target;
1675#if DEFER_TEXT_RENDERING
1676 target = prepareToDraw(paint, kText_DrawCategory);
1677#else
1678 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1679#endif
1680 SetPaint(paint, target);
1681 return target;
1682}
1683
1684const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1685 return fGpu->getQuadIndexBuffer();
1686}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001687
1688GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +00001689 const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001690 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001691 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001692 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1693 return fCustomPathRenderer;
1694 } else {
1695 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1696 return &fDefaultPathRenderer;
1697 }
1698}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001699