gfx/skia/trunk/src/gpu/GrContext.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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  */
    10 #include "GrContext.h"
    12 #include "effects/GrSingleTextureEffect.h"
    13 #include "effects/GrConfigConversionEffect.h"
    15 #include "GrAARectRenderer.h"
    16 #include "GrBufferAllocPool.h"
    17 #include "GrGpu.h"
    18 #include "GrDrawTargetCaps.h"
    19 #include "GrIndexBuffer.h"
    20 #include "GrInOrderDrawBuffer.h"
    21 #include "GrOvalRenderer.h"
    22 #include "GrPathRenderer.h"
    23 #include "GrPathUtils.h"
    24 #include "GrResourceCache.h"
    25 #include "GrSoftwarePathRenderer.h"
    26 #include "GrStencilBuffer.h"
    27 #include "GrTextStrike.h"
    28 #include "SkRTConf.h"
    29 #include "SkRRect.h"
    30 #include "SkStrokeRec.h"
    31 #include "SkTLazy.h"
    32 #include "SkTLS.h"
    33 #include "SkTrace.h"
    35 // It can be useful to set this to false to test whether a bug is caused by using the
    36 // InOrderDrawBuffer, to compare performance of using/not using InOrderDrawBuffer, or to make
    37 // debugging simpler.
    38 SK_CONF_DECLARE(bool, c_Defer, "gpu.deferContext", true,
    39                 "Defers rendering in GrContext via GrInOrderDrawBuffer.");
    41 #define BUFFERED_DRAW (c_Defer ? kYes_BufferedDraw : kNo_BufferedDraw)
    43 #ifdef SK_DEBUG
    44     // change this to a 1 to see notifications when partial coverage fails
    45     #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
    46 #else
    47     #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
    48 #endif
    50 static const size_t MAX_RESOURCE_CACHE_COUNT = GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT;
    51 static const size_t MAX_RESOURCE_CACHE_BYTES = GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT * 1024 * 1024;
    53 static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
    54 static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
    56 static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 1 << 11;
    57 static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4;
    59 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
    61 // Glorified typedef to avoid including GrDrawState.h in GrContext.h
    62 class GrContext::AutoRestoreEffects : public GrDrawState::AutoRestoreEffects {};
    64 class GrContext::AutoCheckFlush {
    65 public:
    66     AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(NULL != context); }
    68     ~AutoCheckFlush() {
    69         if (fContext->fFlushToReduceCacheSize) {
    70             fContext->flush();
    71         }
    72     }
    74 private:
    75     GrContext* fContext;
    76 };
    78 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
    79     GrContext* context = SkNEW(GrContext);
    80     if (context->init(backend, backendContext)) {
    81         return context;
    82     } else {
    83         context->unref();
    84         return NULL;
    85     }
    86 }
    88 GrContext::GrContext() {
    89     fDrawState = NULL;
    90     fGpu = NULL;
    91     fClip = NULL;
    92     fPathRendererChain = NULL;
    93     fSoftwarePathRenderer = NULL;
    94     fTextureCache = NULL;
    95     fFontCache = NULL;
    96     fDrawBuffer = NULL;
    97     fDrawBufferVBAllocPool = NULL;
    98     fDrawBufferIBAllocPool = NULL;
    99     fFlushToReduceCacheSize = false;
   100     fAARectRenderer = NULL;
   101     fOvalRenderer = NULL;
   102     fViewMatrix.reset();
   103     fMaxTextureSizeOverride = 1 << 20;
   104 }
   106 bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
   107     SkASSERT(NULL == fGpu);
   109     fGpu = GrGpu::Create(backend, backendContext, this);
   110     if (NULL == fGpu) {
   111         return false;
   112     }
   114     fDrawState = SkNEW(GrDrawState);
   115     fGpu->setDrawState(fDrawState);
   117     fTextureCache = SkNEW_ARGS(GrResourceCache,
   118                                (MAX_RESOURCE_CACHE_COUNT,
   119                                 MAX_RESOURCE_CACHE_BYTES));
   120     fTextureCache->setOverbudgetCallback(OverbudgetCB, this);
   122     fFontCache = SkNEW_ARGS(GrFontCache, (fGpu));
   124     fLastDrawWasBuffered = kNo_BufferedDraw;
   126     fAARectRenderer = SkNEW(GrAARectRenderer);
   127     fOvalRenderer = SkNEW(GrOvalRenderer);
   129     fDidTestPMConversions = false;
   131     this->setupDrawBuffer();
   133     return true;
   134 }
   136 GrContext::~GrContext() {
   137     if (NULL == fGpu) {
   138         return;
   139     }
   141     this->flush();
   143     for (int i = 0; i < fCleanUpData.count(); ++i) {
   144         (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
   145     }
   147     // Since the gpu can hold scratch textures, give it a chance to let go
   148     // of them before freeing the texture cache
   149     fGpu->purgeResources();
   151     delete fTextureCache;
   152     fTextureCache = NULL;
   153     delete fFontCache;
   154     delete fDrawBuffer;
   155     delete fDrawBufferVBAllocPool;
   156     delete fDrawBufferIBAllocPool;
   158     fAARectRenderer->unref();
   159     fOvalRenderer->unref();
   161     fGpu->unref();
   162     SkSafeUnref(fPathRendererChain);
   163     SkSafeUnref(fSoftwarePathRenderer);
   164     fDrawState->unref();
   165 }
   167 void GrContext::contextLost() {
   168     this->contextDestroyed();
   169     this->setupDrawBuffer();
   170 }
   172 void GrContext::contextDestroyed() {
   173     // abandon first to so destructors
   174     // don't try to free the resources in the API.
   175     fGpu->abandonResources();
   177     // a path renderer may be holding onto resources that
   178     // are now unusable
   179     SkSafeSetNull(fPathRendererChain);
   180     SkSafeSetNull(fSoftwarePathRenderer);
   182     delete fDrawBuffer;
   183     fDrawBuffer = NULL;
   185     delete fDrawBufferVBAllocPool;
   186     fDrawBufferVBAllocPool = NULL;
   188     delete fDrawBufferIBAllocPool;
   189     fDrawBufferIBAllocPool = NULL;
   191     fAARectRenderer->reset();
   192     fOvalRenderer->reset();
   194     fTextureCache->purgeAllUnlocked();
   196     fFontCache->freeAll();
   197     fGpu->markContextDirty();
   198 }
   200 void GrContext::resetContext(uint32_t state) {
   201     fGpu->markContextDirty(state);
   202 }
   204 void GrContext::freeGpuResources() {
   205     this->flush();
   207     fGpu->purgeResources();
   209     fAARectRenderer->reset();
   210     fOvalRenderer->reset();
   212     fTextureCache->purgeAllUnlocked();
   213     fFontCache->freeAll();
   214     // a path renderer may be holding onto resources
   215     SkSafeSetNull(fPathRendererChain);
   216     SkSafeSetNull(fSoftwarePathRenderer);
   217 }
   219 size_t GrContext::getGpuTextureCacheBytes() const {
   220   return fTextureCache->getCachedResourceBytes();
   221 }
   223 ////////////////////////////////////////////////////////////////////////////////
   225 GrTexture* GrContext::findAndRefTexture(const GrTextureDesc& desc,
   226                                         const GrCacheID& cacheID,
   227                                         const GrTextureParams* params) {
   228     GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, params, desc, cacheID);
   229     GrResource* resource = fTextureCache->find(resourceKey);
   230     SkSafeRef(resource);
   231     return static_cast<GrTexture*>(resource);
   232 }
   234 bool GrContext::isTextureInCache(const GrTextureDesc& desc,
   235                                  const GrCacheID& cacheID,
   236                                  const GrTextureParams* params) const {
   237     GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, params, desc, cacheID);
   238     return fTextureCache->hasKey(resourceKey);
   239 }
   241 void GrContext::addStencilBuffer(GrStencilBuffer* sb) {
   242     ASSERT_OWNED_RESOURCE(sb);
   244     GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(sb->width(),
   245                                                             sb->height(),
   246                                                             sb->numSamples());
   247     fTextureCache->addResource(resourceKey, sb);
   248 }
   250 GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
   251                                               int sampleCnt) {
   252     GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(width,
   253                                                             height,
   254                                                             sampleCnt);
   255     GrResource* resource = fTextureCache->find(resourceKey);
   256     return static_cast<GrStencilBuffer*>(resource);
   257 }
   259 static void stretchImage(void* dst,
   260                          int dstW,
   261                          int dstH,
   262                          void* src,
   263                          int srcW,
   264                          int srcH,
   265                          size_t bpp) {
   266     GrFixed dx = (srcW << 16) / dstW;
   267     GrFixed dy = (srcH << 16) / dstH;
   269     GrFixed y = dy >> 1;
   271     size_t dstXLimit = dstW*bpp;
   272     for (int j = 0; j < dstH; ++j) {
   273         GrFixed x = dx >> 1;
   274         void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
   275         void* dstRow = (uint8_t*)dst + j*dstW*bpp;
   276         for (size_t i = 0; i < dstXLimit; i += bpp) {
   277             memcpy((uint8_t*) dstRow + i,
   278                    (uint8_t*) srcRow + (x>>16)*bpp,
   279                    bpp);
   280             x += dx;
   281         }
   282         y += dy;
   283     }
   284 }
   286 namespace {
   288 // position + local coordinate
   289 extern const GrVertexAttrib gVertexAttribs[] = {
   290     {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
   291     {kVec2f_GrVertexAttribType, sizeof(GrPoint), kLocalCoord_GrVertexAttribBinding}
   292 };
   294 };
   296 // The desired texture is NPOT and tiled but that isn't supported by
   297 // the current hardware. Resize the texture to be a POT
   298 GrTexture* GrContext::createResizedTexture(const GrTextureDesc& desc,
   299                                            const GrCacheID& cacheID,
   300                                            void* srcData,
   301                                            size_t rowBytes,
   302                                            bool filter) {
   303     SkAutoTUnref<GrTexture> clampedTexture(this->findAndRefTexture(desc, cacheID, NULL));
   304     if (NULL == clampedTexture) {
   305         clampedTexture.reset(this->createTexture(NULL, desc, cacheID, srcData, rowBytes));
   307         if (NULL == clampedTexture) {
   308             return NULL;
   309         }
   310     }
   312     GrTextureDesc rtDesc = desc;
   313     rtDesc.fFlags =  rtDesc.fFlags |
   314                      kRenderTarget_GrTextureFlagBit |
   315                      kNoStencil_GrTextureFlagBit;
   316     rtDesc.fWidth  = GrNextPow2(desc.fWidth);
   317     rtDesc.fHeight = GrNextPow2(desc.fHeight);
   319     GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
   321     if (NULL != texture) {
   322         GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
   323         GrDrawState* drawState = fGpu->drawState();
   324         drawState->setRenderTarget(texture->asRenderTarget());
   326         // if filtering is not desired then we want to ensure all
   327         // texels in the resampled image are copies of texels from
   328         // the original.
   329         GrTextureParams params(SkShader::kClamp_TileMode, filter ? GrTextureParams::kBilerp_FilterMode :
   330                                                                    GrTextureParams::kNone_FilterMode);
   331         drawState->addColorTextureEffect(clampedTexture, SkMatrix::I(), params);
   333         drawState->setVertexAttribs<gVertexAttribs>(SK_ARRAY_COUNT(gVertexAttribs));
   335         GrDrawTarget::AutoReleaseGeometry arg(fGpu, 4, 0);
   337         if (arg.succeeded()) {
   338             GrPoint* verts = (GrPoint*) arg.vertices();
   339             verts[0].setIRectFan(0, 0, texture->width(), texture->height(), 2 * sizeof(GrPoint));
   340             verts[1].setIRectFan(0, 0, 1, 1, 2 * sizeof(GrPoint));
   341             fGpu->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4);
   342         }
   343     } else {
   344         // TODO: Our CPU stretch doesn't filter. But we create separate
   345         // stretched textures when the texture params is either filtered or
   346         // not. Either implement filtered stretch blit on CPU or just create
   347         // one when FBO case fails.
   349         rtDesc.fFlags = kNone_GrTextureFlags;
   350         // no longer need to clamp at min RT size.
   351         rtDesc.fWidth  = GrNextPow2(desc.fWidth);
   352         rtDesc.fHeight = GrNextPow2(desc.fHeight);
   353         size_t bpp = GrBytesPerPixel(desc.fConfig);
   354         SkAutoSMalloc<128*128*4> stretchedPixels(bpp * rtDesc.fWidth * rtDesc.fHeight);
   355         stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
   356                      srcData, desc.fWidth, desc.fHeight, bpp);
   358         size_t stretchedRowBytes = rtDesc.fWidth * bpp;
   360         SkDEBUGCODE(GrTexture* texture = )fGpu->createTexture(rtDesc, stretchedPixels.get(),
   361                                                               stretchedRowBytes);
   362         SkASSERT(NULL != texture);
   363     }
   365     return texture;
   366 }
   368 GrTexture* GrContext::createTexture(const GrTextureParams* params,
   369                                     const GrTextureDesc& desc,
   370                                     const GrCacheID& cacheID,
   371                                     void* srcData,
   372                                     size_t rowBytes,
   373                                     GrResourceKey* cacheKey) {
   374     SK_TRACE_EVENT0("GrContext::createTexture");
   376     GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, params, desc, cacheID);
   378     GrTexture* texture;
   379     if (GrTexture::NeedsResizing(resourceKey)) {
   380         texture = this->createResizedTexture(desc, cacheID,
   381                                              srcData, rowBytes,
   382                                              GrTexture::NeedsBilerp(resourceKey));
   383     } else {
   384         texture= fGpu->createTexture(desc, srcData, rowBytes);
   385     }
   387     if (NULL != texture) {
   388         // Adding a resource could put us overbudget. Try to free up the
   389         // necessary space before adding it.
   390         fTextureCache->purgeAsNeeded(1, texture->sizeInBytes());
   391         fTextureCache->addResource(resourceKey, texture);
   393         if (NULL != cacheKey) {
   394             *cacheKey = resourceKey;
   395         }
   396     }
   398     return texture;
   399 }
   401 static GrTexture* create_scratch_texture(GrGpu* gpu,
   402                                          GrResourceCache* textureCache,
   403                                          const GrTextureDesc& desc) {
   404     GrTexture* texture = gpu->createTexture(desc, NULL, 0);
   405     if (NULL != texture) {
   406         GrResourceKey key = GrTexture::ComputeScratchKey(texture->desc());
   407         // Adding a resource could put us overbudget. Try to free up the
   408         // necessary space before adding it.
   409         textureCache->purgeAsNeeded(1, texture->sizeInBytes());
   410         // Make the resource exclusive so future 'find' calls don't return it
   411         textureCache->addResource(key, texture, GrResourceCache::kHide_OwnershipFlag);
   412     }
   413     return texture;
   414 }
   416 GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, ScratchTexMatch match) {
   418     SkASSERT((inDesc.fFlags & kRenderTarget_GrTextureFlagBit) ||
   419              !(inDesc.fFlags & kNoStencil_GrTextureFlagBit));
   421     // Renderable A8 targets are not universally supported (e.g., not on ANGLE)
   422     SkASSERT(this->isConfigRenderable(kAlpha_8_GrPixelConfig, inDesc.fSampleCnt > 0) ||
   423              !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit) ||
   424              (inDesc.fConfig != kAlpha_8_GrPixelConfig));
   426     if (!fGpu->caps()->reuseScratchTextures() &&
   427         !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit)) {
   428         // If we're never recycling this texture we can always make it the right size
   429         return create_scratch_texture(fGpu, fTextureCache, inDesc);
   430     }
   432     GrTextureDesc desc = inDesc;
   434     if (kApprox_ScratchTexMatch == match) {
   435         // bin by pow2 with a reasonable min
   436         static const int MIN_SIZE = 16;
   437         desc.fWidth  = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
   438         desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
   439     }
   441     GrResource* resource = NULL;
   442     int origWidth = desc.fWidth;
   443     int origHeight = desc.fHeight;
   445     do {
   446         GrResourceKey key = GrTexture::ComputeScratchKey(desc);
   447         // Ensure we have exclusive access to the texture so future 'find' calls don't return it
   448         resource = fTextureCache->find(key, GrResourceCache::kHide_OwnershipFlag);
   449         if (NULL != resource) {
   450             resource->ref();
   451             break;
   452         }
   453         if (kExact_ScratchTexMatch == match) {
   454             break;
   455         }
   456         // We had a cache miss and we are in approx mode, relax the fit of the flags.
   458         // We no longer try to reuse textures that were previously used as render targets in
   459         // situations where no RT is needed; doing otherwise can confuse the video driver and
   460         // cause significant performance problems in some cases.
   461         if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
   462             desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
   463         } else {
   464             break;
   465         }
   467     } while (true);
   469     if (NULL == resource) {
   470         desc.fFlags = inDesc.fFlags;
   471         desc.fWidth = origWidth;
   472         desc.fHeight = origHeight;
   473         resource = create_scratch_texture(fGpu, fTextureCache, desc);
   474     }
   476     return static_cast<GrTexture*>(resource);
   477 }
   479 void GrContext::addExistingTextureToCache(GrTexture* texture) {
   481     if (NULL == texture) {
   482         return;
   483     }
   485     // This texture should already have a cache entry since it was once
   486     // attached
   487     SkASSERT(NULL != texture->getCacheEntry());
   489     // Conceptually, the cache entry is going to assume responsibility
   490     // for the creation ref. Assert refcnt == 1.
   491     SkASSERT(texture->unique());
   493     if (fGpu->caps()->reuseScratchTextures() || NULL != texture->asRenderTarget()) {
   494         // Since this texture came from an AutoScratchTexture it should
   495         // still be in the exclusive pile. Recycle it.
   496         fTextureCache->makeNonExclusive(texture->getCacheEntry());
   497         this->purgeCache();
   498     } else if (texture->getDeferredRefCount() <= 0) {
   499         // When we aren't reusing textures we know this scratch texture
   500         // will never be reused and would be just wasting time in the cache
   501         fTextureCache->makeNonExclusive(texture->getCacheEntry());
   502         fTextureCache->deleteResource(texture->getCacheEntry());
   503     } else {
   504         // In this case (fDeferredRefCount > 0) but the cache is the only
   505         // one holding a real ref. Mark the object so when the deferred
   506         // ref count goes to 0 the texture will be deleted (remember
   507         // in this code path scratch textures aren't getting reused).
   508         texture->setNeedsDeferredUnref();
   509     }
   510 }
   513 void GrContext::unlockScratchTexture(GrTexture* texture) {
   514     ASSERT_OWNED_RESOURCE(texture);
   515     SkASSERT(NULL != texture->getCacheEntry());
   517     // If this is a scratch texture we detached it from the cache
   518     // while it was locked (to avoid two callers simultaneously getting
   519     // the same texture).
   520     if (texture->getCacheEntry()->key().isScratch()) {
   521         if (fGpu->caps()->reuseScratchTextures() || NULL != texture->asRenderTarget()) {
   522             fTextureCache->makeNonExclusive(texture->getCacheEntry());
   523             this->purgeCache();
   524         } else if (texture->unique() && texture->getDeferredRefCount() <= 0) {
   525             // Only the cache now knows about this texture. Since we're never
   526             // reusing scratch textures (in this code path) it would just be
   527             // wasting time sitting in the cache.
   528             fTextureCache->makeNonExclusive(texture->getCacheEntry());
   529             fTextureCache->deleteResource(texture->getCacheEntry());
   530         } else {
   531             // In this case (fRefCnt > 1 || defRefCnt > 0) but we don't really
   532             // want to readd it to the cache (since it will never be reused).
   533             // Instead, give up the cache's ref and leave the decision up to
   534             // addExistingTextureToCache once its ref count reaches 0. For
   535             // this to work we need to leave it in the exclusive list.
   536             texture->setFlag((GrTextureFlags) GrTexture::kReturnToCache_FlagBit);
   537             // Give up the cache's ref to the texture
   538             texture->unref();
   539         }
   540     }
   541 }
   543 void GrContext::purgeCache() {
   544     if (NULL != fTextureCache) {
   545         fTextureCache->purgeAsNeeded();
   546     }
   547 }
   549 bool GrContext::OverbudgetCB(void* data) {
   550     SkASSERT(NULL != data);
   552     GrContext* context = reinterpret_cast<GrContext*>(data);
   554     // Flush the InOrderDrawBuffer to possibly free up some textures
   555     context->fFlushToReduceCacheSize = true;
   557     return true;
   558 }
   561 GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& descIn,
   562                                             void* srcData,
   563                                             size_t rowBytes) {
   564     GrTextureDesc descCopy = descIn;
   565     return fGpu->createTexture(descCopy, srcData, rowBytes);
   566 }
   568 void GrContext::getTextureCacheLimits(int* maxTextures,
   569                                       size_t* maxTextureBytes) const {
   570     fTextureCache->getLimits(maxTextures, maxTextureBytes);
   571 }
   573 void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
   574     fTextureCache->setLimits(maxTextures, maxTextureBytes);
   575 }
   577 int GrContext::getMaxTextureSize() const {
   578     return GrMin(fGpu->caps()->maxTextureSize(), fMaxTextureSizeOverride);
   579 }
   581 int GrContext::getMaxRenderTargetSize() const {
   582     return fGpu->caps()->maxRenderTargetSize();
   583 }
   585 int GrContext::getMaxSampleCount() const {
   586     return fGpu->caps()->maxSampleCount();
   587 }
   589 ///////////////////////////////////////////////////////////////////////////////
   591 GrTexture* GrContext::wrapBackendTexture(const GrBackendTextureDesc& desc) {
   592     return fGpu->wrapBackendTexture(desc);
   593 }
   595 GrRenderTarget* GrContext::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
   596     return fGpu->wrapBackendRenderTarget(desc);
   597 }
   599 ///////////////////////////////////////////////////////////////////////////////
   601 bool GrContext::supportsIndex8PixelConfig(const GrTextureParams* params,
   602                                           int width, int height) const {
   603     const GrDrawTargetCaps* caps = fGpu->caps();
   604     if (!caps->eightBitPaletteSupport()) {
   605         return false;
   606     }
   608     bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
   610     if (!isPow2) {
   611         bool tiled = NULL != params && params->isTiled();
   612         if (tiled && !caps->npotTextureTileSupport()) {
   613             return false;
   614         }
   615     }
   616     return true;
   617 }
   620 ////////////////////////////////////////////////////////////////////////////////
   622 void GrContext::clear(const SkIRect* rect,
   623                       const GrColor color,
   624                       bool canIgnoreRect,
   625                       GrRenderTarget* target) {
   626     AutoRestoreEffects are;
   627     AutoCheckFlush acf(this);
   628     this->prepareToDraw(NULL, BUFFERED_DRAW, &are, &acf)->clear(rect, color,
   629                                                                 canIgnoreRect, target);
   630 }
   632 void GrContext::drawPaint(const GrPaint& origPaint) {
   633     // set rect to be big enough to fill the space, but not super-huge, so we
   634     // don't overflow fixed-point implementations
   635     SkRect r;
   636     r.setLTRB(0, 0,
   637               SkIntToScalar(getRenderTarget()->width()),
   638               SkIntToScalar(getRenderTarget()->height()));
   639     SkMatrix inverse;
   640     SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
   641     AutoMatrix am;
   643     // We attempt to map r by the inverse matrix and draw that. mapRect will
   644     // map the four corners and bound them with a new rect. This will not
   645     // produce a correct result for some perspective matrices.
   646     if (!this->getMatrix().hasPerspective()) {
   647         if (!fViewMatrix.invert(&inverse)) {
   648             GrPrintf("Could not invert matrix\n");
   649             return;
   650         }
   651         inverse.mapRect(&r);
   652     } else {
   653         if (!am.setIdentity(this, paint.writable())) {
   654             GrPrintf("Could not invert matrix\n");
   655             return;
   656         }
   657     }
   658     // by definition this fills the entire clip, no need for AA
   659     if (paint->isAntiAlias()) {
   660         paint.writable()->setAntiAlias(false);
   661     }
   662     this->drawRect(*paint, r);
   663 }
   665 #ifdef SK_DEVELOPER
   666 void GrContext::dumpFontCache() const {
   667     fFontCache->dump();
   668 }
   669 #endif
   671 ////////////////////////////////////////////////////////////////////////////////
   673 /*  create a triangle strip that strokes the specified triangle. There are 8
   674  unique vertices, but we repreat the last 2 to close up. Alternatively we
   675  could use an indices array, and then only send 8 verts, but not sure that
   676  would be faster.
   677  */
   678 static void setStrokeRectStrip(GrPoint verts[10], SkRect rect,
   679                                SkScalar width) {
   680     const SkScalar rad = SkScalarHalf(width);
   681     rect.sort();
   683     verts[0].set(rect.fLeft + rad, rect.fTop + rad);
   684     verts[1].set(rect.fLeft - rad, rect.fTop - rad);
   685     verts[2].set(rect.fRight - rad, rect.fTop + rad);
   686     verts[3].set(rect.fRight + rad, rect.fTop - rad);
   687     verts[4].set(rect.fRight - rad, rect.fBottom - rad);
   688     verts[5].set(rect.fRight + rad, rect.fBottom + rad);
   689     verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
   690     verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
   691     verts[8] = verts[0];
   692     verts[9] = verts[1];
   693 }
   695 static bool isIRect(const SkRect& r) {
   696     return SkScalarIsInt(r.fLeft)  && SkScalarIsInt(r.fTop) &&
   697            SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
   698 }
   700 static bool apply_aa_to_rect(GrDrawTarget* target,
   701                              const SkRect& rect,
   702                              SkScalar strokeWidth,
   703                              const SkMatrix& combinedMatrix,
   704                              SkRect* devBoundRect,
   705                              bool* useVertexCoverage) {
   706     // we use a simple coverage ramp to do aa on axis-aligned rects
   707     // we check if the rect will be axis-aligned, and the rect won't land on
   708     // integer coords.
   710     // we are keeping around the "tweak the alpha" trick because
   711     // it is our only hope for the fixed-pipe implementation.
   712     // In a shader implementation we can give a separate coverage input
   713     // TODO: remove this ugliness when we drop the fixed-pipe impl
   714     *useVertexCoverage = false;
   715     if (!target->getDrawState().canTweakAlphaForCoverage()) {
   716         if (target->shouldDisableCoverageAAForBlend()) {
   717 #ifdef SK_DEBUG
   718             //GrPrintf("Turning off AA to correctly apply blend.\n");
   719 #endif
   720             return false;
   721         } else {
   722             *useVertexCoverage = true;
   723         }
   724     }
   725     const GrDrawState& drawState = target->getDrawState();
   726     if (drawState.getRenderTarget()->isMultisampled()) {
   727         return false;
   728     }
   730     if (0 == strokeWidth && target->willUseHWAALines()) {
   731         return false;
   732     }
   734 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
   735     if (strokeWidth >= 0) {
   736 #endif
   737         if (!combinedMatrix.preservesAxisAlignment()) {
   738             return false;
   739         }
   741 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
   742     } else {
   743         if (!combinedMatrix.preservesRightAngles()) {
   744             return false;
   745         }
   746     }
   747 #endif
   749     combinedMatrix.mapRect(devBoundRect, rect);
   751     if (strokeWidth < 0) {
   752         return !isIRect(*devBoundRect);
   753     } else {
   754         return true;
   755     }
   756 }
   758 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
   759     return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
   760            point.fY >= rect.fTop && point.fY <= rect.fBottom;
   761 }
   763 void GrContext::drawRect(const GrPaint& paint,
   764                          const SkRect& rect,
   765                          const SkStrokeRec* stroke,
   766                          const SkMatrix* matrix) {
   767     SK_TRACE_EVENT0("GrContext::drawRect");
   769     AutoRestoreEffects are;
   770     AutoCheckFlush acf(this);
   771     GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
   773     SkScalar width = stroke == NULL ? -1 : stroke->getWidth();
   774     SkMatrix combinedMatrix = target->drawState()->getViewMatrix();
   775     if (NULL != matrix) {
   776         combinedMatrix.preConcat(*matrix);
   777     }
   779     // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
   780     // cases where the RT is fully inside a stroke.
   781     if (width < 0) {
   782         SkRect rtRect;
   783         target->getDrawState().getRenderTarget()->getBoundsRect(&rtRect);
   784         SkRect clipSpaceRTRect = rtRect;
   785         bool checkClip = false;
   786         if (NULL != this->getClip()) {
   787             checkClip = true;
   788             clipSpaceRTRect.offset(SkIntToScalar(this->getClip()->fOrigin.fX),
   789                                    SkIntToScalar(this->getClip()->fOrigin.fY));
   790         }
   791         // Does the clip contain the entire RT?
   792         if (!checkClip || target->getClip()->fClipStack->quickContains(clipSpaceRTRect)) {
   793             SkMatrix invM;
   794             if (!combinedMatrix.invert(&invM)) {
   795                 return;
   796             }
   797             // Does the rect bound the RT?
   798             SkPoint srcSpaceRTQuad[4];
   799             invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
   800             if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
   801                 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
   802                 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
   803                 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
   804                 // Will it blend?
   805                 GrColor clearColor;
   806                 if (paint.isOpaqueAndConstantColor(&clearColor)) {
   807                     target->clear(NULL, clearColor, true);
   808                     return;
   809                 }
   810             }
   811         }
   812     }
   814     SkRect devBoundRect;
   815     bool useVertexCoverage;
   816     bool needAA = paint.isAntiAlias() &&
   817                   !target->getDrawState().getRenderTarget()->isMultisampled();
   818     bool doAA = needAA && apply_aa_to_rect(target, rect, width, combinedMatrix, &devBoundRect,
   819                                            &useVertexCoverage);
   820     if (doAA) {
   821         GrDrawState::AutoViewMatrixRestore avmr;
   822         if (!avmr.setIdentity(target->drawState())) {
   823             return;
   824         }
   825         if (width >= 0) {
   826             fAARectRenderer->strokeAARect(this->getGpu(), target, rect,
   827                                           combinedMatrix, devBoundRect,
   828                                           stroke, useVertexCoverage);
   829         } else {
   830             // filled AA rect
   831             fAARectRenderer->fillAARect(this->getGpu(), target,
   832                                         rect, combinedMatrix, devBoundRect,
   833                                         useVertexCoverage);
   834         }
   835         return;
   836     }
   838     if (width >= 0) {
   839         // TODO: consider making static vertex buffers for these cases.
   840         // Hairline could be done by just adding closing vertex to
   841         // unitSquareVertexBuffer()
   843         static const int worstCaseVertCount = 10;
   844         target->drawState()->setDefaultVertexAttribs();
   845         GrDrawTarget::AutoReleaseGeometry geo(target, worstCaseVertCount, 0);
   847         if (!geo.succeeded()) {
   848             GrPrintf("Failed to get space for vertices!\n");
   849             return;
   850         }
   852         GrPrimitiveType primType;
   853         int vertCount;
   854         GrPoint* vertex = geo.positions();
   856         if (width > 0) {
   857             vertCount = 10;
   858             primType = kTriangleStrip_GrPrimitiveType;
   859             setStrokeRectStrip(vertex, rect, width);
   860         } else {
   861             // hairline
   862             vertCount = 5;
   863             primType = kLineStrip_GrPrimitiveType;
   864             vertex[0].set(rect.fLeft, rect.fTop);
   865             vertex[1].set(rect.fRight, rect.fTop);
   866             vertex[2].set(rect.fRight, rect.fBottom);
   867             vertex[3].set(rect.fLeft, rect.fBottom);
   868             vertex[4].set(rect.fLeft, rect.fTop);
   869         }
   871         GrDrawState::AutoViewMatrixRestore avmr;
   872         if (NULL != matrix) {
   873             GrDrawState* drawState = target->drawState();
   874             avmr.set(drawState, *matrix);
   875         }
   877         target->drawNonIndexed(primType, 0, vertCount);
   878     } else {
   879         // filled BW rect
   880         target->drawSimpleRect(rect, matrix);
   881     }
   882 }
   884 void GrContext::drawRectToRect(const GrPaint& paint,
   885                                const SkRect& dstRect,
   886                                const SkRect& localRect,
   887                                const SkMatrix* dstMatrix,
   888                                const SkMatrix* localMatrix) {
   889     SK_TRACE_EVENT0("GrContext::drawRectToRect");
   890     AutoRestoreEffects are;
   891     AutoCheckFlush acf(this);
   892     GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
   894     target->drawRect(dstRect, dstMatrix, &localRect, localMatrix);
   895 }
   897 namespace {
   899 extern const GrVertexAttrib gPosUVColorAttribs[] = {
   900     {kVec2f_GrVertexAttribType,  0, kPosition_GrVertexAttribBinding },
   901     {kVec2f_GrVertexAttribType,  sizeof(GrPoint), kLocalCoord_GrVertexAttribBinding },
   902     {kVec4ub_GrVertexAttribType, 2*sizeof(GrPoint), kColor_GrVertexAttribBinding}
   903 };
   905 extern const GrVertexAttrib gPosColorAttribs[] = {
   906     {kVec2f_GrVertexAttribType,  0, kPosition_GrVertexAttribBinding},
   907     {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
   908 };
   910 static void set_vertex_attributes(GrDrawState* drawState,
   911                                   const GrPoint* texCoords,
   912                                   const GrColor* colors,
   913                                   int* colorOffset,
   914                                   int* texOffset) {
   915     *texOffset = -1;
   916     *colorOffset = -1;
   918     if (NULL != texCoords && NULL != colors) {
   919         *texOffset = sizeof(GrPoint);
   920         *colorOffset = 2*sizeof(GrPoint);
   921         drawState->setVertexAttribs<gPosUVColorAttribs>(3);
   922     } else if (NULL != texCoords) {
   923         *texOffset = sizeof(GrPoint);
   924         drawState->setVertexAttribs<gPosUVColorAttribs>(2);
   925     } else if (NULL != colors) {
   926         *colorOffset = sizeof(GrPoint);
   927         drawState->setVertexAttribs<gPosColorAttribs>(2);
   928     } else {
   929         drawState->setVertexAttribs<gPosColorAttribs>(1);
   930     }
   931 }
   933 };
   935 void GrContext::drawVertices(const GrPaint& paint,
   936                              GrPrimitiveType primitiveType,
   937                              int vertexCount,
   938                              const GrPoint positions[],
   939                              const GrPoint texCoords[],
   940                              const GrColor colors[],
   941                              const uint16_t indices[],
   942                              int indexCount) {
   943     SK_TRACE_EVENT0("GrContext::drawVertices");
   945     AutoRestoreEffects are;
   946     AutoCheckFlush acf(this);
   947     GrDrawTarget::AutoReleaseGeometry geo; // must be inside AutoCheckFlush scope
   949     GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
   951     GrDrawState* drawState = target->drawState();
   953     int colorOffset = -1, texOffset = -1;
   954     set_vertex_attributes(drawState, texCoords, colors, &colorOffset, &texOffset);
   956     size_t vertexSize = drawState->getVertexSize();
   957     if (sizeof(GrPoint) != vertexSize) {
   958         if (!geo.set(target, vertexCount, 0)) {
   959             GrPrintf("Failed to get space for vertices!\n");
   960             return;
   961         }
   962         void* curVertex = geo.vertices();
   964         for (int i = 0; i < vertexCount; ++i) {
   965             *((GrPoint*)curVertex) = positions[i];
   967             if (texOffset >= 0) {
   968                 *(GrPoint*)((intptr_t)curVertex + texOffset) = texCoords[i];
   969             }
   970             if (colorOffset >= 0) {
   971                 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
   972             }
   973             curVertex = (void*)((intptr_t)curVertex + vertexSize);
   974         }
   975     } else {
   976         target->setVertexSourceToArray(positions, vertexCount);
   977     }
   979     // we don't currently apply offscreen AA to this path. Need improved
   980     // management of GrDrawTarget's geometry to avoid copying points per-tile.
   982     if (NULL != indices) {
   983         target->setIndexSourceToArray(indices, indexCount);
   984         target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
   985         target->resetIndexSource();
   986     } else {
   987         target->drawNonIndexed(primitiveType, 0, vertexCount);
   988     }
   989 }
   991 ///////////////////////////////////////////////////////////////////////////////
   993 void GrContext::drawRRect(const GrPaint& paint,
   994                           const SkRRect& rect,
   995                           const SkStrokeRec& stroke) {
   996     if (rect.isEmpty()) {
   997        return;
   998     }
  1000     AutoRestoreEffects are;
  1001     AutoCheckFlush acf(this);
  1002     GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
  1004     if (!fOvalRenderer->drawSimpleRRect(target, this, paint.isAntiAlias(), rect, stroke)) {
  1005         SkPath path;
  1006         path.addRRect(rect);
  1007         this->internalDrawPath(target, paint.isAntiAlias(), path, stroke);
  1011 ///////////////////////////////////////////////////////////////////////////////
  1013 void GrContext::drawOval(const GrPaint& paint,
  1014                          const SkRect& oval,
  1015                          const SkStrokeRec& stroke) {
  1016     if (oval.isEmpty()) {
  1017        return;
  1020     AutoRestoreEffects are;
  1021     AutoCheckFlush acf(this);
  1022     GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
  1024     if (!fOvalRenderer->drawOval(target, this, paint.isAntiAlias(), oval, stroke)) {
  1025         SkPath path;
  1026         path.addOval(oval);
  1027         this->internalDrawPath(target, paint.isAntiAlias(), path, stroke);
  1031 // Can 'path' be drawn as a pair of filled nested rectangles?
  1032 static bool is_nested_rects(GrDrawTarget* target,
  1033                             const SkPath& path,
  1034                             const SkStrokeRec& stroke,
  1035                             SkRect rects[2],
  1036                             bool* useVertexCoverage) {
  1037     SkASSERT(stroke.isFillStyle());
  1039     if (path.isInverseFillType()) {
  1040         return false;
  1043     const GrDrawState& drawState = target->getDrawState();
  1045     // TODO: this restriction could be lifted if we were willing to apply
  1046     // the matrix to all the points individually rather than just to the rect
  1047     if (!drawState.getViewMatrix().preservesAxisAlignment()) {
  1048         return false;
  1051     *useVertexCoverage = false;
  1052     if (!target->getDrawState().canTweakAlphaForCoverage()) {
  1053         if (target->shouldDisableCoverageAAForBlend()) {
  1054             return false;
  1055         } else {
  1056             *useVertexCoverage = true;
  1060     SkPath::Direction dirs[2];
  1061     if (!path.isNestedRects(rects, dirs)) {
  1062         return false;
  1065     if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
  1066         // The two rects need to be wound opposite to each other
  1067         return false;
  1070     // Right now, nested rects where the margin is not the same width
  1071     // all around do not render correctly
  1072     const SkScalar* outer = rects[0].asScalars();
  1073     const SkScalar* inner = rects[1].asScalars();
  1075     SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
  1076     for (int i = 1; i < 4; ++i) {
  1077         SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
  1078         if (!SkScalarNearlyEqual(margin, temp)) {
  1079             return false;
  1083     return true;
  1086 void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke) {
  1088     if (path.isEmpty()) {
  1089        if (path.isInverseFillType()) {
  1090            this->drawPaint(paint);
  1092        return;
  1095     // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
  1096     // Scratch textures can be recycled after they are returned to the texture
  1097     // cache. This presents a potential hazard for buffered drawing. However,
  1098     // the writePixels that uploads to the scratch will perform a flush so we're
  1099     // OK.
  1100     AutoRestoreEffects are;
  1101     AutoCheckFlush acf(this);
  1102     GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
  1103     GrDrawState* drawState = target->drawState();
  1105     bool useCoverageAA = paint.isAntiAlias() && !drawState->getRenderTarget()->isMultisampled();
  1107     if (useCoverageAA && stroke.getWidth() < 0 && !path.isConvex()) {
  1108         // Concave AA paths are expensive - try to avoid them for special cases
  1109         bool useVertexCoverage;
  1110         SkRect rects[2];
  1112         if (is_nested_rects(target, path, stroke, rects, &useVertexCoverage)) {
  1113             SkMatrix origViewMatrix = drawState->getViewMatrix();
  1114             GrDrawState::AutoViewMatrixRestore avmr;
  1115             if (!avmr.setIdentity(target->drawState())) {
  1116                 return;
  1119             fAARectRenderer->fillAANestedRects(this->getGpu(), target,
  1120                                                rects,
  1121                                                origViewMatrix,
  1122                                                useVertexCoverage);
  1123             return;
  1127     SkRect ovalRect;
  1128     bool isOval = path.isOval(&ovalRect);
  1130     if (!isOval || path.isInverseFillType()
  1131         || !fOvalRenderer->drawOval(target, this, paint.isAntiAlias(), ovalRect, stroke)) {
  1132         this->internalDrawPath(target, paint.isAntiAlias(), path, stroke);
  1136 void GrContext::internalDrawPath(GrDrawTarget* target, bool useAA, const SkPath& path,
  1137                                  const SkStrokeRec& origStroke) {
  1138     SkASSERT(!path.isEmpty());
  1140     // An Assumption here is that path renderer would use some form of tweaking
  1141     // the src color (either the input alpha or in the frag shader) to implement
  1142     // aa. If we have some future driver-mojo path AA that can do the right
  1143     // thing WRT to the blend then we'll need some query on the PR.
  1144     bool useCoverageAA = useAA &&
  1145         !target->getDrawState().getRenderTarget()->isMultisampled() &&
  1146         !target->shouldDisableCoverageAAForBlend();
  1149     GrPathRendererChain::DrawType type =
  1150         useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
  1151                            GrPathRendererChain::kColor_DrawType;
  1153     const SkPath* pathPtr = &path;
  1154     SkTLazy<SkPath> tmpPath;
  1155     SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke);
  1157     // Try a 1st time without stroking the path and without allowing the SW renderer
  1158     GrPathRenderer* pr = this->getPathRenderer(*pathPtr, *stroke, target, false, type);
  1160     if (NULL == pr) {
  1161         if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*stroke, this->getMatrix(), NULL)) {
  1162             // It didn't work the 1st time, so try again with the stroked path
  1163             if (stroke->applyToPath(tmpPath.init(), *pathPtr)) {
  1164                 pathPtr = tmpPath.get();
  1165                 stroke.writable()->setFillStyle();
  1166                 if (pathPtr->isEmpty()) {
  1167                     return;
  1172         // This time, allow SW renderer
  1173         pr = this->getPathRenderer(*pathPtr, *stroke, target, true, type);
  1176     if (NULL == pr) {
  1177 #ifdef SK_DEBUG
  1178         GrPrintf("Unable to find path renderer compatible with path.\n");
  1179 #endif
  1180         return;
  1183     pr->drawPath(*pathPtr, *stroke, target, useCoverageAA);
  1186 ////////////////////////////////////////////////////////////////////////////////
  1188 void GrContext::flush(int flagsBitfield) {
  1189     if (NULL == fDrawBuffer) {
  1190         return;
  1193     if (kDiscard_FlushBit & flagsBitfield) {
  1194         fDrawBuffer->reset();
  1195     } else {
  1196         fDrawBuffer->flush();
  1198     fFlushToReduceCacheSize = false;
  1201 bool GrContext::writeTexturePixels(GrTexture* texture,
  1202                                    int left, int top, int width, int height,
  1203                                    GrPixelConfig config, const void* buffer, size_t rowBytes,
  1204                                    uint32_t flags) {
  1205     SK_TRACE_EVENT0("GrContext::writeTexturePixels");
  1206     ASSERT_OWNED_RESOURCE(texture);
  1208     if ((kUnpremul_PixelOpsFlag & flags) || !fGpu->canWriteTexturePixels(texture, config)) {
  1209         if (NULL != texture->asRenderTarget()) {
  1210             return this->writeRenderTargetPixels(texture->asRenderTarget(),
  1211                                                  left, top, width, height,
  1212                                                  config, buffer, rowBytes, flags);
  1213         } else {
  1214             return false;
  1218     if (!(kDontFlush_PixelOpsFlag & flags)) {
  1219         this->flush();
  1222     return fGpu->writeTexturePixels(texture, left, top, width, height,
  1223                                     config, buffer, rowBytes);
  1226 bool GrContext::readTexturePixels(GrTexture* texture,
  1227                                   int left, int top, int width, int height,
  1228                                   GrPixelConfig config, void* buffer, size_t rowBytes,
  1229                                   uint32_t flags) {
  1230     SK_TRACE_EVENT0("GrContext::readTexturePixels");
  1231     ASSERT_OWNED_RESOURCE(texture);
  1233     GrRenderTarget* target = texture->asRenderTarget();
  1234     if (NULL != target) {
  1235         return this->readRenderTargetPixels(target,
  1236                                             left, top, width, height,
  1237                                             config, buffer, rowBytes,
  1238                                             flags);
  1239     } else {
  1240         // TODO: make this more efficient for cases where we're reading the entire
  1241         //       texture, i.e., use GetTexImage() instead
  1243         // create scratch rendertarget and read from that
  1244         GrAutoScratchTexture ast;
  1245         GrTextureDesc desc;
  1246         desc.fFlags = kRenderTarget_GrTextureFlagBit;
  1247         desc.fWidth = width;
  1248         desc.fHeight = height;
  1249         desc.fConfig = config;
  1250         desc.fOrigin = kTopLeft_GrSurfaceOrigin;
  1251         ast.set(this, desc, kExact_ScratchTexMatch);
  1252         GrTexture* dst = ast.texture();
  1253         if (NULL != dst && NULL != (target = dst->asRenderTarget())) {
  1254             this->copyTexture(texture, target, NULL);
  1255             return this->readRenderTargetPixels(target,
  1256                                                 left, top, width, height,
  1257                                                 config, buffer, rowBytes,
  1258                                                 flags);
  1261         return false;
  1265 #include "SkConfig8888.h"
  1267 namespace {
  1268 /**
  1269  * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
  1270  * formats are representable as Config8888 and so the function returns false
  1271  * if the GrPixelConfig has no equivalent Config8888.
  1272  */
  1273 bool grconfig_to_config8888(GrPixelConfig config,
  1274                             bool unpremul,
  1275                             SkCanvas::Config8888* config8888) {
  1276     switch (config) {
  1277         case kRGBA_8888_GrPixelConfig:
  1278             if (unpremul) {
  1279                 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
  1280             } else {
  1281                 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
  1283             return true;
  1284         case kBGRA_8888_GrPixelConfig:
  1285             if (unpremul) {
  1286                 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
  1287             } else {
  1288                 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
  1290             return true;
  1291         default:
  1292             return false;
  1296 // It returns a configuration with where the byte position of the R & B components are swapped in
  1297 // relation to the input config. This should only be called with the result of
  1298 // grconfig_to_config8888 as it will fail for other configs.
  1299 SkCanvas::Config8888 swap_config8888_red_and_blue(SkCanvas::Config8888 config8888) {
  1300     switch (config8888) {
  1301         case SkCanvas::kBGRA_Premul_Config8888:
  1302             return SkCanvas::kRGBA_Premul_Config8888;
  1303         case SkCanvas::kBGRA_Unpremul_Config8888:
  1304             return SkCanvas::kRGBA_Unpremul_Config8888;
  1305         case SkCanvas::kRGBA_Premul_Config8888:
  1306             return SkCanvas::kBGRA_Premul_Config8888;
  1307         case SkCanvas::kRGBA_Unpremul_Config8888:
  1308             return SkCanvas::kBGRA_Unpremul_Config8888;
  1309         default:
  1310             GrCrash("Unexpected input");
  1311             return SkCanvas::kBGRA_Unpremul_Config8888;;
  1316 bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
  1317                                        int left, int top, int width, int height,
  1318                                        GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
  1319                                        uint32_t flags) {
  1320     SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
  1321     ASSERT_OWNED_RESOURCE(target);
  1323     if (NULL == target) {
  1324         target = fRenderTarget.get();
  1325         if (NULL == target) {
  1326             return false;
  1330     if (!(kDontFlush_PixelOpsFlag & flags)) {
  1331         this->flush();
  1334     // Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul.
  1336     // If fGpu->readPixels would incur a y-flip cost then we will read the pixels upside down. We'll
  1337     // either do the flipY by drawing into a scratch with a matrix or on the cpu after the read.
  1338     bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top,
  1339                                                  width, height, dstConfig,
  1340                                                  rowBytes);
  1341     // We ignore the preferred config if it is different than our config unless it is an R/B swap.
  1342     // In that case we'll perform an R and B swap while drawing to a scratch texture of the swapped
  1343     // config. Then we will call readPixels on the scratch with the swapped config. The swaps during
  1344     // the draw cancels out the fact that we call readPixels with a config that is R/B swapped from
  1345     // dstConfig.
  1346     GrPixelConfig readConfig = dstConfig;
  1347     bool swapRAndB = false;
  1348     if (GrPixelConfigSwapRAndB(dstConfig) ==
  1349         fGpu->preferredReadPixelsConfig(dstConfig, target->config())) {
  1350         readConfig = GrPixelConfigSwapRAndB(readConfig);
  1351         swapRAndB = true;
  1354     bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
  1356     if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
  1357         // The unpremul flag is only allowed for these two configs.
  1358         return false;
  1361     // If the src is a texture and we would have to do conversions after read pixels, we instead
  1362     // do the conversions by drawing the src to a scratch texture. If we handle any of the
  1363     // conversions in the draw we set the corresponding bool to false so that we don't reapply it
  1364     // on the read back pixels.
  1365     GrTexture* src = target->asTexture();
  1366     GrAutoScratchTexture ast;
  1367     if (NULL != src && (swapRAndB || unpremul || flipY)) {
  1368         // Make the scratch a render target because we don't have a robust readTexturePixels as of
  1369         // yet. It calls this function.
  1370         GrTextureDesc desc;
  1371         desc.fFlags = kRenderTarget_GrTextureFlagBit;
  1372         desc.fWidth = width;
  1373         desc.fHeight = height;
  1374         desc.fConfig = readConfig;
  1375         desc.fOrigin = kTopLeft_GrSurfaceOrigin;
  1377         // When a full read back is faster than a partial we could always make the scratch exactly
  1378         // match the passed rect. However, if we see many different size rectangles we will trash
  1379         // our texture cache and pay the cost of creating and destroying many textures. So, we only
  1380         // request an exact match when the caller is reading an entire RT.
  1381         ScratchTexMatch match = kApprox_ScratchTexMatch;
  1382         if (0 == left &&
  1383             0 == top &&
  1384             target->width() == width &&
  1385             target->height() == height &&
  1386             fGpu->fullReadPixelsIsFasterThanPartial()) {
  1387             match = kExact_ScratchTexMatch;
  1389         ast.set(this, desc, match);
  1390         GrTexture* texture = ast.texture();
  1391         if (texture) {
  1392             // compute a matrix to perform the draw
  1393             SkMatrix textureMatrix;
  1394             textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
  1395             textureMatrix.postIDiv(src->width(), src->height());
  1397             SkAutoTUnref<const GrEffectRef> effect;
  1398             if (unpremul) {
  1399                 effect.reset(this->createPMToUPMEffect(src, swapRAndB, textureMatrix));
  1400                 if (NULL != effect) {
  1401                     unpremul = false; // we no longer need to do this on CPU after the read back.
  1404             // If we failed to create a PM->UPM effect and have no other conversions to perform then
  1405             // there is no longer any point to using the scratch.
  1406             if (NULL != effect || flipY || swapRAndB) {
  1407                 if (!effect) {
  1408                     effect.reset(GrConfigConversionEffect::Create(
  1409                                                     src,
  1410                                                     swapRAndB,
  1411                                                     GrConfigConversionEffect::kNone_PMConversion,
  1412                                                     textureMatrix));
  1414                 swapRAndB = false; // we will handle the swap in the draw.
  1416                 // We protect the existing geometry here since it may not be
  1417                 // clear to the caller that a draw operation (i.e., drawSimpleRect)
  1418                 // can be invoked in this method
  1419                 GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit);
  1420                 GrDrawState* drawState = fGpu->drawState();
  1421                 SkASSERT(effect);
  1422                 drawState->addColorEffect(effect);
  1424                 drawState->setRenderTarget(texture->asRenderTarget());
  1425                 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
  1426                 fGpu->drawSimpleRect(rect, NULL);
  1427                 // we want to read back from the scratch's origin
  1428                 left = 0;
  1429                 top = 0;
  1430                 target = texture->asRenderTarget();
  1434     if (!fGpu->readPixels(target,
  1435                           left, top, width, height,
  1436                           readConfig, buffer, rowBytes)) {
  1437         return false;
  1439     // Perform any conversions we weren't able to perform using a scratch texture.
  1440     if (unpremul || swapRAndB) {
  1441         // These are initialized to suppress a warning
  1442         SkCanvas::Config8888 srcC8888 = SkCanvas::kNative_Premul_Config8888;
  1443         SkCanvas::Config8888 dstC8888 = SkCanvas::kNative_Premul_Config8888;
  1445         SkDEBUGCODE(bool c8888IsValid =) grconfig_to_config8888(dstConfig, false, &srcC8888);
  1446         grconfig_to_config8888(dstConfig, unpremul, &dstC8888);
  1448         if (swapRAndB) {
  1449             SkASSERT(c8888IsValid); // we should only do r/b swap on 8888 configs
  1450             srcC8888 = swap_config8888_red_and_blue(srcC8888);
  1452         SkASSERT(c8888IsValid);
  1453         uint32_t* b32 = reinterpret_cast<uint32_t*>(buffer);
  1454         SkConvertConfig8888Pixels(b32, rowBytes, dstC8888,
  1455                                   b32, rowBytes, srcC8888,
  1456                                   width, height);
  1458     return true;
  1461 void GrContext::resolveRenderTarget(GrRenderTarget* target) {
  1462     SkASSERT(target);
  1463     ASSERT_OWNED_RESOURCE(target);
  1464     // In the future we may track whether there are any pending draws to this
  1465     // target. We don't today so we always perform a flush. We don't promise
  1466     // this to our clients, though.
  1467     this->flush();
  1468     fGpu->resolveRenderTarget(target);
  1471 void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst, const SkIPoint* topLeft) {
  1472     if (NULL == src || NULL == dst) {
  1473         return;
  1475     ASSERT_OWNED_RESOURCE(src);
  1477     // Writes pending to the source texture are not tracked, so a flush
  1478     // is required to ensure that the copy captures the most recent contents
  1479     // of the source texture. See similar behavior in
  1480     // GrContext::resolveRenderTarget.
  1481     this->flush();
  1483     GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
  1484     GrDrawState* drawState = fGpu->drawState();
  1485     drawState->setRenderTarget(dst);
  1486     SkMatrix sampleM;
  1487     sampleM.setIDiv(src->width(), src->height());
  1488     SkIRect srcRect = SkIRect::MakeWH(dst->width(), dst->height());
  1489     if (NULL != topLeft) {
  1490         srcRect.offset(*topLeft);
  1492     SkIRect srcBounds = SkIRect::MakeWH(src->width(), src->height());
  1493     if (!srcRect.intersect(srcBounds)) {
  1494         return;
  1496     sampleM.preTranslate(SkIntToScalar(srcRect.fLeft), SkIntToScalar(srcRect.fTop));
  1497     drawState->addColorTextureEffect(src, sampleM);
  1498     SkRect dstR = SkRect::MakeWH(SkIntToScalar(srcRect.width()), SkIntToScalar(srcRect.height()));
  1499     fGpu->drawSimpleRect(dstR, NULL);
  1502 bool GrContext::writeRenderTargetPixels(GrRenderTarget* target,
  1503                                         int left, int top, int width, int height,
  1504                                         GrPixelConfig srcConfig,
  1505                                         const void* buffer,
  1506                                         size_t rowBytes,
  1507                                         uint32_t flags) {
  1508     SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
  1509     ASSERT_OWNED_RESOURCE(target);
  1511     if (NULL == target) {
  1512         target = fRenderTarget.get();
  1513         if (NULL == target) {
  1514             return false;
  1518     // TODO: when underlying api has a direct way to do this we should use it (e.g. glDrawPixels on
  1519     // desktop GL).
  1521     // We will always call some form of writeTexturePixels and we will pass our flags on to it.
  1522     // Thus, we don't perform a flush here since that call will do it (if the kNoFlush flag isn't
  1523     // set.)
  1525     // If the RT is also a texture and we don't have to premultiply then take the texture path.
  1526     // We expect to be at least as fast or faster since it doesn't use an intermediate texture as
  1527     // we do below.
  1529 #if !defined(SK_BUILD_FOR_MAC)
  1530     // At least some drivers on the Mac get confused when glTexImage2D is called on a texture
  1531     // attached to an FBO. The FBO still sees the old image. TODO: determine what OS versions and/or
  1532     // HW is affected.
  1533     if (NULL != target->asTexture() && !(kUnpremul_PixelOpsFlag & flags) &&
  1534         fGpu->canWriteTexturePixels(target->asTexture(), srcConfig)) {
  1535         return this->writeTexturePixels(target->asTexture(),
  1536                                         left, top, width, height,
  1537                                         srcConfig, buffer, rowBytes, flags);
  1539 #endif
  1541     // We ignore the preferred config unless it is a R/B swap of the src config. In that case
  1542     // we will upload the original src data to a scratch texture but we will spoof it as the swapped
  1543     // config. This scratch will then have R and B swapped. We correct for this by swapping again
  1544     // when drawing the scratch to the dst using a conversion effect.
  1545     bool swapRAndB = false;
  1546     GrPixelConfig writeConfig = srcConfig;
  1547     if (GrPixelConfigSwapRAndB(srcConfig) ==
  1548         fGpu->preferredWritePixelsConfig(srcConfig, target->config())) {
  1549         writeConfig = GrPixelConfigSwapRAndB(srcConfig);
  1550         swapRAndB = true;
  1553     GrTextureDesc desc;
  1554     desc.fWidth = width;
  1555     desc.fHeight = height;
  1556     desc.fConfig = writeConfig;
  1557     GrAutoScratchTexture ast(this, desc);
  1558     GrTexture* texture = ast.texture();
  1559     if (NULL == texture) {
  1560         return false;
  1563     SkAutoTUnref<const GrEffectRef> effect;
  1564     SkMatrix textureMatrix;
  1565     textureMatrix.setIDiv(texture->width(), texture->height());
  1567     // allocate a tmp buffer and sw convert the pixels to premul
  1568     SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
  1570     if (kUnpremul_PixelOpsFlag & flags) {
  1571         if (!GrPixelConfigIs8888(srcConfig)) {
  1572             return false;
  1574         effect.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix));
  1575         // handle the unpremul step on the CPU if we couldn't create an effect to do it.
  1576         if (NULL == effect) {
  1577             SkCanvas::Config8888 srcConfig8888, dstConfig8888;
  1578             SkDEBUGCODE(bool success = )
  1579             grconfig_to_config8888(srcConfig, true, &srcConfig8888);
  1580             SkASSERT(success);
  1581             SkDEBUGCODE(success = )
  1582             grconfig_to_config8888(srcConfig, false, &dstConfig8888);
  1583             SkASSERT(success);
  1584             const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
  1585             tmpPixels.reset(width * height);
  1586             SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
  1587                                       src, rowBytes, srcConfig8888,
  1588                                       width, height);
  1589             buffer = tmpPixels.get();
  1590             rowBytes = 4 * width;
  1593     if (NULL == effect) {
  1594         effect.reset(GrConfigConversionEffect::Create(texture,
  1595                                                       swapRAndB,
  1596                                                       GrConfigConversionEffect::kNone_PMConversion,
  1597                                                       textureMatrix));
  1600     if (!this->writeTexturePixels(texture,
  1601                                   0, 0, width, height,
  1602                                   writeConfig, buffer, rowBytes,
  1603                                   flags & ~kUnpremul_PixelOpsFlag)) {
  1604         return false;
  1607     // writeRenderTargetPixels can be called in the midst of drawing another
  1608     // object (e.g., when uploading a SW path rendering to the gpu while
  1609     // drawing a rect) so preserve the current geometry.
  1610     SkMatrix matrix;
  1611     matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
  1612     GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit, &matrix);
  1613     GrDrawState* drawState = fGpu->drawState();
  1614     SkASSERT(effect);
  1615     drawState->addColorEffect(effect);
  1617     drawState->setRenderTarget(target);
  1619     fGpu->drawSimpleRect(SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)), NULL);
  1620     return true;
  1622 ////////////////////////////////////////////////////////////////////////////////
  1624 GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint,
  1625                                        BufferedDraw buffered,
  1626                                        AutoRestoreEffects* are,
  1627                                        AutoCheckFlush* acf) {
  1628     // All users of this draw state should be freeing up all effects when they're done.
  1629     // Otherwise effects that own resources may keep those resources alive indefinitely.
  1630     SkASSERT(0 == fDrawState->numColorStages() && 0 == fDrawState->numCoverageStages());
  1632     if (kNo_BufferedDraw == buffered && kYes_BufferedDraw == fLastDrawWasBuffered) {
  1633         fDrawBuffer->flush();
  1634         fLastDrawWasBuffered = kNo_BufferedDraw;
  1636     ASSERT_OWNED_RESOURCE(fRenderTarget.get());
  1637     if (NULL != paint) {
  1638         SkASSERT(NULL != are);
  1639         SkASSERT(NULL != acf);
  1640         are->set(fDrawState);
  1641         fDrawState->setFromPaint(*paint, fViewMatrix, fRenderTarget.get());
  1642 #if GR_DEBUG_PARTIAL_COVERAGE_CHECK
  1643         if ((paint->hasMask() || 0xff != paint->fCoverage) &&
  1644             !fGpu->canApplyCoverage()) {
  1645             GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
  1647 #endif
  1648     } else {
  1649         fDrawState->reset(fViewMatrix);
  1650         fDrawState->setRenderTarget(fRenderTarget.get());
  1652     GrDrawTarget* target;
  1653     if (kYes_BufferedDraw == buffered) {
  1654         fLastDrawWasBuffered = kYes_BufferedDraw;
  1655         target = fDrawBuffer;
  1656     } else {
  1657         SkASSERT(kNo_BufferedDraw == buffered);
  1658         fLastDrawWasBuffered = kNo_BufferedDraw;
  1659         target = fGpu;
  1661     fDrawState->setState(GrDrawState::kClip_StateBit, NULL != fClip &&
  1662                                                      !fClip->fClipStack->isWideOpen());
  1663     target->setClip(fClip);
  1664     SkASSERT(fDrawState == target->drawState());
  1665     return target;
  1668 /*
  1669  * This method finds a path renderer that can draw the specified path on
  1670  * the provided target.
  1671  * Due to its expense, the software path renderer has split out so it can
  1672  * can be individually allowed/disallowed via the "allowSW" boolean.
  1673  */
  1674 GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
  1675                                            const SkStrokeRec& stroke,
  1676                                            const GrDrawTarget* target,
  1677                                            bool allowSW,
  1678                                            GrPathRendererChain::DrawType drawType,
  1679                                            GrPathRendererChain::StencilSupport* stencilSupport) {
  1681     if (NULL == fPathRendererChain) {
  1682         fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
  1685     GrPathRenderer* pr = fPathRendererChain->getPathRenderer(path,
  1686                                                              stroke,
  1687                                                              target,
  1688                                                              drawType,
  1689                                                              stencilSupport);
  1691     if (NULL == pr && allowSW) {
  1692         if (NULL == fSoftwarePathRenderer) {
  1693             fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
  1695         pr = fSoftwarePathRenderer;
  1698     return pr;
  1701 ////////////////////////////////////////////////////////////////////////////////
  1702 bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const {
  1703     return fGpu->caps()->isConfigRenderable(config, withMSAA);
  1706 int GrContext::getRecommendedSampleCount(GrPixelConfig config,
  1707                                          SkScalar dpi) const {
  1708     if (!this->isConfigRenderable(config, true)) {
  1709         return 0;
  1711     int chosenSampleCount = 0;
  1712     if (fGpu->caps()->pathRenderingSupport()) {
  1713         if (dpi >= 250.0f) {
  1714             chosenSampleCount = 4;
  1715         } else {
  1716             chosenSampleCount = 16;
  1719     return chosenSampleCount <= fGpu->caps()->maxSampleCount() ?
  1720         chosenSampleCount : 0;
  1723 void GrContext::setupDrawBuffer() {
  1724     SkASSERT(NULL == fDrawBuffer);
  1725     SkASSERT(NULL == fDrawBufferVBAllocPool);
  1726     SkASSERT(NULL == fDrawBufferIBAllocPool);
  1728     fDrawBufferVBAllocPool =
  1729         SkNEW_ARGS(GrVertexBufferAllocPool, (fGpu, false,
  1730                                     DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
  1731                                     DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS));
  1732     fDrawBufferIBAllocPool =
  1733         SkNEW_ARGS(GrIndexBufferAllocPool, (fGpu, false,
  1734                                    DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
  1735                                    DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS));
  1737     fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (fGpu,
  1738                                                    fDrawBufferVBAllocPool,
  1739                                                    fDrawBufferIBAllocPool));
  1741     fDrawBuffer->setDrawState(fDrawState);
  1744 GrDrawTarget* GrContext::getTextTarget() {
  1745     return this->prepareToDraw(NULL, BUFFERED_DRAW, NULL, NULL);
  1748 const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
  1749     return fGpu->getQuadIndexBuffer();
  1752 namespace {
  1753 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
  1754     GrConfigConversionEffect::PMConversion pmToUPM;
  1755     GrConfigConversionEffect::PMConversion upmToPM;
  1756     GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
  1757     *pmToUPMValue = pmToUPM;
  1758     *upmToPMValue = upmToPM;
  1762 const GrEffectRef* GrContext::createPMToUPMEffect(GrTexture* texture,
  1763                                                   bool swapRAndB,
  1764                                                   const SkMatrix& matrix) {
  1765     if (!fDidTestPMConversions) {
  1766         test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
  1767         fDidTestPMConversions = true;
  1769     GrConfigConversionEffect::PMConversion pmToUPM =
  1770         static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
  1771     if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
  1772         return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, matrix);
  1773     } else {
  1774         return NULL;
  1778 const GrEffectRef* GrContext::createUPMToPMEffect(GrTexture* texture,
  1779                                                   bool swapRAndB,
  1780                                                   const SkMatrix& matrix) {
  1781     if (!fDidTestPMConversions) {
  1782         test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
  1783         fDidTestPMConversions = true;
  1785     GrConfigConversionEffect::PMConversion upmToPM =
  1786         static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
  1787     if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
  1788         return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, matrix);
  1789     } else {
  1790         return NULL;
  1794 GrPath* GrContext::createPath(const SkPath& inPath, const SkStrokeRec& stroke) {
  1795     SkASSERT(fGpu->caps()->pathRenderingSupport());
  1797     // TODO: now we add to fTextureCache. This should change to fResourceCache.
  1798     GrResourceKey resourceKey = GrPath::ComputeKey(inPath, stroke);
  1799     GrPath* path = static_cast<GrPath*>(fTextureCache->find(resourceKey));
  1800     if (NULL != path && path->isEqualTo(inPath, stroke)) {
  1801         path->ref();
  1802     } else {
  1803         path = fGpu->createPath(inPath, stroke);
  1804         fTextureCache->purgeAsNeeded(1, path->sizeInBytes());
  1805         fTextureCache->addResource(resourceKey, path);
  1807     return path;
  1810 ///////////////////////////////////////////////////////////////////////////////
  1811 #if GR_CACHE_STATS
  1812 void GrContext::printCacheStats() const {
  1813     fTextureCache->printStats();
  1815 #endif

mercurial