1 /*
2 Copyright 2011 Google Inc.
3
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"
18 #include "GrGpu.h"
19 #include "GrTextureCache.h"
20 #include "GrTextStrike.h"
21 #include "GrMemory.h"
22 #include "GrClipIterator.h"
23 #include "GrIndexBuffer.h"
24 #include "GrInOrderDrawBuffer.h"
25 #include "GrBufferAllocPool.h"
26 #include "GrPathRenderer.h"
27
28 // larger than this, and we don't AA. set to 0 for no AA
29 #ifndef GR_MAX_OFFSCREEN_AA_DIM
30 #define GR_MAX_OFFSCREEN_AA_DIM 0
31 #endif
32
33 #define DEFER_TEXT_RENDERING 1
34
35 #define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
36
37 static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
38 static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
39
40 static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
41 static 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.
45 static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
46 static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
47
Create(GrEngine engine,GrPlatform3DContext context3D)48 GrContext* GrContext::Create(GrEngine engine,
49 GrPlatform3DContext context3D) {
50 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
CreateGLShaderContext()59 GrContext* GrContext::CreateGLShaderContext() {
60 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
61 }
62
~GrContext()63 GrContext::~GrContext() {
64 this->flush();
65 delete fTextureCache;
66 delete fFontCache;
67 delete fDrawBuffer;
68 delete fDrawBufferVBAllocPool;
69 delete fDrawBufferIBAllocPool;
70 GrSafeUnref(fCustomPathRenderer);
71 GrSafeUnref(fAAFillRectIndexBuffer);
72 GrSafeUnref(fAAStrokeRectIndexBuffer);
73 fGpu->unref();
74 }
75
contextLost()76 void GrContext::contextLost() {
77 contextDestroyed();
78 this->setupDrawBuffer();
79 }
80
contextDestroyed()81 void GrContext::contextDestroyed() {
82 // abandon first to so destructors
83 // don't try to free the resources in the API.
84 fGpu->abandonResources();
85
86 delete fDrawBuffer;
87 fDrawBuffer = NULL;
88
89 delete fDrawBufferVBAllocPool;
90 fDrawBufferVBAllocPool = NULL;
91
92 delete fDrawBufferIBAllocPool;
93 fDrawBufferIBAllocPool = NULL;
94
95 GrSafeSetNull(fAAFillRectIndexBuffer);
96 GrSafeSetNull(fAAStrokeRectIndexBuffer);
97
98 fTextureCache->removeAll();
99 fFontCache->freeAll();
100 fGpu->markContextDirty();
101 }
102
resetContext()103 void GrContext::resetContext() {
104 fGpu->markContextDirty();
105 }
106
freeGpuResources()107 void GrContext::freeGpuResources() {
108 this->flush();
109 fTextureCache->removeAll();
110 fFontCache->freeAll();
111 }
112
113 ////////////////////////////////////////////////////////////////////////////////
114
PaintStageVertexLayoutBits(const GrPaint & paint,const bool hasTexCoords[GrPaint::kTotalStages])115 int 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
135 enum {
136 kNPOTBit = 0x1,
137 kFilterBit = 0x2,
138 kKeylessBit = 0x4,
139 };
140
finalizeTextureKey(GrTextureKey * key,const GrSamplerState & sampler,bool keyless) const141 bool 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;
156 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
157 bits |= kFilterBit;
158 }
159 }
160 }
161
162 if (keyless) {
163 bits |= kKeylessBit;
164 }
165 key->finalize(bits);
166 return 0 != bits;
167 }
168
findAndLockTexture(GrTextureKey * key,const GrSamplerState & sampler)169 GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
170 const GrSamplerState& sampler) {
171 finalizeTextureKey(key, sampler, false);
172 return fTextureCache->findAndLock(*key);
173 }
174
stretchImage(void * dst,int dstW,int dstH,void * src,int srcW,int srcH,int bpp)175 static 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
createAndLockTexture(GrTextureKey * key,const GrSamplerState & sampler,const GrTextureDesc & desc,void * srcData,size_t rowBytes)202 GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
203 const GrSamplerState& sampler,
204 const GrTextureDesc& desc,
205 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;
214 bool special = finalizeTextureKey(key, sampler, false);
215 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 }
229 GrTextureDesc rtDesc = desc;
230 rtDesc.fFlags = rtDesc.fFlags |
231 kRenderTarget_GrTextureFlagBit |
232 kNoStencil_GrTextureFlagBit;
233 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());
244 fGpu->disableStencil();
245 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);
251 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 }
260 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
261 GrSamplerState::kClamp_WrapMode,
262 filter);
263 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 }
280 texture->releaseRenderTarget();
281 } 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
287 rtDesc.fFlags = kNone_GrTextureFlags;
288 // no longer need to clamp at min RT size.
289 rtDesc.fWidth = GrNextPow2(desc.fWidth);
290 rtDesc.fHeight = GrNextPow2(desc.fHeight);
291 int bpp = GrBytesPerPixel(desc.fFormat);
292 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
lockKeylessTexture(const GrTextureDesc & desc)319 GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
320 uint32_t p0 = desc.fFormat;
321 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
322 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
323 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
324
325 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
unlockTexture(GrTextureEntry * entry)341 void GrContext::unlockTexture(GrTextureEntry* entry) {
342 if (kKeylessBit & entry->key().getPrivateBits()) {
343 fTextureCache->reattachAndUnlock(entry);
344 } else {
345 fTextureCache->unlock(entry);
346 }
347 }
348
createUncachedTexture(const GrTextureDesc & desc,void * srcData,size_t rowBytes)349 GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
350 void* srcData,
351 size_t rowBytes) {
352 return fGpu->createTexture(desc, srcData, rowBytes);
353 }
354
getTextureCacheLimits(int * maxTextures,size_t * maxTextureBytes) const355 void GrContext::getTextureCacheLimits(int* maxTextures,
356 size_t* maxTextureBytes) const {
357 fTextureCache->getLimits(maxTextures, maxTextureBytes);
358 }
359
setTextureCacheLimits(int maxTextures,size_t maxTextureBytes)360 void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
361 fTextureCache->setLimits(maxTextures, maxTextureBytes);
362 }
363
getMaxTextureDimension()364 int GrContext::getMaxTextureDimension() {
365 return fGpu->maxTextureDimension();
366 }
367
368 ///////////////////////////////////////////////////////////////////////////////
369
createPlatformSurface(const GrPlatformSurfaceDesc & desc)370 GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
371 // validate flags here so that GrGpu subclasses don't have to check
372 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
373 0 != desc.fRenderTargetFlags) {
374 return NULL;
375 }
376 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
377 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
378 return NULL;
379 }
380 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
381 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
382 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
383 return NULL;
384 }
385 return fGpu->createPlatformSurface(desc);
386 }
387
createRenderTargetFrom3DApiState()388 GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
389 return fGpu->createRenderTargetFrom3DApiState();
390 }
391
392 ///////////////////////////////////////////////////////////////////////////////
393
supportsIndex8PixelConfig(const GrSamplerState & sampler,int width,int height)394 bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
395 int width, int height) {
396 if (!fGpu->supports8BitPalette()) {
397 return false;
398 }
399
400
401 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
402
403 if (!isPow2) {
404 if (!fGpu->npotTextureSupport()) {
405 return false;
406 }
407
408 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
409 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
410 if (tiled && !fGpu->npotTextureTileSupport()) {
411 return false;
412 }
413 }
414 return true;
415 }
416
417 ////////////////////////////////////////////////////////////////////////////////
418
getClip() const419 const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
420
setClip(const GrClip & clip)421 void GrContext::setClip(const GrClip& clip) {
422 fGpu->setClip(clip);
423 fGpu->enableState(GrDrawTarget::kClip_StateBit);
424 }
425
setClip(const GrIRect & rect)426 void GrContext::setClip(const GrIRect& rect) {
427 GrClip clip;
428 clip.setFromIRect(rect);
429 fGpu->setClip(clip);
430 }
431
432 ////////////////////////////////////////////////////////////////////////////////
433
clear(const GrIRect * rect,const GrColor color)434 void GrContext::clear(const GrIRect* rect, const GrColor color) {
435 this->flush();
436 fGpu->clear(rect, color);
437 }
438
drawPaint(const GrPaint & paint)439 void GrContext::drawPaint(const GrPaint& paint) {
440 // set rect to be big enough to fill the space, but not super-huge, so we
441 // don't overflow fixed-point implementations
442 GrRect r;
443 r.setLTRB(0, 0,
444 GrIntToScalar(getRenderTarget()->width()),
445 GrIntToScalar(getRenderTarget()->height()));
446 GrMatrix inverse;
447 if (fGpu->getViewInverse(&inverse)) {
448 inverse.mapRect(&r);
449 } else {
450 GrPrintf("---- fGpu->getViewInverse failed\n");
451 }
452 this->drawRect(paint, r);
453 }
454
455 ////////////////////////////////////////////////////////////////////////////////
456
doOffscreenAA(GrDrawTarget * target,const GrPaint & paint,bool isLines) const457 bool GrContext::doOffscreenAA(GrDrawTarget* target,
458 const GrPaint& paint,
459 bool isLines) const {
460 #if GR_MAX_OFFSCREEN_AA_DIM==0
461 return false;
462 #else
463 if (!paint.fAntiAlias) {
464 return false;
465 }
466 if (isLines && fGpu->supportsAALines()) {
467 return false;
468 }
469 if (target->getRenderTarget()->isMultisampled()) {
470 return false;
471 }
472 // we have to be sure that the blend equation is expressible
473 // as simple src / dst coeffecients when the source
474 // is already modulated by the coverage fraction.
475 // We could use dual-source blending to get the correct per-pixel
476 // dst coeffecient for the remaining cases.
477 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
478 kOne_BlendCoeff != paint.fDstBlendCoeff &&
479 kISA_BlendCoeff != paint.fDstBlendCoeff) {
480 return false;
481 }
482 return true;
483 #endif
484 }
485
setupOffscreenAAPass1(GrDrawTarget * target,bool requireStencil,const GrIRect & boundRect,OffscreenRecord * record)486 bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
487 bool requireStencil,
488 const GrIRect& boundRect,
489 OffscreenRecord* record) {
490 GrAssert(GR_MAX_OFFSCREEN_AA_DIM > 0);
491
492 GrAssert(NULL == record->fEntry0);
493 GrAssert(NULL == record->fEntry1);
494
495 int boundW = boundRect.width();
496 int boundH = boundRect.height();
497 int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH)));
498
499 GrTextureDesc desc;
500 if (requireStencil) {
501 desc.fFlags = kRenderTarget_GrTextureFlagBit;
502 } else {
503 desc.fFlags = kRenderTarget_GrTextureFlagBit |
504 kNoStencil_GrTextureFlagBit;
505 }
506
507 desc.fFormat = kRGBA_8888_GrPixelConfig;
508
509 int scale;
510 // Using MSAA seems to be slower for some yet unknown reason.
511 if (false && fGpu->supportsFullsceneAA()) {
512 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
513 scale = GR_Scalar1;
514 desc.fAALevel = kMed_GrAALevel;
515 } else {
516 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
517 OffscreenRecord::k4x4SinglePass_Downsample :
518 OffscreenRecord::k4x4TwoPass_Downsample;
519 scale = 4;
520 desc.fAALevel = kNone_GrAALevel;
521 }
522
523 desc.fWidth = scale * size;
524 desc.fHeight = scale * size;
525
526 record->fEntry0 = this->lockKeylessTexture(desc);
527
528 if (NULL == record->fEntry0) {
529 return false;
530 }
531
532 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
533 desc.fWidth /= 2;
534 desc.fHeight /= 2;
535 record->fEntry1 = this->lockKeylessTexture(desc);
536 if (NULL == record->fEntry1) {
537 this->unlockTexture(record->fEntry0);
538 record->fEntry0 = NULL;
539 return false;
540 }
541 }
542
543 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
544 GrAssert(NULL != offRT0);
545
546 target->saveCurrentDrawState(&record->fSavedState);
547
548 GrPaint tempPaint;
549 tempPaint.reset();
550 SetPaint(tempPaint, target);
551 target->setRenderTarget(offRT0);
552
553 GrMatrix transM;
554 transM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
555 target->postConcatViewMatrix(transM);
556 GrMatrix scaleM;
557 scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1);
558 target->postConcatViewMatrix(scaleM);
559
560 // clip gets applied in second pass
561 target->disableState(GrDrawTarget::kClip_StateBit);
562
563 GrIRect clear = SkIRect::MakeWH(scale * boundW, scale * boundH);
564 target->clear(&clear, 0x0);
565
566 return true;
567 }
568
offscreenAAPass2(GrDrawTarget * target,const GrPaint & paint,const GrIRect & boundRect,OffscreenRecord * record)569 void GrContext::offscreenAAPass2(GrDrawTarget* target,
570 const GrPaint& paint,
571 const GrIRect& boundRect,
572 OffscreenRecord* record) {
573
574 GrAssert(NULL != record->fEntry0);
575
576 GrSamplerState::Filter filter;
577 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
578 filter = GrSamplerState::k4x4Downsample_Filter;
579 } else {
580 filter = GrSamplerState::kBilinear_Filter;
581 }
582
583 GrMatrix sampleM;
584 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
585 GrSamplerState::kClamp_WrapMode, filter);
586
587 GrTexture* src = record->fEntry0->texture();
588 int scale;
589
590 enum {
591 kOffscreenStage = GrPaint::kTotalStages,
592 };
593
594 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
595 GrAssert(NULL != record->fEntry1);
596 scale = 2;
597 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
598
599 // Do 2x2 downsample from first to second
600 target->setTexture(kOffscreenStage, src);
601 target->setRenderTarget(dst);
602 target->setViewMatrix(GrMatrix::I());
603 sampleM.setScale(scale * GR_Scalar1 / src->width(),
604 scale * GR_Scalar1 / src->height());
605 sampler.setMatrix(sampleM);
606 target->setSamplerState(kOffscreenStage, sampler);
607 GrRect rect = SkRect::MakeWH(scale * boundRect.width(),
608 scale * boundRect.height());
609 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
610
611 src = record->fEntry1->texture();
612 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
613 scale = 1;
614 GrIRect rect = SkIRect::MakeWH(boundRect.width(), boundRect.height());
615 src->asRenderTarget()->overrideResolveRect(rect);
616 } else {
617 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
618 record->fDownsample);
619 scale = 4;
620 }
621
622 // setup for draw back to main RT
623 int stageMask = paint.getActiveStageMask();
624
625 target->restoreDrawState(record->fSavedState);
626
627 if (stageMask) {
628 GrMatrix invVM;
629 if (target->getViewInverse(&invVM)) {
630 target->preConcatSamplerMatrices(stageMask, invVM);
631 }
632 }
633 target->setViewMatrix(GrMatrix::I());
634
635 target->setTexture(kOffscreenStage, src);
636 sampleM.setScale(scale * GR_Scalar1 / src->width(),
637 scale * GR_Scalar1 / src->height());
638 sampler.setMatrix(sampleM);
639 sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
640 sampler.preConcatMatrix(sampleM);
641 target->setSamplerState(kOffscreenStage, sampler);
642
643 GrRect dstRect;
644 int stages = (1 << kOffscreenStage) | stageMask;
645 dstRect.set(boundRect);
646 target->drawSimpleRect(dstRect, NULL, stages);
647
648 this->unlockTexture(record->fEntry0);
649 record->fEntry0 = NULL;
650 if (NULL != record->fEntry1) {
651 this->unlockTexture(record->fEntry1);
652 record->fEntry1 = NULL;
653 }
654 target->restoreDrawState(record->fSavedState);
655 }
656
657 ////////////////////////////////////////////////////////////////////////////////
658
659 /* create a triangle strip that strokes the specified triangle. There are 8
660 unique vertices, but we repreat the last 2 to close up. Alternatively we
661 could use an indices array, and then only send 8 verts, but not sure that
662 would be faster.
663 */
setStrokeRectStrip(GrPoint verts[10],GrRect rect,GrScalar width)664 static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
665 GrScalar width) {
666 const GrScalar rad = GrScalarHalf(width);
667 rect.sort();
668
669 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
670 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
671 verts[2].set(rect.fRight - rad, rect.fTop + rad);
672 verts[3].set(rect.fRight + rad, rect.fTop - rad);
673 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
674 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
675 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
676 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
677 verts[8] = verts[0];
678 verts[9] = verts[1];
679 }
680
getColorForMesh(const GrPaint & paint)681 static GrColor getColorForMesh(const GrPaint& paint) {
682 // FIXME: This was copied from SkGpuDevice, seems like
683 // we should have already smeared a in caller if that
684 // is what is desired.
685 if (paint.hasTexture()) {
686 unsigned a = GrColorUnpackA(paint.fColor);
687 return GrColorPackRGBA(a, a, a, a);
688 } else {
689 return paint.fColor;
690 }
691 }
692
setInsetFan(GrPoint * pts,size_t stride,const GrRect & r,GrScalar dx,GrScalar dy)693 static void setInsetFan(GrPoint* pts, size_t stride,
694 const GrRect& r, GrScalar dx, GrScalar dy) {
695 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
696 }
697
698 static const uint16_t gFillAARectIdx[] = {
699 0, 1, 5, 5, 4, 0,
700 1, 2, 6, 6, 5, 1,
701 2, 3, 7, 7, 6, 2,
702 3, 0, 4, 4, 7, 3,
703 4, 5, 6, 6, 7, 4,
704 };
705
aaFillRectIndexCount() const706 int GrContext::aaFillRectIndexCount() const {
707 return GR_ARRAY_COUNT(gFillAARectIdx);
708 }
709
aaFillRectIndexBuffer()710 GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
711 if (NULL == fAAFillRectIndexBuffer) {
712 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
713 false);
714 GrAssert(NULL != fAAFillRectIndexBuffer);
715 #if GR_DEBUG
716 bool updated =
717 #endif
718 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
719 sizeof(gFillAARectIdx));
720 GR_DEBUGASSERT(updated);
721 }
722 return fAAFillRectIndexBuffer;
723 }
724
725 static const uint16_t gStrokeAARectIdx[] = {
726 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
727 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
728 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
729 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
730
731 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
732 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
733 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
734 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
735
736 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
737 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
738 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
739 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
740 };
741
aaStrokeRectIndexCount() const742 int GrContext::aaStrokeRectIndexCount() const {
743 return GR_ARRAY_COUNT(gStrokeAARectIdx);
744 }
745
aaStrokeRectIndexBuffer()746 GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
747 if (NULL == fAAStrokeRectIndexBuffer) {
748 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
749 false);
750 GrAssert(NULL != fAAStrokeRectIndexBuffer);
751 #if GR_DEBUG
752 bool updated =
753 #endif
754 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
755 sizeof(gStrokeAARectIdx));
756 GR_DEBUGASSERT(updated);
757 }
758 return fAAStrokeRectIndexBuffer;
759 }
760
fillAARect(GrDrawTarget * target,const GrPaint & paint,const GrRect & devRect)761 void GrContext::fillAARect(GrDrawTarget* target,
762 const GrPaint& paint,
763 const GrRect& devRect) {
764
765 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
766 GrDrawTarget::kColor_VertexLayoutBit;
767
768 size_t vsize = GrDrawTarget::VertexSize(layout);
769
770 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
771
772 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
773
774 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
775 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
776
777 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
778 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
779
780 verts += sizeof(GrPoint);
781 for (int i = 0; i < 4; ++i) {
782 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
783 }
784
785 GrColor innerColor = getColorForMesh(paint);
786 verts += 4 * vsize;
787 for (int i = 0; i < 4; ++i) {
788 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
789 }
790
791 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
792
793 target->drawIndexed(kTriangles_PrimitiveType, 0,
794 0, 8, this->aaFillRectIndexCount());
795 }
796
strokeAARect(GrDrawTarget * target,const GrPaint & paint,const GrRect & devRect,const GrVec & devStrokeSize)797 void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
798 const GrRect& devRect, const GrVec& devStrokeSize) {
799 const GrScalar& dx = devStrokeSize.fX;
800 const GrScalar& dy = devStrokeSize.fY;
801 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
802 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
803
804 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
805 GrDrawTarget::kColor_VertexLayoutBit;
806
807 GrScalar spare;
808 {
809 GrScalar w = devRect.width() - dx;
810 GrScalar h = devRect.height() - dy;
811 spare = GrMin(w, h);
812 }
813
814 if (spare <= 0) {
815 GrRect r(devRect);
816 r.inset(-rx, -ry);
817 fillAARect(target, paint, r);
818 return;
819 }
820
821 size_t vsize = GrDrawTarget::VertexSize(layout);
822
823 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
824
825 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
826
827 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
828 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
829 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
830 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
831
832 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
833 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
834 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
835 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
836
837 verts += sizeof(GrPoint);
838 for (int i = 0; i < 4; ++i) {
839 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
840 }
841
842 GrColor innerColor = getColorForMesh(paint);
843 verts += 4 * vsize;
844 for (int i = 0; i < 8; ++i) {
845 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
846 }
847
848 verts += 8 * vsize;
849 for (int i = 0; i < 8; ++i) {
850 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
851 }
852
853 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
854 target->drawIndexed(kTriangles_PrimitiveType,
855 0, 0, 16, aaStrokeRectIndexCount());
856 }
857
858 /**
859 * Returns true if the rects edges are integer-aligned.
860 */
isIRect(const GrRect & r)861 static bool isIRect(const GrRect& r) {
862 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
863 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
864 }
865
apply_aa_to_rect(GrDrawTarget * target,GrGpu * gpu,const GrPaint & paint,const GrRect & rect,GrScalar width,const GrMatrix * matrix,GrMatrix * combinedMatrix,GrRect * devRect)866 static bool apply_aa_to_rect(GrDrawTarget* target,
867 GrGpu* gpu,
868 const GrPaint& paint,
869 const GrRect& rect,
870 GrScalar width,
871 const GrMatrix* matrix,
872 GrMatrix* combinedMatrix,
873 GrRect* devRect) {
874 // we use a simple alpha ramp to do aa on axis-aligned rects
875 // do AA with alpha ramp if the caller requested AA, the rect
876 // will be axis-aligned,the render target is not
877 // multisampled, and the rect won't land on integer coords.
878
879 if (!paint.fAntiAlias) {
880 return false;
881 }
882
883 if (target->getRenderTarget()->isMultisampled()) {
884 return false;
885 }
886
887 if (0 == width && gpu->supportsAALines()) {
888 return false;
889 }
890
891 if (!target->getViewMatrix().preservesAxisAlignment()) {
892 return false;
893 }
894
895 if (NULL != matrix &&
896 !matrix->preservesAxisAlignment()) {
897 return false;
898 }
899
900 *combinedMatrix = target->getViewMatrix();
901 if (NULL != matrix) {
902 combinedMatrix->preConcat(*matrix);
903 GrAssert(combinedMatrix->preservesAxisAlignment());
904 }
905
906 combinedMatrix->mapRect(devRect, rect);
907 devRect->sort();
908
909 if (width < 0) {
910 return !isIRect(*devRect);
911 } else {
912 return true;
913 }
914 }
915
drawRect(const GrPaint & paint,const GrRect & rect,GrScalar width,const GrMatrix * matrix)916 void GrContext::drawRect(const GrPaint& paint,
917 const GrRect& rect,
918 GrScalar width,
919 const GrMatrix* matrix) {
920
921
922 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
923 int stageMask = paint.getActiveStageMask();
924
925 GrRect devRect = rect;
926 GrMatrix combinedMatrix;
927 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
928 &combinedMatrix, &devRect);
929
930 if (doAA) {
931 GrDrawTarget::AutoViewMatrixRestore avm(target);
932 if (stageMask) {
933 GrMatrix inv;
934 if (combinedMatrix.invert(&inv)) {
935 target->preConcatSamplerMatrices(stageMask, inv);
936 }
937 }
938 target->setViewMatrix(GrMatrix::I());
939 if (width >= 0) {
940 GrVec strokeSize;;
941 if (width > 0) {
942 strokeSize.set(width, width);
943 combinedMatrix.mapVectors(&strokeSize, 1);
944 strokeSize.setAbs(strokeSize);
945 } else {
946 strokeSize.set(GR_Scalar1, GR_Scalar1);
947 }
948 strokeAARect(target, paint, devRect, strokeSize);
949 } else {
950 fillAARect(target, paint, devRect);
951 }
952 return;
953 }
954
955 if (width >= 0) {
956 // TODO: consider making static vertex buffers for these cases.
957 // Hairline could be done by just adding closing vertex to
958 // unitSquareVertexBuffer()
959 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
960
961 static const int worstCaseVertCount = 10;
962 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
963
964 if (!geo.succeeded()) {
965 return;
966 }
967
968 GrPrimitiveType primType;
969 int vertCount;
970 GrPoint* vertex = geo.positions();
971
972 if (width > 0) {
973 vertCount = 10;
974 primType = kTriangleStrip_PrimitiveType;
975 setStrokeRectStrip(vertex, rect, width);
976 } else {
977 // hairline
978 vertCount = 5;
979 primType = kLineStrip_PrimitiveType;
980 vertex[0].set(rect.fLeft, rect.fTop);
981 vertex[1].set(rect.fRight, rect.fTop);
982 vertex[2].set(rect.fRight, rect.fBottom);
983 vertex[3].set(rect.fLeft, rect.fBottom);
984 vertex[4].set(rect.fLeft, rect.fTop);
985 }
986
987 GrDrawTarget::AutoViewMatrixRestore avmr;
988 if (NULL != matrix) {
989 avmr.set(target);
990 target->preConcatViewMatrix(*matrix);
991 target->preConcatSamplerMatrices(stageMask, *matrix);
992 }
993
994 target->drawNonIndexed(primType, 0, vertCount);
995 } else {
996 #if GR_STATIC_RECT_VB
997 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
998
999 target->setVertexSourceToBuffer(layout,
1000 fGpu->getUnitSquareVertexBuffer());
1001 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1002 GrMatrix m;
1003 m.setAll(rect.width(), 0, rect.fLeft,
1004 0, rect.height(), rect.fTop,
1005 0, 0, GrMatrix::I()[8]);
1006
1007 if (NULL != matrix) {
1008 m.postConcat(*matrix);
1009 }
1010
1011 target->preConcatViewMatrix(m);
1012 target->preConcatSamplerMatrices(stageMask, m);
1013
1014 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1015 #else
1016 target->drawSimpleRect(rect, matrix, stageMask);
1017 #endif
1018 }
1019 }
1020
drawRectToRect(const GrPaint & paint,const GrRect & dstRect,const GrRect & srcRect,const GrMatrix * dstMatrix,const GrMatrix * srcMatrix)1021 void GrContext::drawRectToRect(const GrPaint& paint,
1022 const GrRect& dstRect,
1023 const GrRect& srcRect,
1024 const GrMatrix* dstMatrix,
1025 const GrMatrix* srcMatrix) {
1026
1027 // srcRect refers to paint's first texture
1028 if (NULL == paint.getTexture(0)) {
1029 drawRect(paint, dstRect, -1, dstMatrix);
1030 return;
1031 }
1032
1033 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1034
1035 #if GR_STATIC_RECT_VB
1036 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1037
1038 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1039 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1040
1041 GrMatrix m;
1042
1043 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1044 0, dstRect.height(), dstRect.fTop,
1045 0, 0, GrMatrix::I()[8]);
1046 if (NULL != dstMatrix) {
1047 m.postConcat(*dstMatrix);
1048 }
1049 target->preConcatViewMatrix(m);
1050
1051 // srcRect refers to first stage
1052 int otherStageMask = paint.getActiveStageMask() &
1053 (~(1 << GrPaint::kFirstTextureStage));
1054 if (otherStageMask) {
1055 target->preConcatSamplerMatrices(otherStageMask, m);
1056 }
1057
1058 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1059 0, srcRect.height(), srcRect.fTop,
1060 0, 0, GrMatrix::I()[8]);
1061 if (NULL != srcMatrix) {
1062 m.postConcat(*srcMatrix);
1063 }
1064 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
1065
1066 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1067 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1068 #else
1069
1070 GrDrawTarget* target;
1071 #if BATCH_RECT_TO_RECT
1072 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
1073 #else
1074 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1075 #endif
1076
1077 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1078 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1079 srcRects[0] = &srcRect;
1080 srcMatrices[0] = srcMatrix;
1081
1082 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1083 #endif
1084 }
1085
drawVertices(const GrPaint & paint,GrPrimitiveType primitiveType,int vertexCount,const GrPoint positions[],const GrPoint texCoords[],const GrColor colors[],const uint16_t indices[],int indexCount)1086 void GrContext::drawVertices(const GrPaint& paint,
1087 GrPrimitiveType primitiveType,
1088 int vertexCount,
1089 const GrPoint positions[],
1090 const GrPoint texCoords[],
1091 const GrColor colors[],
1092 const uint16_t indices[],
1093 int indexCount) {
1094
1095 GrDrawTarget::AutoReleaseGeometry geo;
1096
1097 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1098
1099 bool hasTexCoords[GrPaint::kTotalStages] = {
1100 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1101 0 // remaining stages use positions
1102 };
1103
1104 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
1105
1106 if (NULL != colors) {
1107 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1108 }
1109 int vertexSize = GrDrawTarget::VertexSize(layout);
1110
1111 bool doAA = false;
1112 OffscreenRecord record;
1113 GrIRect bounds;
1114
1115 if (sizeof(GrPoint) != vertexSize) {
1116 if (!geo.set(target, layout, vertexCount, 0)) {
1117 GrPrintf("Failed to get space for vertices!");
1118 return;
1119 }
1120 int texOffsets[GrDrawTarget::kMaxTexCoords];
1121 int colorOffset;
1122 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1123 texOffsets,
1124 &colorOffset);
1125 void* curVertex = geo.vertices();
1126
1127 for (int i = 0; i < vertexCount; ++i) {
1128 *((GrPoint*)curVertex) = positions[i];
1129
1130 if (texOffsets[0] > 0) {
1131 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1132 }
1133 if (colorOffset > 0) {
1134 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1135 }
1136 curVertex = (void*)((intptr_t)curVertex + vertexSize);
1137 }
1138 } else {
1139 // we don't do offscreen AA when we have per-vertex tex coords or colors
1140 if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) {
1141 GrRect b;
1142 b.setBounds(positions, vertexCount);
1143 target->getViewMatrix().mapRect(&b);
1144 b.roundOut(&bounds);
1145
1146 if (this->setupOffscreenAAPass1(target, false, bounds, &record)) {
1147 doAA = true;
1148 }
1149 }
1150 target->setVertexSourceToArray(layout, positions, vertexCount);
1151 }
1152
1153 if (NULL != indices) {
1154 target->setIndexSourceToArray(indices, indexCount);
1155 }
1156
1157 if (NULL != indices) {
1158 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
1159 } else {
1160 target->drawNonIndexed(primitiveType, 0, vertexCount);
1161 }
1162
1163 if (doAA) {
1164 this->offscreenAAPass2(target, paint, bounds, &record);
1165 }
1166 }
1167
1168
1169 ///////////////////////////////////////////////////////////////////////////////
1170
drawPath(const GrPaint & paint,const GrPath & path,GrPathFill fill,const GrPoint * translate)1171 void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1172 GrPathFill fill, const GrPoint* translate) {
1173
1174 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1175 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1176
1177 if (!IsFillInverted(fill) && // will be relaxed soon
1178 !pr->supportsAA(target, path, fill) &&
1179 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
1180
1181 OffscreenRecord record;
1182 bool needsStencil = pr->requiresStencilPass(target, path, fill);
1183
1184 // compute bounds as intersection of rt size, clip, and path
1185 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1186 target->getRenderTarget()->height());
1187 if (target->getClip().hasConservativeBounds()) {
1188 GrIRect clipIBounds;
1189 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
1190 if (!bound.intersect(clipIBounds)) {
1191 return;
1192 }
1193 }
1194
1195 GrRect pathBounds = path.getBounds();
1196 GrIRect pathIBounds;
1197 if (!pathBounds.isEmpty()) {
1198 if (NULL != translate) {
1199 pathBounds.offset(*translate);
1200 }
1201 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
1202 pathBounds.roundOut(&pathIBounds);
1203 if (!bound.intersect(pathIBounds)) {
1204 return;
1205 }
1206 }
1207
1208 // for now, abort antialiasing if our bounds are too big, so we don't
1209 // hit the FBO size limit
1210 if (pathIBounds.width() > GR_MAX_OFFSCREEN_AA_DIM ||
1211 pathIBounds.height() > GR_MAX_OFFSCREEN_AA_DIM) {
1212 goto NO_AA;
1213 }
1214
1215 if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) {
1216 pr->drawPath(target, 0, path, fill, translate);
1217 this->offscreenAAPass2(target, paint, bound, &record);
1218 return;
1219 }
1220 }
1221
1222 // we can fall out of the AA section for some reasons, and land here
1223 NO_AA:
1224 GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
1225
1226 pr->drawPath(target, enabledStages, path, fill, translate);
1227 }
1228
1229 ////////////////////////////////////////////////////////////////////////////////
1230
flush(int flagsBitfield)1231 void GrContext::flush(int flagsBitfield) {
1232 if (kDiscard_FlushBit & flagsBitfield) {
1233 fDrawBuffer->reset();
1234 } else {
1235 flushDrawBuffer();
1236 }
1237
1238 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
1239 fGpu->forceRenderTargetFlush();
1240 }
1241 }
1242
flushText()1243 void GrContext::flushText() {
1244 if (kText_DrawCategory == fLastDrawCategory) {
1245 flushDrawBuffer();
1246 }
1247 }
1248
flushDrawBuffer()1249 void GrContext::flushDrawBuffer() {
1250 #if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1251 if (fDrawBuffer) {
1252 fDrawBuffer->playback(fGpu);
1253 fDrawBuffer->reset();
1254 }
1255 #endif
1256 }
1257
readTexturePixels(GrTexture * texture,int left,int top,int width,int height,GrPixelConfig config,void * buffer)1258 bool GrContext::readTexturePixels(GrTexture* texture,
1259 int left, int top, int width, int height,
1260 GrPixelConfig config, void* buffer) {
1261
1262 // TODO: code read pixels for textures that aren't rendertargets
1263
1264 this->flush();
1265 GrRenderTarget* target = texture->asRenderTarget();
1266 if (NULL != target) {
1267 return fGpu->readPixels(target,
1268 left, top, width, height,
1269 config, buffer);
1270 } else {
1271 return false;
1272 }
1273 }
1274
readRenderTargetPixels(GrRenderTarget * target,int left,int top,int width,int height,GrPixelConfig config,void * buffer)1275 bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1276 int left, int top, int width, int height,
1277 GrPixelConfig config, void* buffer) {
1278 uint32_t flushFlags = 0;
1279 if (NULL == target) {
1280 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1281 }
1282
1283 this->flush(flushFlags);
1284 return fGpu->readPixels(target,
1285 left, top, width, height,
1286 config, buffer);
1287 }
1288
writePixels(int left,int top,int width,int height,GrPixelConfig config,const void * buffer,size_t stride)1289 void GrContext::writePixels(int left, int top, int width, int height,
1290 GrPixelConfig config, const void* buffer,
1291 size_t stride) {
1292
1293 // TODO: when underlying api has a direct way to do this we should use it
1294 // (e.g. glDrawPixels on desktop GL).
1295
1296 const GrTextureDesc desc = {
1297 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
1298 };
1299 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1300 if (NULL == texture) {
1301 return;
1302 }
1303
1304 this->flush(true);
1305
1306 GrAutoUnref aur(texture);
1307 GrDrawTarget::AutoStateRestore asr(fGpu);
1308
1309 GrMatrix matrix;
1310 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1311 fGpu->setViewMatrix(matrix);
1312
1313 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
1314 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1315 fGpu->setAlpha(0xFF);
1316 fGpu->setBlendFunc(kOne_BlendCoeff,
1317 kZero_BlendCoeff);
1318 fGpu->setTexture(0, texture);
1319
1320 GrSamplerState sampler;
1321 sampler.setClampNoFilter();
1322 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1323 sampler.setMatrix(matrix);
1324 fGpu->setSamplerState(0, sampler);
1325
1326 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1327 static const int VCOUNT = 4;
1328
1329 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1330 if (!geo.succeeded()) {
1331 return;
1332 }
1333 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1334 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1335 }
1336 ////////////////////////////////////////////////////////////////////////////////
1337
SetPaint(const GrPaint & paint,GrDrawTarget * target)1338 void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
1339
1340 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1341 int s = i + GrPaint::kFirstTextureStage;
1342 target->setTexture(s, paint.getTexture(i));
1343 target->setSamplerState(s, *paint.getTextureSampler(i));
1344 }
1345
1346 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1347
1348 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1349 int s = i + GrPaint::kFirstMaskStage;
1350 target->setTexture(s, paint.getMask(i));
1351 target->setSamplerState(s, *paint.getMaskSampler(i));
1352 }
1353
1354 target->setColor(paint.fColor);
1355
1356 if (paint.fDither) {
1357 target->enableState(GrDrawTarget::kDither_StateBit);
1358 } else {
1359 target->disableState(GrDrawTarget::kDither_StateBit);
1360 }
1361 if (paint.fAntiAlias) {
1362 target->enableState(GrDrawTarget::kAntialias_StateBit);
1363 } else {
1364 target->disableState(GrDrawTarget::kAntialias_StateBit);
1365 }
1366 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1367 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1368 }
1369
prepareToDraw(const GrPaint & paint,DrawCategory category)1370 GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
1371 DrawCategory category) {
1372 if (category != fLastDrawCategory) {
1373 flushDrawBuffer();
1374 fLastDrawCategory = category;
1375 }
1376 SetPaint(paint, fGpu);
1377 GrDrawTarget* target = fGpu;
1378 switch (category) {
1379 case kText_DrawCategory:
1380 #if DEFER_TEXT_RENDERING
1381 target = fDrawBuffer;
1382 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1383 #else
1384 target = fGpu;
1385 #endif
1386 break;
1387 case kUnbuffered_DrawCategory:
1388 target = fGpu;
1389 break;
1390 case kBuffered_DrawCategory:
1391 target = fDrawBuffer;
1392 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1393 break;
1394 }
1395 return target;
1396 }
1397
1398 ////////////////////////////////////////////////////////////////////////////////
1399
setRenderTarget(GrRenderTarget * target)1400 void GrContext::setRenderTarget(GrRenderTarget* target) {
1401 this->flush(false);
1402 fGpu->setRenderTarget(target);
1403 }
1404
getRenderTarget()1405 GrRenderTarget* GrContext::getRenderTarget() {
1406 return fGpu->getRenderTarget();
1407 }
1408
getRenderTarget() const1409 const GrRenderTarget* GrContext::getRenderTarget() const {
1410 return fGpu->getRenderTarget();
1411 }
1412
getMatrix() const1413 const GrMatrix& GrContext::getMatrix() const {
1414 return fGpu->getViewMatrix();
1415 }
1416
setMatrix(const GrMatrix & m)1417 void GrContext::setMatrix(const GrMatrix& m) {
1418 fGpu->setViewMatrix(m);
1419 }
1420
concatMatrix(const GrMatrix & m) const1421 void GrContext::concatMatrix(const GrMatrix& m) const {
1422 fGpu->preConcatViewMatrix(m);
1423 }
1424
setOrClear(intptr_t bits,int shift,intptr_t pred)1425 static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1426 intptr_t mask = 1 << shift;
1427 if (pred) {
1428 bits |= mask;
1429 } else {
1430 bits &= ~mask;
1431 }
1432 return bits;
1433 }
1434
resetStats()1435 void GrContext::resetStats() {
1436 fGpu->resetStats();
1437 }
1438
getStats() const1439 const GrGpuStats& GrContext::getStats() const {
1440 return fGpu->getStats();
1441 }
1442
printStats() const1443 void GrContext::printStats() const {
1444 fGpu->printStats();
1445 }
1446
GrContext(GrGpu * gpu)1447 GrContext::GrContext(GrGpu* gpu) :
1448 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1449 gpu->supportsStencilWrapOps()) {
1450
1451 fGpu = gpu;
1452 fGpu->ref();
1453 fGpu->setContext(this);
1454
1455 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1456 fGpu->setClipPathRenderer(fCustomPathRenderer);
1457
1458 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1459 MAX_TEXTURE_CACHE_BYTES);
1460 fFontCache = new GrFontCache(fGpu);
1461
1462 fLastDrawCategory = kUnbuffered_DrawCategory;
1463
1464 fDrawBuffer = NULL;
1465 fDrawBufferVBAllocPool = NULL;
1466 fDrawBufferIBAllocPool = NULL;
1467
1468 fAAFillRectIndexBuffer = NULL;
1469 fAAStrokeRectIndexBuffer = NULL;
1470
1471 this->setupDrawBuffer();
1472 }
1473
setupDrawBuffer()1474 void GrContext::setupDrawBuffer() {
1475
1476 GrAssert(NULL == fDrawBuffer);
1477 GrAssert(NULL == fDrawBufferVBAllocPool);
1478 GrAssert(NULL == fDrawBufferIBAllocPool);
1479
1480 #if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
1481 fDrawBufferVBAllocPool =
1482 new GrVertexBufferAllocPool(fGpu, false,
1483 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1484 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
1485 fDrawBufferIBAllocPool =
1486 new GrIndexBufferAllocPool(fGpu, false,
1487 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
1488 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1489
1490 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1491 fDrawBufferIBAllocPool);
1492 #endif
1493
1494 #if BATCH_RECT_TO_RECT
1495 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1496 #endif
1497 }
1498
getTextTarget(const GrPaint & paint)1499 GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1500 GrDrawTarget* target;
1501 #if DEFER_TEXT_RENDERING
1502 target = prepareToDraw(paint, kText_DrawCategory);
1503 #else
1504 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1505 #endif
1506 SetPaint(paint, target);
1507 return target;
1508 }
1509
getQuadIndexBuffer() const1510 const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1511 return fGpu->getQuadIndexBuffer();
1512 }
1513
getPathRenderer(const GrDrawTarget * target,const GrPath & path,GrPathFill fill)1514 GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1515 const GrPath& path,
1516 GrPathFill fill) {
1517 if (NULL != fCustomPathRenderer &&
1518 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1519 return fCustomPathRenderer;
1520 } else {
1521 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1522 return &fDefaultPathRenderer;
1523 }
1524 }
1525
1526