1
2 /*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10 #include "GrContext.h"
11
12 #include "effects/GrConfigConversionEffect.h"
13 #include "effects/GrDashingEffect.h"
14 #include "effects/GrSingleTextureEffect.h"
15
16 #include "GrAARectRenderer.h"
17 #include "GrBufferAllocPool.h"
18 #include "GrGpu.h"
19 #include "GrDistanceFieldTextContext.h"
20 #include "GrDrawTargetCaps.h"
21 #include "GrIndexBuffer.h"
22 #include "GrInOrderDrawBuffer.h"
23 #include "GrLayerCache.h"
24 #include "GrOvalRenderer.h"
25 #include "GrPathRenderer.h"
26 #include "GrPathUtils.h"
27 #include "GrResourceCache.h"
28 #include "GrResourceCache2.h"
29 #include "GrSoftwarePathRenderer.h"
30 #include "GrStencilBuffer.h"
31 #include "GrStencilAndCoverTextContext.h"
32 #include "GrStrokeInfo.h"
33 #include "GrTextStrike.h"
34 #include "GrTraceMarker.h"
35 #include "GrTracing.h"
36 #include "SkDashPathPriv.h"
37 #include "SkGr.h"
38 #include "SkRTConf.h"
39 #include "SkRRect.h"
40 #include "SkStrokeRec.h"
41 #include "SkTLazy.h"
42 #include "SkTLS.h"
43 #include "SkTraceEvent.h"
44
45 // It can be useful to set this to false to test whether a bug is caused by using the
46 // InOrderDrawBuffer, to compare performance of using/not using InOrderDrawBuffer, or to make
47 // debugging simpler.
48 SK_CONF_DECLARE(bool, c_Defer, "gpu.deferContext", true,
49 "Defers rendering in GrContext via GrInOrderDrawBuffer.");
50
51 #define BUFFERED_DRAW (c_Defer ? kYes_BufferedDraw : kNo_BufferedDraw)
52
53 #ifdef SK_DEBUG
54 // change this to a 1 to see notifications when partial coverage fails
55 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
56 #else
57 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
58 #endif
59
60 static const size_t MAX_RESOURCE_CACHE_COUNT = GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT;
61 static const size_t MAX_RESOURCE_CACHE_BYTES = GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT * 1024 * 1024;
62
63 static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
64 static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
65
66 static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 1 << 11;
67 static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4;
68
69 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
70
71 // Glorified typedef to avoid including GrDrawState.h in GrContext.h
72 class GrContext::AutoRestoreEffects : public GrDrawState::AutoRestoreEffects {};
73
74 class GrContext::AutoCheckFlush {
75 public:
AutoCheckFlush(GrContext * context)76 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
77
~AutoCheckFlush()78 ~AutoCheckFlush() {
79 if (fContext->fFlushToReduceCacheSize) {
80 fContext->flush();
81 }
82 }
83
84 private:
85 GrContext* fContext;
86 };
87
Create(GrBackend backend,GrBackendContext backendContext,const Options * opts)88 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
89 const Options* opts) {
90 GrContext* context;
91 if (NULL == opts) {
92 context = SkNEW_ARGS(GrContext, (Options()));
93 } else {
94 context = SkNEW_ARGS(GrContext, (*opts));
95 }
96
97 if (context->init(backend, backendContext)) {
98 return context;
99 } else {
100 context->unref();
101 return NULL;
102 }
103 }
104
GrContext(const Options & opts)105 GrContext::GrContext(const Options& opts) : fOptions(opts) {
106 fDrawState = NULL;
107 fGpu = NULL;
108 fClip = NULL;
109 fPathRendererChain = NULL;
110 fSoftwarePathRenderer = NULL;
111 fResourceCache = NULL;
112 fResourceCache2 = NULL;
113 fFontCache = NULL;
114 fDrawBuffer = NULL;
115 fDrawBufferVBAllocPool = NULL;
116 fDrawBufferIBAllocPool = NULL;
117 fFlushToReduceCacheSize = false;
118 fAARectRenderer = NULL;
119 fOvalRenderer = NULL;
120 fViewMatrix.reset();
121 fMaxTextureSizeOverride = 1 << 20;
122 }
123
init(GrBackend backend,GrBackendContext backendContext)124 bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
125 SkASSERT(NULL == fGpu);
126
127 fGpu = GrGpu::Create(backend, backendContext, this);
128 if (NULL == fGpu) {
129 return false;
130 }
131
132 fDrawState = SkNEW(GrDrawState);
133 fGpu->setDrawState(fDrawState);
134
135 fResourceCache = SkNEW_ARGS(GrResourceCache, (MAX_RESOURCE_CACHE_COUNT,
136 MAX_RESOURCE_CACHE_BYTES));
137 fResourceCache->setOverbudgetCallback(OverbudgetCB, this);
138 fResourceCache2 = SkNEW(GrResourceCache2);
139
140 fFontCache = SkNEW_ARGS(GrFontCache, (fGpu));
141
142 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this)));
143
144 fLastDrawWasBuffered = kNo_BufferedDraw;
145
146 fAARectRenderer = SkNEW(GrAARectRenderer);
147 fOvalRenderer = SkNEW(GrOvalRenderer);
148
149 fDidTestPMConversions = false;
150
151 this->setupDrawBuffer();
152
153 return true;
154 }
155
~GrContext()156 GrContext::~GrContext() {
157 if (NULL == fGpu) {
158 return;
159 }
160
161 this->flush();
162
163 for (int i = 0; i < fCleanUpData.count(); ++i) {
164 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
165 }
166
167 delete fResourceCache2;
168 fResourceCache2 = NULL;
169 delete fResourceCache;
170 fResourceCache = NULL;
171 delete fFontCache;
172 delete fDrawBuffer;
173 delete fDrawBufferVBAllocPool;
174 delete fDrawBufferIBAllocPool;
175
176 fAARectRenderer->unref();
177 fOvalRenderer->unref();
178
179 fGpu->unref();
180 SkSafeUnref(fPathRendererChain);
181 SkSafeUnref(fSoftwarePathRenderer);
182 fDrawState->unref();
183 }
184
abandonContext()185 void GrContext::abandonContext() {
186 // abandon first to so destructors
187 // don't try to free the resources in the API.
188 fResourceCache2->abandonAll();
189
190 fGpu->contextAbandoned();
191
192 // a path renderer may be holding onto resources that
193 // are now unusable
194 SkSafeSetNull(fPathRendererChain);
195 SkSafeSetNull(fSoftwarePathRenderer);
196
197 delete fDrawBuffer;
198 fDrawBuffer = NULL;
199
200 delete fDrawBufferVBAllocPool;
201 fDrawBufferVBAllocPool = NULL;
202
203 delete fDrawBufferIBAllocPool;
204 fDrawBufferIBAllocPool = NULL;
205
206 fAARectRenderer->reset();
207 fOvalRenderer->reset();
208
209 fResourceCache->purgeAllUnlocked();
210
211 fFontCache->freeAll();
212 fLayerCache->freeAll();
213 }
214
resetContext(uint32_t state)215 void GrContext::resetContext(uint32_t state) {
216 fGpu->markContextDirty(state);
217 }
218
freeGpuResources()219 void GrContext::freeGpuResources() {
220 this->flush();
221
222 fGpu->purgeResources();
223 if (fDrawBuffer) {
224 fDrawBuffer->purgeResources();
225 }
226
227 fAARectRenderer->reset();
228 fOvalRenderer->reset();
229
230 fResourceCache->purgeAllUnlocked();
231 fFontCache->freeAll();
232 fLayerCache->freeAll();
233 // a path renderer may be holding onto resources
234 SkSafeSetNull(fPathRendererChain);
235 SkSafeSetNull(fSoftwarePathRenderer);
236 }
237
getResourceCacheUsage(int * resourceCount,size_t * resourceBytes) const238 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
239 if (resourceCount) {
240 *resourceCount = fResourceCache->getCachedResourceCount();
241 }
242 if (resourceBytes) {
243 *resourceBytes = fResourceCache->getCachedResourceBytes();
244 }
245 }
246
createTextContext(GrRenderTarget * renderTarget,const SkDeviceProperties & leakyProperties,bool enableDistanceFieldFonts)247 GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
248 const SkDeviceProperties&
249 leakyProperties,
250 bool enableDistanceFieldFonts) {
251 if (fGpu->caps()->pathRenderingSupport()) {
252 if (renderTarget->getStencilBuffer() && renderTarget->isMultisampled()) {
253 return SkNEW_ARGS(GrStencilAndCoverTextContext, (this, leakyProperties));
254 }
255 }
256 return SkNEW_ARGS(GrDistanceFieldTextContext, (this, leakyProperties,
257 enableDistanceFieldFonts));
258 }
259
260 ////////////////////////////////////////////////////////////////////////////////
261
findAndRefTexture(const GrTextureDesc & desc,const GrCacheID & cacheID,const GrTextureParams * params)262 GrTexture* GrContext::findAndRefTexture(const GrTextureDesc& desc,
263 const GrCacheID& cacheID,
264 const GrTextureParams* params) {
265 GrResourceKey resourceKey = GrTextureImpl::ComputeKey(fGpu, params, desc, cacheID);
266 GrGpuResource* resource = fResourceCache->find(resourceKey);
267 SkSafeRef(resource);
268 return static_cast<GrTexture*>(resource);
269 }
270
isTextureInCache(const GrTextureDesc & desc,const GrCacheID & cacheID,const GrTextureParams * params) const271 bool GrContext::isTextureInCache(const GrTextureDesc& desc,
272 const GrCacheID& cacheID,
273 const GrTextureParams* params) const {
274 GrResourceKey resourceKey = GrTextureImpl::ComputeKey(fGpu, params, desc, cacheID);
275 return fResourceCache->hasKey(resourceKey);
276 }
277
addStencilBuffer(GrStencilBuffer * sb)278 void GrContext::addStencilBuffer(GrStencilBuffer* sb) {
279 ASSERT_OWNED_RESOURCE(sb);
280
281 GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(sb->width(),
282 sb->height(),
283 sb->numSamples());
284 fResourceCache->addResource(resourceKey, sb);
285 }
286
findStencilBuffer(int width,int height,int sampleCnt)287 GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
288 int sampleCnt) {
289 GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(width,
290 height,
291 sampleCnt);
292 GrGpuResource* resource = fResourceCache->find(resourceKey);
293 return static_cast<GrStencilBuffer*>(resource);
294 }
295
stretch_image(void * dst,int dstW,int dstH,const void * src,int srcW,int srcH,size_t bpp)296 static void stretch_image(void* dst,
297 int dstW,
298 int dstH,
299 const void* src,
300 int srcW,
301 int srcH,
302 size_t bpp) {
303 SkFixed dx = (srcW << 16) / dstW;
304 SkFixed dy = (srcH << 16) / dstH;
305
306 SkFixed y = dy >> 1;
307
308 size_t dstXLimit = dstW*bpp;
309 for (int j = 0; j < dstH; ++j) {
310 SkFixed x = dx >> 1;
311 const uint8_t* srcRow = reinterpret_cast<const uint8_t *>(src) + (y>>16)*srcW*bpp;
312 uint8_t* dstRow = reinterpret_cast<uint8_t *>(dst) + j*dstW*bpp;
313 for (size_t i = 0; i < dstXLimit; i += bpp) {
314 memcpy(dstRow + i, srcRow + (x>>16)*bpp, bpp);
315 x += dx;
316 }
317 y += dy;
318 }
319 }
320
321 namespace {
322
323 // position + local coordinate
324 extern const GrVertexAttrib gVertexAttribs[] = {
325 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
326 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kLocalCoord_GrVertexAttribBinding}
327 };
328
329 };
330
331 // The desired texture is NPOT and tiled but that isn't supported by
332 // the current hardware. Resize the texture to be a POT
createResizedTexture(const GrTextureDesc & desc,const GrCacheID & cacheID,const void * srcData,size_t rowBytes,bool filter)333 GrTexture* GrContext::createResizedTexture(const GrTextureDesc& desc,
334 const GrCacheID& cacheID,
335 const void* srcData,
336 size_t rowBytes,
337 bool filter) {
338 SkAutoTUnref<GrTexture> clampedTexture(this->findAndRefTexture(desc, cacheID, NULL));
339 if (NULL == clampedTexture) {
340 clampedTexture.reset(this->createTexture(NULL, desc, cacheID, srcData, rowBytes));
341
342 if (NULL == clampedTexture) {
343 return NULL;
344 }
345 }
346
347 GrTextureDesc rtDesc = desc;
348 rtDesc.fFlags = rtDesc.fFlags |
349 kRenderTarget_GrTextureFlagBit |
350 kNoStencil_GrTextureFlagBit;
351 rtDesc.fWidth = GrNextPow2(desc.fWidth);
352 rtDesc.fHeight = GrNextPow2(desc.fHeight);
353
354 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
355
356 if (texture) {
357 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
358 GrDrawState* drawState = fGpu->drawState();
359 drawState->setRenderTarget(texture->asRenderTarget());
360
361 // if filtering is not desired then we want to ensure all
362 // texels in the resampled image are copies of texels from
363 // the original.
364 GrTextureParams params(SkShader::kClamp_TileMode, filter ? GrTextureParams::kBilerp_FilterMode :
365 GrTextureParams::kNone_FilterMode);
366 drawState->addColorTextureProcessor(clampedTexture, SkMatrix::I(), params);
367
368 drawState->setVertexAttribs<gVertexAttribs>(SK_ARRAY_COUNT(gVertexAttribs),
369 2 * sizeof(SkPoint));
370
371 GrDrawTarget::AutoReleaseGeometry arg(fGpu, 4, 0);
372
373 if (arg.succeeded()) {
374 SkPoint* verts = (SkPoint*) arg.vertices();
375 verts[0].setIRectFan(0, 0, texture->width(), texture->height(), 2 * sizeof(SkPoint));
376 verts[1].setIRectFan(0, 0, 1, 1, 2 * sizeof(SkPoint));
377 fGpu->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4);
378 }
379 } else {
380 // TODO: Our CPU stretch doesn't filter. But we create separate
381 // stretched textures when the texture params is either filtered or
382 // not. Either implement filtered stretch blit on CPU or just create
383 // one when FBO case fails.
384
385 rtDesc.fFlags = kNone_GrTextureFlags;
386 // no longer need to clamp at min RT size.
387 rtDesc.fWidth = GrNextPow2(desc.fWidth);
388 rtDesc.fHeight = GrNextPow2(desc.fHeight);
389
390 // We shouldn't be resizing a compressed texture.
391 SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
392
393 size_t bpp = GrBytesPerPixel(desc.fConfig);
394 GrAutoMalloc<128*128*4> stretchedPixels(bpp * rtDesc.fWidth * rtDesc.fHeight);
395 stretch_image(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
396 srcData, desc.fWidth, desc.fHeight, bpp);
397
398 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
399
400 texture = fGpu->createTexture(rtDesc, stretchedPixels.get(), stretchedRowBytes);
401 SkASSERT(texture);
402 }
403
404 return texture;
405 }
406
createTexture(const GrTextureParams * params,const GrTextureDesc & desc,const GrCacheID & cacheID,const void * srcData,size_t rowBytes,GrResourceKey * cacheKey)407 GrTexture* GrContext::createTexture(const GrTextureParams* params,
408 const GrTextureDesc& desc,
409 const GrCacheID& cacheID,
410 const void* srcData,
411 size_t rowBytes,
412 GrResourceKey* cacheKey) {
413 GrResourceKey resourceKey = GrTextureImpl::ComputeKey(fGpu, params, desc, cacheID);
414
415 GrTexture* texture;
416 if (GrTextureImpl::NeedsResizing(resourceKey)) {
417 // We do not know how to resize compressed textures.
418 SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
419
420 texture = this->createResizedTexture(desc, cacheID,
421 srcData, rowBytes,
422 GrTextureImpl::NeedsBilerp(resourceKey));
423 } else {
424 texture = fGpu->createTexture(desc, srcData, rowBytes);
425 }
426
427 if (texture) {
428 // Adding a resource could put us overbudget. Try to free up the
429 // necessary space before adding it.
430 fResourceCache->purgeAsNeeded(1, texture->gpuMemorySize());
431 fResourceCache->addResource(resourceKey, texture);
432
433 if (cacheKey) {
434 *cacheKey = resourceKey;
435 }
436 }
437
438 return texture;
439 }
440
create_scratch_texture(GrGpu * gpu,GrResourceCache * resourceCache,const GrTextureDesc & desc)441 static GrTexture* create_scratch_texture(GrGpu* gpu,
442 GrResourceCache* resourceCache,
443 const GrTextureDesc& desc) {
444 GrTexture* texture = gpu->createTexture(desc, NULL, 0);
445 if (texture) {
446 GrResourceKey key = GrTextureImpl::ComputeScratchKey(texture->desc());
447 // Adding a resource could put us overbudget. Try to free up the
448 // necessary space before adding it.
449 resourceCache->purgeAsNeeded(1, texture->gpuMemorySize());
450 // Make the resource exclusive so future 'find' calls don't return it
451 resourceCache->addResource(key, texture, GrResourceCache::kHide_OwnershipFlag);
452 }
453 return texture;
454 }
455
lockAndRefScratchTexture(const GrTextureDesc & inDesc,ScratchTexMatch match)456 GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, ScratchTexMatch match) {
457
458 SkASSERT((inDesc.fFlags & kRenderTarget_GrTextureFlagBit) ||
459 !(inDesc.fFlags & kNoStencil_GrTextureFlagBit));
460
461 // Renderable A8 targets are not universally supported (e.g., not on ANGLE)
462 SkASSERT(this->isConfigRenderable(kAlpha_8_GrPixelConfig, inDesc.fSampleCnt > 0) ||
463 !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit) ||
464 (inDesc.fConfig != kAlpha_8_GrPixelConfig));
465
466 if (!fGpu->caps()->reuseScratchTextures() &&
467 !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit)) {
468 // If we're never recycling this texture we can always make it the right size
469 return create_scratch_texture(fGpu, fResourceCache, inDesc);
470 }
471
472 GrTextureDesc desc = inDesc;
473
474 if (kApprox_ScratchTexMatch == match) {
475 // bin by pow2 with a reasonable min
476 static const int MIN_SIZE = 16;
477 desc.fWidth = SkTMax(MIN_SIZE, GrNextPow2(desc.fWidth));
478 desc.fHeight = SkTMax(MIN_SIZE, GrNextPow2(desc.fHeight));
479 }
480
481 GrGpuResource* resource = NULL;
482 int origWidth = desc.fWidth;
483 int origHeight = desc.fHeight;
484
485 do {
486 GrResourceKey key = GrTextureImpl::ComputeScratchKey(desc);
487 // Ensure we have exclusive access to the texture so future 'find' calls don't return it
488 resource = fResourceCache->find(key, GrResourceCache::kHide_OwnershipFlag);
489 if (resource) {
490 resource->ref();
491 break;
492 }
493 if (kExact_ScratchTexMatch == match) {
494 break;
495 }
496 // We had a cache miss and we are in approx mode, relax the fit of the flags.
497
498 // We no longer try to reuse textures that were previously used as render targets in
499 // situations where no RT is needed; doing otherwise can confuse the video driver and
500 // cause significant performance problems in some cases.
501 if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
502 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
503 } else {
504 break;
505 }
506
507 } while (true);
508
509 if (NULL == resource) {
510 desc.fFlags = inDesc.fFlags;
511 desc.fWidth = origWidth;
512 desc.fHeight = origHeight;
513 resource = create_scratch_texture(fGpu, fResourceCache, desc);
514 }
515
516 return static_cast<GrTexture*>(resource);
517 }
518
addExistingTextureToCache(GrTexture * texture)519 void GrContext::addExistingTextureToCache(GrTexture* texture) {
520
521 if (NULL == texture) {
522 return;
523 }
524
525 // This texture should already have a cache entry since it was once
526 // attached
527 SkASSERT(texture->getCacheEntry());
528
529 // Conceptually, the cache entry is going to assume responsibility
530 // for the creation ref. Assert refcnt == 1.
531 // Except that this also gets called when the texture is prematurely
532 // abandoned. In that case the ref count may be > 1.
533 // SkASSERT(texture->unique());
534
535 if (fGpu->caps()->reuseScratchTextures() || texture->asRenderTarget()) {
536 // Since this texture came from an AutoScratchTexture it should
537 // still be in the exclusive pile. Recycle it.
538 fResourceCache->makeNonExclusive(texture->getCacheEntry());
539 this->purgeCache();
540 } else {
541 // When we aren't reusing textures we know this scratch texture
542 // will never be reused and would be just wasting time in the cache
543 fResourceCache->makeNonExclusive(texture->getCacheEntry());
544 fResourceCache->deleteResource(texture->getCacheEntry());
545 }
546 }
547
unlockScratchTexture(GrTexture * texture)548 void GrContext::unlockScratchTexture(GrTexture* texture) {
549 if (texture->wasDestroyed()) {
550 if (texture->getCacheEntry()->key().isScratch()) {
551 // This texture was detached from the cache but the cache still had a ref to it but
552 // not a pointer to it. This will unref the texture and delete its resource cache
553 // entry.
554 delete texture->getCacheEntry();
555 }
556 return;
557 }
558
559 ASSERT_OWNED_RESOURCE(texture);
560 SkASSERT(texture->getCacheEntry());
561
562 // If this is a scratch texture we detached it from the cache
563 // while it was locked (to avoid two callers simultaneously getting
564 // the same texture).
565 if (texture->getCacheEntry()->key().isScratch()) {
566 if (fGpu->caps()->reuseScratchTextures() || texture->asRenderTarget()) {
567 fResourceCache->makeNonExclusive(texture->getCacheEntry());
568 this->purgeCache();
569 } else if (texture->unique()) {
570 // Only the cache now knows about this texture. Since we're never
571 // reusing scratch textures (in this code path) it would just be
572 // wasting time sitting in the cache.
573 fResourceCache->makeNonExclusive(texture->getCacheEntry());
574 fResourceCache->deleteResource(texture->getCacheEntry());
575 } else {
576 // In this case (there is still a non-cache ref) but we don't really
577 // want to readd it to the cache (since it will never be reused).
578 // Instead, give up the cache's ref and leave the decision up to
579 // addExistingTextureToCache once its ref count reaches 0. For
580 // this to work we need to leave it in the exclusive list.
581 texture->impl()->setFlag((GrTextureFlags) GrTextureImpl::kReturnToCache_FlagBit);
582 // Give up the cache's ref to the texture
583 texture->unref();
584 }
585 }
586 }
587
purgeCache()588 void GrContext::purgeCache() {
589 if (fResourceCache) {
590 fResourceCache->purgeAsNeeded();
591 }
592 }
593
OverbudgetCB(void * data)594 bool GrContext::OverbudgetCB(void* data) {
595 SkASSERT(data);
596
597 GrContext* context = reinterpret_cast<GrContext*>(data);
598
599 // Flush the InOrderDrawBuffer to possibly free up some textures
600 context->fFlushToReduceCacheSize = true;
601
602 return true;
603 }
604
605
createUncachedTexture(const GrTextureDesc & descIn,void * srcData,size_t rowBytes)606 GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& descIn,
607 void* srcData,
608 size_t rowBytes) {
609 GrTextureDesc descCopy = descIn;
610 return fGpu->createTexture(descCopy, srcData, rowBytes);
611 }
612
getResourceCacheLimits(int * maxTextures,size_t * maxTextureBytes) const613 void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
614 fResourceCache->getLimits(maxTextures, maxTextureBytes);
615 }
616
setResourceCacheLimits(int maxTextures,size_t maxTextureBytes)617 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
618 fResourceCache->setLimits(maxTextures, maxTextureBytes);
619 }
620
getMaxTextureSize() const621 int GrContext::getMaxTextureSize() const {
622 return SkTMin(fGpu->caps()->maxTextureSize(), fMaxTextureSizeOverride);
623 }
624
getMaxRenderTargetSize() const625 int GrContext::getMaxRenderTargetSize() const {
626 return fGpu->caps()->maxRenderTargetSize();
627 }
628
getMaxSampleCount() const629 int GrContext::getMaxSampleCount() const {
630 return fGpu->caps()->maxSampleCount();
631 }
632
633 ///////////////////////////////////////////////////////////////////////////////
634
wrapBackendTexture(const GrBackendTextureDesc & desc)635 GrTexture* GrContext::wrapBackendTexture(const GrBackendTextureDesc& desc) {
636 return fGpu->wrapBackendTexture(desc);
637 }
638
wrapBackendRenderTarget(const GrBackendRenderTargetDesc & desc)639 GrRenderTarget* GrContext::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
640 return fGpu->wrapBackendRenderTarget(desc);
641 }
642
643 ///////////////////////////////////////////////////////////////////////////////
644
supportsIndex8PixelConfig(const GrTextureParams * params,int width,int height) const645 bool GrContext::supportsIndex8PixelConfig(const GrTextureParams* params,
646 int width, int height) const {
647 const GrDrawTargetCaps* caps = fGpu->caps();
648 if (!caps->isConfigTexturable(kIndex_8_GrPixelConfig)) {
649 return false;
650 }
651
652 bool isPow2 = SkIsPow2(width) && SkIsPow2(height);
653
654 if (!isPow2) {
655 bool tiled = params && params->isTiled();
656 if (tiled && !caps->npotTextureTileSupport()) {
657 return false;
658 }
659 }
660 return true;
661 }
662
663
664 ////////////////////////////////////////////////////////////////////////////////
665
clear(const SkIRect * rect,const GrColor color,bool canIgnoreRect,GrRenderTarget * renderTarget)666 void GrContext::clear(const SkIRect* rect,
667 const GrColor color,
668 bool canIgnoreRect,
669 GrRenderTarget* renderTarget) {
670 ASSERT_OWNED_RESOURCE(renderTarget);
671 AutoRestoreEffects are;
672 AutoCheckFlush acf(this);
673 GR_CREATE_TRACE_MARKER_CONTEXT("GrContext::clear", this);
674 GrDrawTarget* target = this->prepareToDraw(NULL, BUFFERED_DRAW, &are, &acf);
675 if (NULL == target) {
676 return;
677 }
678 target->clear(rect, color, canIgnoreRect, renderTarget);
679 }
680
drawPaint(const GrPaint & origPaint)681 void GrContext::drawPaint(const GrPaint& origPaint) {
682 // set rect to be big enough to fill the space, but not super-huge, so we
683 // don't overflow fixed-point implementations
684 SkRect r;
685 r.setLTRB(0, 0,
686 SkIntToScalar(getRenderTarget()->width()),
687 SkIntToScalar(getRenderTarget()->height()));
688 SkMatrix inverse;
689 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
690 AutoMatrix am;
691 GR_CREATE_TRACE_MARKER_CONTEXT("GrContext::drawPaint", this);
692
693 // We attempt to map r by the inverse matrix and draw that. mapRect will
694 // map the four corners and bound them with a new rect. This will not
695 // produce a correct result for some perspective matrices.
696 if (!this->getMatrix().hasPerspective()) {
697 if (!fViewMatrix.invert(&inverse)) {
698 GrPrintf("Could not invert matrix\n");
699 return;
700 }
701 inverse.mapRect(&r);
702 } else {
703 if (!am.setIdentity(this, paint.writable())) {
704 GrPrintf("Could not invert matrix\n");
705 return;
706 }
707 }
708 // by definition this fills the entire clip, no need for AA
709 if (paint->isAntiAlias()) {
710 paint.writable()->setAntiAlias(false);
711 }
712 this->drawRect(*paint, r);
713 }
714
715 #ifdef SK_DEVELOPER
dumpFontCache() const716 void GrContext::dumpFontCache() const {
717 fFontCache->dump();
718 }
719 #endif
720
721 ////////////////////////////////////////////////////////////////////////////////
722
723 /* create a triangle strip that strokes the specified triangle. There are 8
724 unique vertices, but we repreat the last 2 to close up. Alternatively we
725 could use an indices array, and then only send 8 verts, but not sure that
726 would be faster.
727 */
setStrokeRectStrip(SkPoint verts[10],SkRect rect,SkScalar width)728 static void setStrokeRectStrip(SkPoint verts[10], SkRect rect,
729 SkScalar width) {
730 const SkScalar rad = SkScalarHalf(width);
731 rect.sort();
732
733 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
734 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
735 verts[2].set(rect.fRight - rad, rect.fTop + rad);
736 verts[3].set(rect.fRight + rad, rect.fTop - rad);
737 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
738 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
739 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
740 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
741 verts[8] = verts[0];
742 verts[9] = verts[1];
743 }
744
is_irect(const SkRect & r)745 static inline bool is_irect(const SkRect& r) {
746 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) &&
747 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
748 }
749
apply_aa_to_rect(GrDrawTarget * target,const SkRect & rect,SkScalar strokeWidth,const SkMatrix & combinedMatrix,SkRect * devBoundRect)750 static bool apply_aa_to_rect(GrDrawTarget* target,
751 const SkRect& rect,
752 SkScalar strokeWidth,
753 const SkMatrix& combinedMatrix,
754 SkRect* devBoundRect) {
755 if (!target->getDrawState().canTweakAlphaForCoverage() &&
756 target->shouldDisableCoverageAAForBlend()) {
757 #ifdef SK_DEBUG
758 //GrPrintf("Turning off AA to correctly apply blend.\n");
759 #endif
760 return false;
761 }
762 const GrDrawState& drawState = target->getDrawState();
763 if (drawState.getRenderTarget()->isMultisampled()) {
764 return false;
765 }
766
767 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
768 if (strokeWidth >= 0) {
769 #endif
770 if (!combinedMatrix.preservesAxisAlignment()) {
771 return false;
772 }
773
774 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
775 } else {
776 if (!combinedMatrix.preservesRightAngles()) {
777 return false;
778 }
779 }
780 #endif
781
782 combinedMatrix.mapRect(devBoundRect, rect);
783 if (strokeWidth < 0) {
784 return !is_irect(*devBoundRect);
785 }
786
787 return true;
788 }
789
rect_contains_inclusive(const SkRect & rect,const SkPoint & point)790 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
791 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
792 point.fY >= rect.fTop && point.fY <= rect.fBottom;
793 }
794
drawRect(const GrPaint & paint,const SkRect & rect,const GrStrokeInfo * strokeInfo)795 void GrContext::drawRect(const GrPaint& paint,
796 const SkRect& rect,
797 const GrStrokeInfo* strokeInfo) {
798 if (strokeInfo && strokeInfo->isDashed()) {
799 SkPath path;
800 path.addRect(rect);
801 this->drawPath(paint, path, *strokeInfo);
802 return;
803 }
804
805 AutoRestoreEffects are;
806 AutoCheckFlush acf(this);
807 GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
808 if (NULL == target) {
809 return;
810 }
811
812 GR_CREATE_TRACE_MARKER("GrContext::drawRect", target);
813 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getStrokeRec().getWidth();
814 SkMatrix matrix = target->drawState()->getViewMatrix();
815
816 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
817 // cases where the RT is fully inside a stroke.
818 if (width < 0) {
819 SkRect rtRect;
820 target->getDrawState().getRenderTarget()->getBoundsRect(&rtRect);
821 SkRect clipSpaceRTRect = rtRect;
822 bool checkClip = false;
823 if (this->getClip()) {
824 checkClip = true;
825 clipSpaceRTRect.offset(SkIntToScalar(this->getClip()->fOrigin.fX),
826 SkIntToScalar(this->getClip()->fOrigin.fY));
827 }
828 // Does the clip contain the entire RT?
829 if (!checkClip || target->getClip()->fClipStack->quickContains(clipSpaceRTRect)) {
830 SkMatrix invM;
831 if (!matrix.invert(&invM)) {
832 return;
833 }
834 // Does the rect bound the RT?
835 SkPoint srcSpaceRTQuad[4];
836 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
837 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
838 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
839 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
840 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
841 // Will it blend?
842 GrColor clearColor;
843 if (paint.isOpaqueAndConstantColor(&clearColor)) {
844 target->clear(NULL, clearColor, true);
845 return;
846 }
847 }
848 }
849 }
850
851 SkRect devBoundRect;
852 bool needAA = paint.isAntiAlias() &&
853 !target->getDrawState().getRenderTarget()->isMultisampled();
854 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix, &devBoundRect);
855
856 const SkStrokeRec& strokeRec = strokeInfo->getStrokeRec();
857
858 if (doAA) {
859 GrDrawState::AutoViewMatrixRestore avmr;
860 if (!avmr.setIdentity(target->drawState())) {
861 return;
862 }
863 if (width >= 0) {
864 fAARectRenderer->strokeAARect(this->getGpu(), target, rect,
865 matrix, devBoundRect,
866 strokeRec);
867 } else {
868 // filled AA rect
869 fAARectRenderer->fillAARect(this->getGpu(), target,
870 rect, matrix, devBoundRect);
871 }
872 return;
873 }
874
875 if (width >= 0) {
876 // TODO: consider making static vertex buffers for these cases.
877 // Hairline could be done by just adding closing vertex to
878 // unitSquareVertexBuffer()
879
880 static const int worstCaseVertCount = 10;
881 target->drawState()->setDefaultVertexAttribs();
882 GrDrawTarget::AutoReleaseGeometry geo(target, worstCaseVertCount, 0);
883
884 if (!geo.succeeded()) {
885 GrPrintf("Failed to get space for vertices!\n");
886 return;
887 }
888
889 GrPrimitiveType primType;
890 int vertCount;
891 SkPoint* vertex = geo.positions();
892
893 if (width > 0) {
894 vertCount = 10;
895 primType = kTriangleStrip_GrPrimitiveType;
896 setStrokeRectStrip(vertex, rect, width);
897 } else {
898 // hairline
899 vertCount = 5;
900 primType = kLineStrip_GrPrimitiveType;
901 vertex[0].set(rect.fLeft, rect.fTop);
902 vertex[1].set(rect.fRight, rect.fTop);
903 vertex[2].set(rect.fRight, rect.fBottom);
904 vertex[3].set(rect.fLeft, rect.fBottom);
905 vertex[4].set(rect.fLeft, rect.fTop);
906 }
907
908 target->drawNonIndexed(primType, 0, vertCount);
909 } else {
910 // filled BW rect
911 target->drawSimpleRect(rect);
912 }
913 }
914
drawRectToRect(const GrPaint & paint,const SkRect & dstRect,const SkRect & localRect,const SkMatrix * localMatrix)915 void GrContext::drawRectToRect(const GrPaint& paint,
916 const SkRect& dstRect,
917 const SkRect& localRect,
918 const SkMatrix* localMatrix) {
919 AutoRestoreEffects are;
920 AutoCheckFlush acf(this);
921 GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
922 if (NULL == target) {
923 return;
924 }
925
926 GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target);
927
928 target->drawRect(dstRect, &localRect, localMatrix);
929 }
930
931 namespace {
932
933 extern const GrVertexAttrib gPosUVColorAttribs[] = {
934 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
935 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kLocalCoord_GrVertexAttribBinding },
936 {kVec4ub_GrVertexAttribType, 2*sizeof(SkPoint), kColor_GrVertexAttribBinding}
937 };
938
939 static const size_t kPosUVAttribsSize = 2 * sizeof(SkPoint);
940 static const size_t kPosUVColorAttribsSize = 2 * sizeof(SkPoint) + sizeof(GrColor);
941
942 extern const GrVertexAttrib gPosColorAttribs[] = {
943 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
944 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
945 };
946
947 static const size_t kPosAttribsSize = sizeof(SkPoint);
948 static const size_t kPosColorAttribsSize = sizeof(SkPoint) + sizeof(GrColor);
949
set_vertex_attributes(GrDrawState * drawState,const SkPoint * texCoords,const GrColor * colors,int * colorOffset,int * texOffset)950 static void set_vertex_attributes(GrDrawState* drawState,
951 const SkPoint* texCoords,
952 const GrColor* colors,
953 int* colorOffset,
954 int* texOffset) {
955 *texOffset = -1;
956 *colorOffset = -1;
957
958 if (texCoords && colors) {
959 *texOffset = sizeof(SkPoint);
960 *colorOffset = 2*sizeof(SkPoint);
961 drawState->setVertexAttribs<gPosUVColorAttribs>(3, kPosUVColorAttribsSize);
962 } else if (texCoords) {
963 *texOffset = sizeof(SkPoint);
964 drawState->setVertexAttribs<gPosUVColorAttribs>(2, kPosUVAttribsSize);
965 } else if (colors) {
966 *colorOffset = sizeof(SkPoint);
967 drawState->setVertexAttribs<gPosColorAttribs>(2, kPosColorAttribsSize);
968 } else {
969 drawState->setVertexAttribs<gPosColorAttribs>(1, kPosAttribsSize);
970 }
971 }
972
973 };
974
drawVertices(const GrPaint & paint,GrPrimitiveType primitiveType,int vertexCount,const SkPoint positions[],const SkPoint texCoords[],const GrColor colors[],const uint16_t indices[],int indexCount)975 void GrContext::drawVertices(const GrPaint& paint,
976 GrPrimitiveType primitiveType,
977 int vertexCount,
978 const SkPoint positions[],
979 const SkPoint texCoords[],
980 const GrColor colors[],
981 const uint16_t indices[],
982 int indexCount) {
983 AutoRestoreEffects are;
984 AutoCheckFlush acf(this);
985 GrDrawTarget::AutoReleaseGeometry geo; // must be inside AutoCheckFlush scope
986
987 GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
988 if (NULL == target) {
989 return;
990 }
991 GrDrawState* drawState = target->drawState();
992
993 GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target);
994
995 int colorOffset = -1, texOffset = -1;
996 set_vertex_attributes(drawState, texCoords, colors, &colorOffset, &texOffset);
997
998 size_t VertexStride = drawState->getVertexStride();
999 if (sizeof(SkPoint) != VertexStride) {
1000 if (!geo.set(target, vertexCount, 0)) {
1001 GrPrintf("Failed to get space for vertices!\n");
1002 return;
1003 }
1004 void* curVertex = geo.vertices();
1005
1006 for (int i = 0; i < vertexCount; ++i) {
1007 *((SkPoint*)curVertex) = positions[i];
1008
1009 if (texOffset >= 0) {
1010 *(SkPoint*)((intptr_t)curVertex + texOffset) = texCoords[i];
1011 }
1012 if (colorOffset >= 0) {
1013 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1014 }
1015 curVertex = (void*)((intptr_t)curVertex + VertexStride);
1016 }
1017 } else {
1018 target->setVertexSourceToArray(positions, vertexCount);
1019 }
1020
1021 // we don't currently apply offscreen AA to this path. Need improved
1022 // management of GrDrawTarget's geometry to avoid copying points per-tile.
1023
1024 if (indices) {
1025 target->setIndexSourceToArray(indices, indexCount);
1026 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
1027 target->resetIndexSource();
1028 } else {
1029 target->drawNonIndexed(primitiveType, 0, vertexCount);
1030 }
1031 }
1032
1033 ///////////////////////////////////////////////////////////////////////////////
1034
drawRRect(const GrPaint & paint,const SkRRect & rrect,const GrStrokeInfo & strokeInfo)1035 void GrContext::drawRRect(const GrPaint& paint,
1036 const SkRRect& rrect,
1037 const GrStrokeInfo& strokeInfo) {
1038 if (rrect.isEmpty()) {
1039 return;
1040 }
1041
1042 if (strokeInfo.isDashed()) {
1043 SkPath path;
1044 path.addRRect(rrect);
1045 this->drawPath(paint, path, strokeInfo);
1046 return;
1047 }
1048
1049 AutoRestoreEffects are;
1050 AutoCheckFlush acf(this);
1051 GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
1052 if (NULL == target) {
1053 return;
1054 }
1055
1056 GR_CREATE_TRACE_MARKER("GrContext::drawRRect", target);
1057
1058 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1059
1060 if (!fOvalRenderer->drawRRect(target, this, paint.isAntiAlias(), rrect, strokeRec)) {
1061 SkPath path;
1062 path.addRRect(rrect);
1063 this->internalDrawPath(target, paint.isAntiAlias(), path, strokeInfo);
1064 }
1065 }
1066
1067 ///////////////////////////////////////////////////////////////////////////////
1068
drawDRRect(const GrPaint & paint,const SkRRect & outer,const SkRRect & inner)1069 void GrContext::drawDRRect(const GrPaint& paint,
1070 const SkRRect& outer,
1071 const SkRRect& inner) {
1072 if (outer.isEmpty()) {
1073 return;
1074 }
1075
1076 AutoRestoreEffects are;
1077 AutoCheckFlush acf(this);
1078 GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
1079
1080 GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target);
1081
1082 if (!fOvalRenderer->drawDRRect(target, this, paint.isAntiAlias(), outer, inner)) {
1083 SkPath path;
1084 path.addRRect(inner);
1085 path.addRRect(outer);
1086 path.setFillType(SkPath::kEvenOdd_FillType);
1087
1088 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
1089 this->internalDrawPath(target, paint.isAntiAlias(), path, fillRec);
1090 }
1091 }
1092
1093 ///////////////////////////////////////////////////////////////////////////////
1094
drawOval(const GrPaint & paint,const SkRect & oval,const GrStrokeInfo & strokeInfo)1095 void GrContext::drawOval(const GrPaint& paint,
1096 const SkRect& oval,
1097 const GrStrokeInfo& strokeInfo) {
1098 if (oval.isEmpty()) {
1099 return;
1100 }
1101
1102 if (strokeInfo.isDashed()) {
1103 SkPath path;
1104 path.addOval(oval);
1105 this->drawPath(paint, path, strokeInfo);
1106 return;
1107 }
1108
1109 AutoRestoreEffects are;
1110 AutoCheckFlush acf(this);
1111 GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
1112 if (NULL == target) {
1113 return;
1114 }
1115
1116 GR_CREATE_TRACE_MARKER("GrContext::drawOval", target);
1117
1118 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1119
1120
1121 if (!fOvalRenderer->drawOval(target, this, paint.isAntiAlias(), oval, strokeRec)) {
1122 SkPath path;
1123 path.addOval(oval);
1124 this->internalDrawPath(target, paint.isAntiAlias(), path, strokeInfo);
1125 }
1126 }
1127
1128 // Can 'path' be drawn as a pair of filled nested rectangles?
is_nested_rects(GrDrawTarget * target,const SkPath & path,const SkStrokeRec & stroke,SkRect rects[2])1129 static bool is_nested_rects(GrDrawTarget* target,
1130 const SkPath& path,
1131 const SkStrokeRec& stroke,
1132 SkRect rects[2]) {
1133 SkASSERT(stroke.isFillStyle());
1134
1135 if (path.isInverseFillType()) {
1136 return false;
1137 }
1138
1139 const GrDrawState& drawState = target->getDrawState();
1140
1141 // TODO: this restriction could be lifted if we were willing to apply
1142 // the matrix to all the points individually rather than just to the rect
1143 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
1144 return false;
1145 }
1146
1147 if (!target->getDrawState().canTweakAlphaForCoverage() &&
1148 target->shouldDisableCoverageAAForBlend()) {
1149 return false;
1150 }
1151
1152 SkPath::Direction dirs[2];
1153 if (!path.isNestedRects(rects, dirs)) {
1154 return false;
1155 }
1156
1157 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
1158 // The two rects need to be wound opposite to each other
1159 return false;
1160 }
1161
1162 // Right now, nested rects where the margin is not the same width
1163 // all around do not render correctly
1164 const SkScalar* outer = rects[0].asScalars();
1165 const SkScalar* inner = rects[1].asScalars();
1166
1167 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
1168 for (int i = 1; i < 4; ++i) {
1169 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
1170 if (!SkScalarNearlyEqual(margin, temp)) {
1171 return false;
1172 }
1173 }
1174
1175 return true;
1176 }
1177
drawPath(const GrPaint & paint,const SkPath & path,const GrStrokeInfo & strokeInfo)1178 void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const GrStrokeInfo& strokeInfo) {
1179
1180 if (path.isEmpty()) {
1181 if (path.isInverseFillType()) {
1182 this->drawPaint(paint);
1183 }
1184 return;
1185 }
1186
1187 if (strokeInfo.isDashed()) {
1188 SkPoint pts[2];
1189 if (path.isLine(pts)) {
1190 AutoRestoreEffects are;
1191 AutoCheckFlush acf(this);
1192 GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
1193 if (NULL == target) {
1194 return;
1195 }
1196 GrDrawState* drawState = target->drawState();
1197
1198 SkMatrix origViewMatrix = drawState->getViewMatrix();
1199 GrDrawState::AutoViewMatrixRestore avmr;
1200 if (avmr.setIdentity(target->drawState())) {
1201 if (GrDashingEffect::DrawDashLine(pts, paint, strokeInfo, fGpu, target,
1202 origViewMatrix)) {
1203 return;
1204 }
1205 }
1206 }
1207
1208 // Filter dashed path into new path with the dashing applied
1209 const SkPathEffect::DashInfo& info = strokeInfo.getDashInfo();
1210 SkTLazy<SkPath> effectPath;
1211 GrStrokeInfo newStrokeInfo(strokeInfo, false);
1212 SkStrokeRec* stroke = newStrokeInfo.getStrokeRecPtr();
1213 if (SkDashPath::FilterDashPath(effectPath.init(), path, stroke, NULL, info)) {
1214 this->drawPath(paint, *effectPath.get(), newStrokeInfo);
1215 return;
1216 }
1217
1218 this->drawPath(paint, path, newStrokeInfo);
1219 return;
1220 }
1221
1222 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
1223 // Scratch textures can be recycled after they are returned to the texture
1224 // cache. This presents a potential hazard for buffered drawing. However,
1225 // the writePixels that uploads to the scratch will perform a flush so we're
1226 // OK.
1227 AutoRestoreEffects are;
1228 AutoCheckFlush acf(this);
1229 GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
1230 if (NULL == target) {
1231 return;
1232 }
1233 GrDrawState* drawState = target->drawState();
1234
1235 GR_CREATE_TRACE_MARKER1("GrContext::drawPath", target, "Is Convex", path.isConvex());
1236
1237 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1238
1239 bool useCoverageAA = paint.isAntiAlias() && !drawState->getRenderTarget()->isMultisampled();
1240
1241 if (useCoverageAA && strokeRec.getWidth() < 0 && !path.isConvex()) {
1242 // Concave AA paths are expensive - try to avoid them for special cases
1243 SkRect rects[2];
1244
1245 if (is_nested_rects(target, path, strokeRec, rects)) {
1246 SkMatrix origViewMatrix = drawState->getViewMatrix();
1247 GrDrawState::AutoViewMatrixRestore avmr;
1248 if (!avmr.setIdentity(target->drawState())) {
1249 return;
1250 }
1251
1252 fAARectRenderer->fillAANestedRects(this->getGpu(), target, rects, origViewMatrix);
1253 return;
1254 }
1255 }
1256
1257 SkRect ovalRect;
1258 bool isOval = path.isOval(&ovalRect);
1259
1260 if (!isOval || path.isInverseFillType()
1261 || !fOvalRenderer->drawOval(target, this, paint.isAntiAlias(), ovalRect, strokeRec)) {
1262 this->internalDrawPath(target, paint.isAntiAlias(), path, strokeInfo);
1263 }
1264 }
1265
internalDrawPath(GrDrawTarget * target,bool useAA,const SkPath & path,const GrStrokeInfo & strokeInfo)1266 void GrContext::internalDrawPath(GrDrawTarget* target, bool useAA, const SkPath& path,
1267 const GrStrokeInfo& strokeInfo) {
1268 SkASSERT(!path.isEmpty());
1269
1270 GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target);
1271
1272
1273 // An Assumption here is that path renderer would use some form of tweaking
1274 // the src color (either the input alpha or in the frag shader) to implement
1275 // aa. If we have some future driver-mojo path AA that can do the right
1276 // thing WRT to the blend then we'll need some query on the PR.
1277 bool useCoverageAA = useAA &&
1278 !target->getDrawState().getRenderTarget()->isMultisampled() &&
1279 !target->shouldDisableCoverageAAForBlend();
1280
1281
1282 GrPathRendererChain::DrawType type =
1283 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
1284 GrPathRendererChain::kColor_DrawType;
1285
1286 const SkPath* pathPtr = &path;
1287 SkTLazy<SkPath> tmpPath;
1288 SkTCopyOnFirstWrite<SkStrokeRec> stroke(strokeInfo.getStrokeRec());
1289
1290 // Try a 1st time without stroking the path and without allowing the SW renderer
1291 GrPathRenderer* pr = this->getPathRenderer(*pathPtr, *stroke, target, false, type);
1292
1293 if (NULL == pr) {
1294 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*stroke, this->getMatrix(), NULL)) {
1295 // It didn't work the 1st time, so try again with the stroked path
1296 if (stroke->applyToPath(tmpPath.init(), *pathPtr)) {
1297 pathPtr = tmpPath.get();
1298 stroke.writable()->setFillStyle();
1299 if (pathPtr->isEmpty()) {
1300 return;
1301 }
1302 }
1303 }
1304
1305 // This time, allow SW renderer
1306 pr = this->getPathRenderer(*pathPtr, *stroke, target, true, type);
1307 }
1308
1309 if (NULL == pr) {
1310 #ifdef SK_DEBUG
1311 GrPrintf("Unable to find path renderer compatible with path.\n");
1312 #endif
1313 return;
1314 }
1315
1316 pr->drawPath(*pathPtr, *stroke, target, useCoverageAA);
1317 }
1318
1319 ////////////////////////////////////////////////////////////////////////////////
1320
flush(int flagsBitfield)1321 void GrContext::flush(int flagsBitfield) {
1322 if (NULL == fDrawBuffer) {
1323 return;
1324 }
1325
1326 if (kDiscard_FlushBit & flagsBitfield) {
1327 fDrawBuffer->reset();
1328 } else {
1329 fDrawBuffer->flush();
1330 }
1331 fFlushToReduceCacheSize = false;
1332 }
1333
writeTexturePixels(GrTexture * texture,int left,int top,int width,int height,GrPixelConfig config,const void * buffer,size_t rowBytes,uint32_t flags)1334 bool GrContext::writeTexturePixels(GrTexture* texture,
1335 int left, int top, int width, int height,
1336 GrPixelConfig config, const void* buffer, size_t rowBytes,
1337 uint32_t flags) {
1338 ASSERT_OWNED_RESOURCE(texture);
1339
1340 if ((kUnpremul_PixelOpsFlag & flags) || !fGpu->canWriteTexturePixels(texture, config)) {
1341 if (texture->asRenderTarget()) {
1342 return this->writeRenderTargetPixels(texture->asRenderTarget(),
1343 left, top, width, height,
1344 config, buffer, rowBytes, flags);
1345 } else {
1346 return false;
1347 }
1348 }
1349
1350 if (!(kDontFlush_PixelOpsFlag & flags) && texture->hasPendingIO()) {
1351 this->flush();
1352 }
1353
1354 return fGpu->writeTexturePixels(texture, left, top, width, height,
1355 config, buffer, rowBytes);
1356 }
1357
readTexturePixels(GrTexture * texture,int left,int top,int width,int height,GrPixelConfig config,void * buffer,size_t rowBytes,uint32_t flags)1358 bool GrContext::readTexturePixels(GrTexture* texture,
1359 int left, int top, int width, int height,
1360 GrPixelConfig config, void* buffer, size_t rowBytes,
1361 uint32_t flags) {
1362 ASSERT_OWNED_RESOURCE(texture);
1363
1364 GrRenderTarget* target = texture->asRenderTarget();
1365 if (target) {
1366 return this->readRenderTargetPixels(target,
1367 left, top, width, height,
1368 config, buffer, rowBytes,
1369 flags);
1370 } else {
1371 // TODO: make this more efficient for cases where we're reading the entire
1372 // texture, i.e., use GetTexImage() instead
1373
1374 // create scratch rendertarget and read from that
1375 GrAutoScratchTexture ast;
1376 GrTextureDesc desc;
1377 desc.fFlags = kRenderTarget_GrTextureFlagBit;
1378 desc.fWidth = width;
1379 desc.fHeight = height;
1380 desc.fConfig = config;
1381 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1382 ast.set(this, desc, kExact_ScratchTexMatch);
1383 GrTexture* dst = ast.texture();
1384 if (dst && (target = dst->asRenderTarget())) {
1385 this->copyTexture(texture, target, NULL);
1386 return this->readRenderTargetPixels(target,
1387 left, top, width, height,
1388 config, buffer, rowBytes,
1389 flags);
1390 }
1391
1392 return false;
1393 }
1394 }
1395
1396 #include "SkConfig8888.h"
1397
1398 // toggles between RGBA and BGRA
toggle_colortype32(SkColorType ct)1399 static SkColorType toggle_colortype32(SkColorType ct) {
1400 if (kRGBA_8888_SkColorType == ct) {
1401 return kBGRA_8888_SkColorType;
1402 } else {
1403 SkASSERT(kBGRA_8888_SkColorType == ct);
1404 return kRGBA_8888_SkColorType;
1405 }
1406 }
1407
readRenderTargetPixels(GrRenderTarget * target,int left,int top,int width,int height,GrPixelConfig dstConfig,void * buffer,size_t rowBytes,uint32_t flags)1408 bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1409 int left, int top, int width, int height,
1410 GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
1411 uint32_t flags) {
1412 ASSERT_OWNED_RESOURCE(target);
1413
1414 if (NULL == target) {
1415 target = fRenderTarget.get();
1416 if (NULL == target) {
1417 return false;
1418 }
1419 }
1420
1421 if (!(kDontFlush_PixelOpsFlag & flags) && target->hasPendingWrite()) {
1422 this->flush();
1423 }
1424
1425 // Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul.
1426
1427 // If fGpu->readPixels would incur a y-flip cost then we will read the pixels upside down. We'll
1428 // either do the flipY by drawing into a scratch with a matrix or on the cpu after the read.
1429 bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top,
1430 width, height, dstConfig,
1431 rowBytes);
1432 // We ignore the preferred config if it is different than our config unless it is an R/B swap.
1433 // In that case we'll perform an R and B swap while drawing to a scratch texture of the swapped
1434 // config. Then we will call readPixels on the scratch with the swapped config. The swaps during
1435 // the draw cancels out the fact that we call readPixels with a config that is R/B swapped from
1436 // dstConfig.
1437 GrPixelConfig readConfig = dstConfig;
1438 bool swapRAndB = false;
1439 if (GrPixelConfigSwapRAndB(dstConfig) ==
1440 fGpu->preferredReadPixelsConfig(dstConfig, target->config())) {
1441 readConfig = GrPixelConfigSwapRAndB(readConfig);
1442 swapRAndB = true;
1443 }
1444
1445 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
1446
1447 if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
1448 // The unpremul flag is only allowed for these two configs.
1449 return false;
1450 }
1451
1452 // If the src is a texture and we would have to do conversions after read pixels, we instead
1453 // do the conversions by drawing the src to a scratch texture. If we handle any of the
1454 // conversions in the draw we set the corresponding bool to false so that we don't reapply it
1455 // on the read back pixels.
1456 GrTexture* src = target->asTexture();
1457 GrAutoScratchTexture ast;
1458 if (src && (swapRAndB || unpremul || flipY)) {
1459 // Make the scratch a render target because we don't have a robust readTexturePixels as of
1460 // yet. It calls this function.
1461 GrTextureDesc desc;
1462 desc.fFlags = kRenderTarget_GrTextureFlagBit;
1463 desc.fWidth = width;
1464 desc.fHeight = height;
1465 desc.fConfig = readConfig;
1466 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1467
1468 // When a full read back is faster than a partial we could always make the scratch exactly
1469 // match the passed rect. However, if we see many different size rectangles we will trash
1470 // our texture cache and pay the cost of creating and destroying many textures. So, we only
1471 // request an exact match when the caller is reading an entire RT.
1472 ScratchTexMatch match = kApprox_ScratchTexMatch;
1473 if (0 == left &&
1474 0 == top &&
1475 target->width() == width &&
1476 target->height() == height &&
1477 fGpu->fullReadPixelsIsFasterThanPartial()) {
1478 match = kExact_ScratchTexMatch;
1479 }
1480 ast.set(this, desc, match);
1481 GrTexture* texture = ast.texture();
1482 if (texture) {
1483 // compute a matrix to perform the draw
1484 SkMatrix textureMatrix;
1485 textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1486 textureMatrix.postIDiv(src->width(), src->height());
1487
1488 SkAutoTUnref<const GrFragmentProcessor> fp;
1489 if (unpremul) {
1490 fp.reset(this->createPMToUPMEffect(src, swapRAndB, textureMatrix));
1491 if (fp) {
1492 unpremul = false; // we no longer need to do this on CPU after the read back.
1493 }
1494 }
1495 // If we failed to create a PM->UPM effect and have no other conversions to perform then
1496 // there is no longer any point to using the scratch.
1497 if (fp || flipY || swapRAndB) {
1498 if (!fp) {
1499 fp.reset(GrConfigConversionEffect::Create(
1500 src, swapRAndB, GrConfigConversionEffect::kNone_PMConversion,
1501 textureMatrix));
1502 }
1503 swapRAndB = false; // we will handle the swap in the draw.
1504
1505 // We protect the existing geometry here since it may not be
1506 // clear to the caller that a draw operation (i.e., drawSimpleRect)
1507 // can be invoked in this method
1508 GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit);
1509 GrDrawState* drawState = fGpu->drawState();
1510 SkASSERT(fp);
1511 drawState->addColorProcessor(fp);
1512
1513 drawState->setRenderTarget(texture->asRenderTarget());
1514 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
1515 fGpu->drawSimpleRect(rect);
1516 // we want to read back from the scratch's origin
1517 left = 0;
1518 top = 0;
1519 target = texture->asRenderTarget();
1520 }
1521 }
1522 }
1523 if (!fGpu->readPixels(target,
1524 left, top, width, height,
1525 readConfig, buffer, rowBytes)) {
1526 return false;
1527 }
1528 // Perform any conversions we weren't able to perform using a scratch texture.
1529 if (unpremul || swapRAndB) {
1530 SkDstPixelInfo dstPI;
1531 if (!GrPixelConfig2ColorType(dstConfig, &dstPI.fColorType)) {
1532 return false;
1533 }
1534 dstPI.fAlphaType = kUnpremul_SkAlphaType;
1535 dstPI.fPixels = buffer;
1536 dstPI.fRowBytes = rowBytes;
1537
1538 SkSrcPixelInfo srcPI;
1539 srcPI.fColorType = swapRAndB ? toggle_colortype32(dstPI.fColorType) : dstPI.fColorType;
1540 srcPI.fAlphaType = kPremul_SkAlphaType;
1541 srcPI.fPixels = buffer;
1542 srcPI.fRowBytes = rowBytes;
1543
1544 return srcPI.convertPixelsTo(&dstPI, width, height);
1545 }
1546 return true;
1547 }
1548
resolveRenderTarget(GrRenderTarget * target)1549 void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1550 SkASSERT(target);
1551 ASSERT_OWNED_RESOURCE(target);
1552 // In the future we may track whether there are any pending draws to this
1553 // target. We don't today so we always perform a flush. We don't promise
1554 // this to our clients, though.
1555 this->flush();
1556 if (fGpu) {
1557 fGpu->resolveRenderTarget(target);
1558 }
1559 }
1560
discardRenderTarget(GrRenderTarget * renderTarget)1561 void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) {
1562 SkASSERT(renderTarget);
1563 ASSERT_OWNED_RESOURCE(renderTarget);
1564 AutoRestoreEffects are;
1565 AutoCheckFlush acf(this);
1566 GrDrawTarget* target = this->prepareToDraw(NULL, BUFFERED_DRAW, &are, &acf);
1567 if (NULL == target) {
1568 return;
1569 }
1570 target->discard(renderTarget);
1571 }
1572
copyTexture(GrTexture * src,GrRenderTarget * dst,const SkIPoint * topLeft)1573 void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst, const SkIPoint* topLeft) {
1574 if (NULL == src || NULL == dst) {
1575 return;
1576 }
1577 ASSERT_OWNED_RESOURCE(src);
1578
1579 SkIRect srcRect = SkIRect::MakeWH(dst->width(), dst->height());
1580 if (topLeft) {
1581 srcRect.offset(*topLeft);
1582 }
1583 SkIRect srcBounds = SkIRect::MakeWH(src->width(), src->height());
1584 if (!srcRect.intersect(srcBounds)) {
1585 return;
1586 }
1587
1588 GrDrawTarget* target = this->prepareToDraw(NULL, BUFFERED_DRAW, NULL, NULL);
1589 if (NULL == target) {
1590 return;
1591 }
1592 SkIPoint dstPoint;
1593 dstPoint.setZero();
1594 target->copySurface(dst, src, srcRect, dstPoint);
1595 }
1596
writeRenderTargetPixels(GrRenderTarget * target,int left,int top,int width,int height,GrPixelConfig srcConfig,const void * buffer,size_t rowBytes,uint32_t flags)1597 bool GrContext::writeRenderTargetPixels(GrRenderTarget* target,
1598 int left, int top, int width, int height,
1599 GrPixelConfig srcConfig,
1600 const void* buffer,
1601 size_t rowBytes,
1602 uint32_t flags) {
1603 ASSERT_OWNED_RESOURCE(target);
1604
1605 if (NULL == target) {
1606 target = fRenderTarget.get();
1607 if (NULL == target) {
1608 return false;
1609 }
1610 }
1611
1612 // TODO: when underlying api has a direct way to do this we should use it (e.g. glDrawPixels on
1613 // desktop GL).
1614
1615 // We will always call some form of writeTexturePixels and we will pass our flags on to it.
1616 // Thus, we don't perform a flush here since that call will do it (if the kNoFlush flag isn't
1617 // set.)
1618
1619 // If the RT is also a texture and we don't have to premultiply then take the texture path.
1620 // We expect to be at least as fast or faster since it doesn't use an intermediate texture as
1621 // we do below.
1622
1623 #if !defined(SK_BUILD_FOR_MAC)
1624 // At least some drivers on the Mac get confused when glTexImage2D is called on a texture
1625 // attached to an FBO. The FBO still sees the old image. TODO: determine what OS versions and/or
1626 // HW is affected.
1627 if (target->asTexture() && !(kUnpremul_PixelOpsFlag & flags) &&
1628 fGpu->canWriteTexturePixels(target->asTexture(), srcConfig)) {
1629 return this->writeTexturePixels(target->asTexture(),
1630 left, top, width, height,
1631 srcConfig, buffer, rowBytes, flags);
1632 }
1633 #endif
1634
1635 // We ignore the preferred config unless it is a R/B swap of the src config. In that case
1636 // we will upload the original src data to a scratch texture but we will spoof it as the swapped
1637 // config. This scratch will then have R and B swapped. We correct for this by swapping again
1638 // when drawing the scratch to the dst using a conversion effect.
1639 bool swapRAndB = false;
1640 GrPixelConfig writeConfig = srcConfig;
1641 if (GrPixelConfigSwapRAndB(srcConfig) ==
1642 fGpu->preferredWritePixelsConfig(srcConfig, target->config())) {
1643 writeConfig = GrPixelConfigSwapRAndB(srcConfig);
1644 swapRAndB = true;
1645 }
1646
1647 GrTextureDesc desc;
1648 desc.fWidth = width;
1649 desc.fHeight = height;
1650 desc.fConfig = writeConfig;
1651 GrAutoScratchTexture ast(this, desc);
1652 GrTexture* texture = ast.texture();
1653 if (NULL == texture) {
1654 return false;
1655 }
1656
1657 SkAutoTUnref<const GrFragmentProcessor> fp;
1658 SkMatrix textureMatrix;
1659 textureMatrix.setIDiv(texture->width(), texture->height());
1660
1661 // allocate a tmp buffer and sw convert the pixels to premul
1662 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
1663
1664 if (kUnpremul_PixelOpsFlag & flags) {
1665 if (!GrPixelConfigIs8888(srcConfig)) {
1666 return false;
1667 }
1668 fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix));
1669 // handle the unpremul step on the CPU if we couldn't create an effect to do it.
1670 if (NULL == fp) {
1671 SkSrcPixelInfo srcPI;
1672 if (!GrPixelConfig2ColorType(srcConfig, &srcPI.fColorType)) {
1673 return false;
1674 }
1675 srcPI.fAlphaType = kUnpremul_SkAlphaType;
1676 srcPI.fPixels = buffer;
1677 srcPI.fRowBytes = rowBytes;
1678
1679 tmpPixels.reset(width * height);
1680
1681 SkDstPixelInfo dstPI;
1682 dstPI.fColorType = srcPI.fColorType;
1683 dstPI.fAlphaType = kPremul_SkAlphaType;
1684 dstPI.fPixels = tmpPixels.get();
1685 dstPI.fRowBytes = 4 * width;
1686
1687 if (!srcPI.convertPixelsTo(&dstPI, width, height)) {
1688 return false;
1689 }
1690
1691 buffer = tmpPixels.get();
1692 rowBytes = 4 * width;
1693 }
1694 }
1695 if (NULL == fp) {
1696 fp.reset(GrConfigConversionEffect::Create(texture,
1697 swapRAndB,
1698 GrConfigConversionEffect::kNone_PMConversion,
1699 textureMatrix));
1700 }
1701
1702 if (!this->writeTexturePixels(texture,
1703 0, 0, width, height,
1704 writeConfig, buffer, rowBytes,
1705 flags & ~kUnpremul_PixelOpsFlag)) {
1706 return false;
1707 }
1708
1709 // TODO: Usually this could go to fDrawBuffer but currently
1710 // writeRenderTargetPixels can be called in the midst of drawing another
1711 // object (e.g., when uploading a SW path rendering to the gpu while
1712 // drawing a rect). So we always draw directly to GrGpu and preserve the current geometry.
1713 // But that means we also have to flush the draw buffer if there is a pending IO operation to
1714 // the render target.
1715 if (!(kDontFlush_PixelOpsFlag & flags) && target->hasPendingIO()) {
1716 this->flush();
1717 }
1718 SkMatrix matrix;
1719 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
1720 GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit, &matrix);
1721 GrDrawState* drawState = fGpu->drawState();
1722 SkASSERT(fp);
1723 drawState->addColorProcessor(fp);
1724
1725 drawState->setRenderTarget(target);
1726
1727 fGpu->drawSimpleRect(SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)));
1728 return true;
1729 }
1730 ////////////////////////////////////////////////////////////////////////////////
1731
prepareToDraw(const GrPaint * paint,BufferedDraw buffered,AutoRestoreEffects * are,AutoCheckFlush * acf)1732 GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint,
1733 BufferedDraw buffered,
1734 AutoRestoreEffects* are,
1735 AutoCheckFlush* acf) {
1736 // All users of this draw state should be freeing up all effects when they're done.
1737 // Otherwise effects that own resources may keep those resources alive indefinitely.
1738 SkASSERT(0 == fDrawState->numColorStages() && 0 == fDrawState->numCoverageStages() &&
1739 !fDrawState->hasGeometryProcessor());
1740
1741 if (NULL == fGpu) {
1742 return NULL;
1743 }
1744
1745 if (kNo_BufferedDraw == buffered && kYes_BufferedDraw == fLastDrawWasBuffered) {
1746 fDrawBuffer->flush();
1747 fLastDrawWasBuffered = kNo_BufferedDraw;
1748 }
1749 ASSERT_OWNED_RESOURCE(fRenderTarget.get());
1750 if (paint) {
1751 SkASSERT(are);
1752 SkASSERT(acf);
1753 are->set(fDrawState);
1754 fDrawState->setFromPaint(*paint, fViewMatrix, fRenderTarget.get());
1755 #if GR_DEBUG_PARTIAL_COVERAGE_CHECK
1756 if ((paint->hasMask() || 0xff != paint->fCoverage) &&
1757 !fDrawState->couldApplyCoverage(fGpu->caps())) {
1758 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1759 }
1760 #endif
1761 // Clear any vertex attributes configured for the previous use of the
1762 // GrDrawState which can effect which blend optimizations are in effect.
1763 fDrawState->setDefaultVertexAttribs();
1764 } else {
1765 fDrawState->reset(fViewMatrix);
1766 fDrawState->setRenderTarget(fRenderTarget.get());
1767 }
1768 GrDrawTarget* target;
1769 if (kYes_BufferedDraw == buffered) {
1770 fLastDrawWasBuffered = kYes_BufferedDraw;
1771 target = fDrawBuffer;
1772 } else {
1773 SkASSERT(kNo_BufferedDraw == buffered);
1774 fLastDrawWasBuffered = kNo_BufferedDraw;
1775 target = fGpu;
1776 }
1777 fDrawState->setState(GrDrawState::kClip_StateBit, fClip &&
1778 !fClip->fClipStack->isWideOpen());
1779 target->setClip(fClip);
1780 SkASSERT(fDrawState == target->drawState());
1781 return target;
1782 }
1783
1784 /*
1785 * This method finds a path renderer that can draw the specified path on
1786 * the provided target.
1787 * Due to its expense, the software path renderer has split out so it can
1788 * can be individually allowed/disallowed via the "allowSW" boolean.
1789 */
getPathRenderer(const SkPath & path,const SkStrokeRec & stroke,const GrDrawTarget * target,bool allowSW,GrPathRendererChain::DrawType drawType,GrPathRendererChain::StencilSupport * stencilSupport)1790 GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
1791 const SkStrokeRec& stroke,
1792 const GrDrawTarget* target,
1793 bool allowSW,
1794 GrPathRendererChain::DrawType drawType,
1795 GrPathRendererChain::StencilSupport* stencilSupport) {
1796
1797 if (NULL == fPathRendererChain) {
1798 fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
1799 }
1800
1801 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(path,
1802 stroke,
1803 target,
1804 drawType,
1805 stencilSupport);
1806
1807 if (NULL == pr && allowSW) {
1808 if (NULL == fSoftwarePathRenderer) {
1809 fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
1810 }
1811 pr = fSoftwarePathRenderer;
1812 }
1813
1814 return pr;
1815 }
1816
1817 ////////////////////////////////////////////////////////////////////////////////
isConfigRenderable(GrPixelConfig config,bool withMSAA) const1818 bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const {
1819 return fGpu->caps()->isConfigRenderable(config, withMSAA);
1820 }
1821
getRecommendedSampleCount(GrPixelConfig config,SkScalar dpi) const1822 int GrContext::getRecommendedSampleCount(GrPixelConfig config,
1823 SkScalar dpi) const {
1824 if (!this->isConfigRenderable(config, true)) {
1825 return 0;
1826 }
1827 int chosenSampleCount = 0;
1828 if (fGpu->caps()->pathRenderingSupport()) {
1829 if (dpi >= 250.0f) {
1830 chosenSampleCount = 4;
1831 } else {
1832 chosenSampleCount = 16;
1833 }
1834 }
1835 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ?
1836 chosenSampleCount : 0;
1837 }
1838
setupDrawBuffer()1839 void GrContext::setupDrawBuffer() {
1840 SkASSERT(NULL == fDrawBuffer);
1841 SkASSERT(NULL == fDrawBufferVBAllocPool);
1842 SkASSERT(NULL == fDrawBufferIBAllocPool);
1843
1844 fDrawBufferVBAllocPool =
1845 SkNEW_ARGS(GrVertexBufferAllocPool, (fGpu, false,
1846 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1847 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS));
1848 fDrawBufferIBAllocPool =
1849 SkNEW_ARGS(GrIndexBufferAllocPool, (fGpu, false,
1850 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
1851 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS));
1852
1853 fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (fGpu,
1854 fDrawBufferVBAllocPool,
1855 fDrawBufferIBAllocPool));
1856
1857 fDrawBuffer->setDrawState(fDrawState);
1858 }
1859
getTextTarget()1860 GrDrawTarget* GrContext::getTextTarget() {
1861 return this->prepareToDraw(NULL, BUFFERED_DRAW, NULL, NULL);
1862 }
1863
getQuadIndexBuffer() const1864 const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1865 return fGpu->getQuadIndexBuffer();
1866 }
1867
1868 namespace {
test_pm_conversions(GrContext * ctx,int * pmToUPMValue,int * upmToPMValue)1869 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
1870 GrConfigConversionEffect::PMConversion pmToUPM;
1871 GrConfigConversionEffect::PMConversion upmToPM;
1872 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
1873 *pmToUPMValue = pmToUPM;
1874 *upmToPMValue = upmToPM;
1875 }
1876 }
1877
createPMToUPMEffect(GrTexture * texture,bool swapRAndB,const SkMatrix & matrix)1878 const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture,
1879 bool swapRAndB,
1880 const SkMatrix& matrix) {
1881 if (!fDidTestPMConversions) {
1882 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
1883 fDidTestPMConversions = true;
1884 }
1885 GrConfigConversionEffect::PMConversion pmToUPM =
1886 static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
1887 if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
1888 return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, matrix);
1889 } else {
1890 return NULL;
1891 }
1892 }
1893
createUPMToPMEffect(GrTexture * texture,bool swapRAndB,const SkMatrix & matrix)1894 const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
1895 bool swapRAndB,
1896 const SkMatrix& matrix) {
1897 if (!fDidTestPMConversions) {
1898 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
1899 fDidTestPMConversions = true;
1900 }
1901 GrConfigConversionEffect::PMConversion upmToPM =
1902 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
1903 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
1904 return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, matrix);
1905 } else {
1906 return NULL;
1907 }
1908 }
1909
addResourceToCache(const GrResourceKey & resourceKey,GrGpuResource * resource)1910 void GrContext::addResourceToCache(const GrResourceKey& resourceKey, GrGpuResource* resource) {
1911 fResourceCache->purgeAsNeeded(1, resource->gpuMemorySize());
1912 fResourceCache->addResource(resourceKey, resource);
1913 }
1914
findAndRefCachedResource(const GrResourceKey & resourceKey)1915 GrGpuResource* GrContext::findAndRefCachedResource(const GrResourceKey& resourceKey) {
1916 GrGpuResource* resource = fResourceCache->find(resourceKey);
1917 SkSafeRef(resource);
1918 return resource;
1919 }
1920
addGpuTraceMarker(const GrGpuTraceMarker * marker)1921 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
1922 fGpu->addGpuTraceMarker(marker);
1923 if (fDrawBuffer) {
1924 fDrawBuffer->addGpuTraceMarker(marker);
1925 }
1926 }
1927
removeGpuTraceMarker(const GrGpuTraceMarker * marker)1928 void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
1929 fGpu->removeGpuTraceMarker(marker);
1930 if (fDrawBuffer) {
1931 fDrawBuffer->removeGpuTraceMarker(marker);
1932 }
1933 }
1934
1935 ///////////////////////////////////////////////////////////////////////////////
1936 #if GR_CACHE_STATS
printCacheStats() const1937 void GrContext::printCacheStats() const {
1938 fResourceCache->printStats();
1939 }
1940 #endif
1941
1942 #if GR_GPU_STATS
gpuStats() const1943 const GrContext::GPUStats* GrContext::gpuStats() const {
1944 return fGpu->gpuStats();
1945 }
1946 #endif
1947
1948