Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "GrContext.h"
      9 #include "GrContextOptions.h"
     10 #include "GrDrawingManager.h"
     11 #include "GrDrawContext.h"
     12 #include "GrLayerCache.h"
     13 #include "GrResourceCache.h"
     14 #include "GrResourceProvider.h"
     15 #include "GrSoftwarePathRenderer.h"
     16 #include "GrSurfacePriv.h"
     17 
     18 #include "SkConfig8888.h"
     19 #include "SkGrPriv.h"
     20 
     21 #include "batches/GrCopySurfaceBatch.h"
     22 #include "effects/GrConfigConversionEffect.h"
     23 #include "text/GrTextBlobCache.h"
     24 
     25 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
     26 #define ASSERT_SINGLE_OWNER \
     27     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);)
     28 #define RETURN_IF_ABANDONED if (fDrawingManager->abandoned()) { return; }
     29 #define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->abandoned()) { return false; }
     30 #define RETURN_NULL_IF_ABANDONED if (fDrawingManager->abandoned()) { return nullptr; }
     31 
     32 ////////////////////////////////////////////////////////////////////////////////
     33 
     34 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
     35     GrContextOptions defaultOptions;
     36     return Create(backend, backendContext, defaultOptions);
     37 }
     38 
     39 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
     40                              const GrContextOptions& options) {
     41     GrContext* context = new GrContext;
     42 
     43     if (context->init(backend, backendContext, options)) {
     44         return context;
     45     } else {
     46         context->unref();
     47         return nullptr;
     48     }
     49 }
     50 
     51 static int32_t gNextID = 1;
     52 static int32_t next_id() {
     53     int32_t id;
     54     do {
     55         id = sk_atomic_inc(&gNextID);
     56     } while (id == SK_InvalidGenID);
     57     return id;
     58 }
     59 
     60 GrContext::GrContext() : fUniqueID(next_id()) {
     61     fGpu = nullptr;
     62     fCaps = nullptr;
     63     fResourceCache = nullptr;
     64     fResourceProvider = nullptr;
     65     fBatchFontCache = nullptr;
     66     fFlushToReduceCacheSize = false;
     67 }
     68 
     69 bool GrContext::init(GrBackend backend, GrBackendContext backendContext,
     70                      const GrContextOptions& options) {
     71     ASSERT_SINGLE_OWNER
     72     SkASSERT(!fGpu);
     73 
     74     fGpu = GrGpu::Create(backend, backendContext, options, this);
     75     if (!fGpu) {
     76         return false;
     77     }
     78     this->initCommon(options);
     79     return true;
     80 }
     81 
     82 void GrContext::initCommon(const GrContextOptions& options) {
     83     ASSERT_SINGLE_OWNER
     84 
     85     fCaps = SkRef(fGpu->caps());
     86     fResourceCache = new GrResourceCache(fCaps);
     87     fResourceCache->setOverBudgetCallback(OverBudgetCB, this);
     88     fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner);
     89 
     90     fLayerCache.reset(new GrLayerCache(this));
     91 
     92     fDidTestPMConversions = false;
     93 
     94     GrDrawTarget::Options dtOptions;
     95     dtOptions.fClipBatchToBounds = options.fClipBatchToBounds;
     96     dtOptions.fDrawBatchBounds = options.fDrawBatchBounds;
     97     dtOptions.fMaxBatchLookback = options.fMaxBatchLookback;
     98     fDrawingManager.reset(new GrDrawingManager(this, dtOptions, &fSingleOwner));
     99 
    100     // GrBatchFontCache will eventually replace GrFontCache
    101     fBatchFontCache = new GrBatchFontCache(this);
    102 
    103     fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this));
    104 }
    105 
    106 GrContext::~GrContext() {
    107     ASSERT_SINGLE_OWNER
    108 
    109     if (!fGpu) {
    110         SkASSERT(!fCaps);
    111         return;
    112     }
    113 
    114     this->flush();
    115 
    116     fDrawingManager->cleanup();
    117 
    118     for (int i = 0; i < fCleanUpData.count(); ++i) {
    119         (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
    120     }
    121 
    122     delete fResourceProvider;
    123     delete fResourceCache;
    124     delete fBatchFontCache;
    125 
    126     fGpu->unref();
    127     fCaps->unref();
    128 }
    129 
    130 void GrContext::abandonContext() {
    131     ASSERT_SINGLE_OWNER
    132 
    133     fResourceProvider->abandon();
    134 
    135     // Need to abandon the drawing manager first so all the render targets
    136     // will be released/forgotten before they too are abandoned.
    137     fDrawingManager->abandon();
    138 
    139     // abandon first to so destructors
    140     // don't try to free the resources in the API.
    141     fResourceCache->abandonAll();
    142 
    143     fGpu->contextAbandoned();
    144 
    145     fBatchFontCache->freeAll();
    146     fLayerCache->freeAll();
    147     fTextBlobCache->freeAll();
    148 }
    149 
    150 void GrContext::resetContext(uint32_t state) {
    151     ASSERT_SINGLE_OWNER
    152     fGpu->markContextDirty(state);
    153 }
    154 
    155 void GrContext::freeGpuResources() {
    156     ASSERT_SINGLE_OWNER
    157 
    158     this->flush();
    159 
    160     fBatchFontCache->freeAll();
    161     fLayerCache->freeAll();
    162 
    163     fDrawingManager->freeGpuResources();
    164 
    165     fResourceCache->purgeAllUnlocked();
    166 }
    167 
    168 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
    169     ASSERT_SINGLE_OWNER
    170 
    171     if (resourceCount) {
    172         *resourceCount = fResourceCache->getBudgetedResourceCount();
    173     }
    174     if (resourceBytes) {
    175         *resourceBytes = fResourceCache->getBudgetedResourceBytes();
    176     }
    177 }
    178 
    179 ////////////////////////////////////////////////////////////////////////////////
    180 
    181 void GrContext::OverBudgetCB(void* data) {
    182     SkASSERT(data);
    183 
    184     GrContext* context = reinterpret_cast<GrContext*>(data);
    185 
    186     // Flush the GrBufferedDrawTarget to possibly free up some textures
    187     context->fFlushToReduceCacheSize = true;
    188 }
    189 
    190 void GrContext::TextBlobCacheOverBudgetCB(void* data) {
    191     SkASSERT(data);
    192 
    193     // Unlike the GrResourceCache, TextBlobs are drawn at the SkGpuDevice level, therefore they
    194     // cannot use fFlushTorReduceCacheSize because it uses AutoCheckFlush.  The solution is to move
    195     // drawText calls to below the GrContext level, but this is not trivial because they call
    196     // drawPath on SkGpuDevice
    197     GrContext* context = reinterpret_cast<GrContext*>(data);
    198     context->flush();
    199 }
    200 
    201 ////////////////////////////////////////////////////////////////////////////////
    202 
    203 void GrContext::flush(int flagsBitfield) {
    204     ASSERT_SINGLE_OWNER
    205     RETURN_IF_ABANDONED
    206 
    207     if (kDiscard_FlushBit & flagsBitfield) {
    208         fDrawingManager->reset();
    209     } else {
    210         fDrawingManager->flush();
    211     }
    212     fResourceCache->notifyFlushOccurred();
    213     fFlushToReduceCacheSize = false;
    214 }
    215 
    216 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
    217                           const void* inPixels, size_t outRowBytes, void* outPixels) {
    218     SkSrcPixelInfo srcPI;
    219     if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, nullptr)) {
    220         return false;
    221     }
    222     srcPI.fAlphaType = kUnpremul_SkAlphaType;
    223     srcPI.fPixels = inPixels;
    224     srcPI.fRowBytes = inRowBytes;
    225 
    226     SkDstPixelInfo dstPI;
    227     dstPI.fColorType = srcPI.fColorType;
    228     dstPI.fAlphaType = kPremul_SkAlphaType;
    229     dstPI.fPixels = outPixels;
    230     dstPI.fRowBytes = outRowBytes;
    231 
    232     return srcPI.convertPixelsTo(&dstPI, width, height);
    233 }
    234 
    235 bool GrContext::writeSurfacePixels(GrSurface* surface,
    236                                    int left, int top, int width, int height,
    237                                    GrPixelConfig srcConfig, const void* buffer, size_t rowBytes,
    238                                    uint32_t pixelOpsFlags) {
    239     ASSERT_SINGLE_OWNER
    240     RETURN_FALSE_IF_ABANDONED
    241     ASSERT_OWNED_RESOURCE(surface);
    242     SkASSERT(surface);
    243     GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::writeSurfacePixels");
    244 
    245     this->testPMConversionsIfNecessary(pixelOpsFlags);
    246 
    247     // Trim the params here so that if we wind up making a temporary surface it can be as small as
    248     // necessary and because GrGpu::getWritePixelsInfo requires it.
    249     if (!GrSurfacePriv::AdjustWritePixelParams(surface->width(), surface->height(),
    250                                                GrBytesPerPixel(srcConfig), &left, &top, &width,
    251                                                &height, &buffer, &rowBytes)) {
    252         return false;
    253     }
    254 
    255     bool applyPremulToSrc = false;
    256     if (kUnpremul_PixelOpsFlag & pixelOpsFlags) {
    257         if (!GrPixelConfigIs8888(srcConfig)) {
    258             return false;
    259         }
    260         applyPremulToSrc = true;
    261     }
    262 
    263     GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
    264     // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when
    265     // we've already determined that there isn't a roundtrip preserving conversion processor pair.
    266     if (applyPremulToSrc && !this->didFailPMUPMConversionTest()) {
    267         drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference;
    268     }
    269 
    270     GrGpu::WritePixelTempDrawInfo tempDrawInfo;
    271     if (!fGpu->getWritePixelsInfo(surface, width, height, srcConfig, &drawPreference,
    272                                   &tempDrawInfo)) {
    273         return false;
    274     }
    275 
    276     if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && surface->surfacePriv().hasPendingIO()) {
    277         this->flush();
    278     }
    279 
    280     SkAutoTUnref<GrTexture> tempTexture;
    281     if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
    282         tempTexture.reset(
    283             this->textureProvider()->createApproxTexture(tempDrawInfo.fTempSurfaceDesc));
    284         if (!tempTexture && GrGpu::kRequireDraw_DrawPreference == drawPreference) {
    285             return false;
    286         }
    287     }
    288 
    289     // temp buffer for doing sw premul conversion, if needed.
    290     SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
    291     if (tempTexture) {
    292         SkAutoTUnref<const GrFragmentProcessor> fp;
    293         SkMatrix textureMatrix;
    294         textureMatrix.setIDiv(tempTexture->width(), tempTexture->height());
    295         if (applyPremulToSrc) {
    296             fp.reset(this->createUPMToPMEffect(tempTexture, tempDrawInfo.fSwizzle,
    297                                                textureMatrix));
    298             // If premultiplying was the only reason for the draw, fall back to a straight write.
    299             if (!fp) {
    300                 if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) {
    301                     tempTexture.reset(nullptr);
    302                 }
    303             } else {
    304                 applyPremulToSrc = false;
    305             }
    306         }
    307         if (tempTexture) {
    308             if (!fp) {
    309                 fp.reset(GrConfigConversionEffect::Create(tempTexture, tempDrawInfo.fSwizzle,
    310                     GrConfigConversionEffect::kNone_PMConversion, textureMatrix));
    311                 if (!fp) {
    312                     return false;
    313                 }
    314             }
    315             GrRenderTarget* renderTarget = surface->asRenderTarget();
    316             SkASSERT(renderTarget);
    317             if (tempTexture->surfacePriv().hasPendingIO()) {
    318                 this->flush();
    319             }
    320             if (applyPremulToSrc) {
    321                 size_t tmpRowBytes = 4 * width;
    322                 tmpPixels.reset(width * height);
    323                 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
    324                                           tmpPixels.get())) {
    325                     return false;
    326                 }
    327                 rowBytes = tmpRowBytes;
    328                 buffer = tmpPixels.get();
    329                 applyPremulToSrc = false;
    330             }
    331             if (!fGpu->writePixels(tempTexture, 0, 0, width, height,
    332                                    tempDrawInfo.fWriteConfig, buffer,
    333                                    rowBytes)) {
    334                 return false;
    335             }
    336             SkMatrix matrix;
    337             matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
    338             SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(renderTarget));
    339             if (!drawContext) {
    340                 return false;
    341             }
    342             GrPaint paint;
    343             paint.addColorFragmentProcessor(fp);
    344             paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
    345             SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
    346             drawContext->drawRect(GrClip::WideOpen(), paint, matrix, rect, nullptr);
    347 
    348             if (kFlushWrites_PixelOp & pixelOpsFlags) {
    349                 this->flushSurfaceWrites(surface);
    350             }
    351         }
    352     }
    353     if (!tempTexture) {
    354         if (applyPremulToSrc) {
    355             size_t tmpRowBytes = 4 * width;
    356             tmpPixels.reset(width * height);
    357             if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
    358                                       tmpPixels.get())) {
    359                 return false;
    360             }
    361             rowBytes = tmpRowBytes;
    362             buffer = tmpPixels.get();
    363             applyPremulToSrc = false;
    364         }
    365         return fGpu->writePixels(surface, left, top, width, height, srcConfig, buffer, rowBytes);
    366     }
    367     return true;
    368 }
    369 
    370 bool GrContext::readSurfacePixels(GrSurface* src,
    371                                   int left, int top, int width, int height,
    372                                   GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
    373                                   uint32_t flags) {
    374     ASSERT_SINGLE_OWNER
    375     RETURN_FALSE_IF_ABANDONED
    376     ASSERT_OWNED_RESOURCE(src);
    377     SkASSERT(src);
    378     GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::readSurfacePixels");
    379 
    380     this->testPMConversionsIfNecessary(flags);
    381     SkAutoMutexAcquire ama(fReadPixelsMutex);
    382 
    383     // Adjust the params so that if we wind up using an intermediate surface we've already done
    384     // all the trimming and the temporary can be the min size required.
    385     if (!GrSurfacePriv::AdjustReadPixelParams(src->width(), src->height(),
    386                                               GrBytesPerPixel(dstConfig), &left,
    387                                               &top, &width, &height, &buffer, &rowBytes)) {
    388         return false;
    389     }
    390 
    391     if (!(kDontFlush_PixelOpsFlag & flags) && src->surfacePriv().hasPendingWrite()) {
    392         this->flush();
    393     }
    394 
    395     bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
    396     if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
    397         // The unpremul flag is only allowed for 8888 configs.
    398         return false;
    399     }
    400 
    401     GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
    402     // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when
    403     // we've already determined that there isn't a roundtrip preserving conversion processor pair.
    404     if (unpremul && !this->didFailPMUPMConversionTest()) {
    405         drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference;
    406     }
    407 
    408     GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
    409     if (!fGpu->getReadPixelsInfo(src, width, height, rowBytes, dstConfig, &drawPreference,
    410                                  &tempDrawInfo)) {
    411         return false;
    412     }
    413 
    414     SkAutoTUnref<GrSurface> surfaceToRead(SkRef(src));
    415     bool didTempDraw = false;
    416     if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
    417         if (tempDrawInfo.fUseExactScratch) {
    418             // We only respect this when the entire src is being read. Otherwise we can trigger too
    419             // many odd ball texture sizes and trash the cache.
    420             if (width != src->width() || height != src->height()) {
    421                 tempDrawInfo.fUseExactScratch = false;
    422             }
    423         }
    424         SkAutoTUnref<GrTexture> temp;
    425         if (tempDrawInfo.fUseExactScratch) {
    426             temp.reset(this->textureProvider()->createTexture(tempDrawInfo.fTempSurfaceDesc,
    427                                                               SkBudgeted::kYes));
    428         } else {
    429             temp.reset(this->textureProvider()->createApproxTexture(tempDrawInfo.fTempSurfaceDesc));
    430         }
    431         if (temp) {
    432             SkMatrix textureMatrix;
    433             textureMatrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
    434             textureMatrix.postIDiv(src->width(), src->height());
    435             SkAutoTUnref<const GrFragmentProcessor> fp;
    436             if (unpremul) {
    437                 fp.reset(this->createPMToUPMEffect(src->asTexture(), tempDrawInfo.fSwizzle,
    438                     textureMatrix));
    439                 if (fp) {
    440                     unpremul = false; // we no longer need to do this on CPU after the read back.
    441                 } else if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) {
    442                     // We only wanted to do the draw in order to perform the unpremul so don't
    443                     // bother.
    444                     temp.reset(nullptr);
    445                 }
    446             }
    447             if (!fp && temp) {
    448                 fp.reset(GrConfigConversionEffect::Create(src->asTexture(), tempDrawInfo.fSwizzle,
    449                     GrConfigConversionEffect::kNone_PMConversion, textureMatrix));
    450             }
    451             if (fp) {
    452                 GrPaint paint;
    453                 paint.addColorFragmentProcessor(fp);
    454                 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
    455                 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
    456                 SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(temp->asRenderTarget()));
    457                 drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, nullptr);
    458                 surfaceToRead.reset(SkRef(temp.get()));
    459                 left = 0;
    460                 top = 0;
    461                 didTempDraw = true;
    462             }
    463         }
    464     }
    465 
    466     if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) {
    467         return false;
    468     }
    469     GrPixelConfig configToRead = dstConfig;
    470     if (didTempDraw) {
    471         this->flushSurfaceWrites(surfaceToRead);
    472         configToRead = tempDrawInfo.fReadConfig;
    473     }
    474     if (!fGpu->readPixels(surfaceToRead, left, top, width, height, configToRead, buffer,
    475                            rowBytes)) {
    476         return false;
    477     }
    478 
    479     // Perform umpremul conversion if we weren't able to perform it as a draw.
    480     if (unpremul) {
    481         SkDstPixelInfo dstPI;
    482         if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, nullptr)) {
    483             return false;
    484         }
    485         dstPI.fAlphaType = kUnpremul_SkAlphaType;
    486         dstPI.fPixels = buffer;
    487         dstPI.fRowBytes = rowBytes;
    488 
    489         SkSrcPixelInfo srcPI;
    490         srcPI.fColorType = dstPI.fColorType;
    491         srcPI.fAlphaType = kPremul_SkAlphaType;
    492         srcPI.fPixels = buffer;
    493         srcPI.fRowBytes = rowBytes;
    494 
    495         return srcPI.convertPixelsTo(&dstPI, width, height);
    496     }
    497     return true;
    498 }
    499 
    500 void GrContext::prepareSurfaceForExternalIO(GrSurface* surface) {
    501     ASSERT_SINGLE_OWNER
    502     RETURN_IF_ABANDONED
    503     SkASSERT(surface);
    504     ASSERT_OWNED_RESOURCE(surface);
    505     if (surface->surfacePriv().hasPendingIO()) {
    506         this->flush();
    507     }
    508     GrRenderTarget* rt = surface->asRenderTarget();
    509     if (fGpu && rt) {
    510         fGpu->resolveRenderTarget(rt);
    511     }
    512 }
    513 
    514 bool GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
    515                             const SkIPoint& dstPoint) {
    516     ASSERT_SINGLE_OWNER
    517     RETURN_FALSE_IF_ABANDONED
    518     GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::copySurface");
    519 
    520     if (!src || !dst) {
    521         return false;
    522     }
    523     ASSERT_OWNED_RESOURCE(src);
    524     ASSERT_OWNED_RESOURCE(dst);
    525 
    526     if (!dst->asRenderTarget()) {
    527         SkIRect clippedSrcRect;
    528         SkIPoint clippedDstPoint;
    529         if (!GrCopySurfaceBatch::ClipSrcRectAndDstPoint(dst, src, srcRect, dstPoint,
    530                                                         &clippedSrcRect, &clippedDstPoint)) {
    531             return false;
    532         }
    533         // If we don't have an RT for the dst then we won't have a GrDrawContext to insert the
    534         // the copy surface into. In the future we plan to have a more limited Context type
    535         // (GrCopyContext?) that has the subset of GrDrawContext operations that should be
    536         // allowed on textures that aren't render targets.
    537         // For now we just flush any writes to the src and issue an immediate copy to the dst.
    538         src->flushWrites();
    539         return fGpu->copySurface(dst, src, clippedSrcRect, clippedDstPoint);
    540     }
    541     SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(dst->asRenderTarget()));
    542     if (!drawContext) {
    543         return false;
    544     }
    545 
    546     if (!drawContext->copySurface(src, srcRect, dstPoint)) {
    547         return false;
    548     }
    549     return true;
    550 }
    551 
    552 void GrContext::flushSurfaceWrites(GrSurface* surface) {
    553     ASSERT_SINGLE_OWNER
    554     RETURN_IF_ABANDONED
    555     if (surface->surfacePriv().hasPendingWrite()) {
    556         this->flush();
    557     }
    558 }
    559 
    560 ////////////////////////////////////////////////////////////////////////////////
    561 int GrContext::getRecommendedSampleCount(GrPixelConfig config,
    562                                          SkScalar dpi) const {
    563     ASSERT_SINGLE_OWNER
    564 
    565     if (!this->caps()->isConfigRenderable(config, true)) {
    566         return 0;
    567     }
    568     int chosenSampleCount = 0;
    569     if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) {
    570         if (dpi >= 250.0f) {
    571             chosenSampleCount = 4;
    572         } else {
    573             chosenSampleCount = 16;
    574         }
    575     }
    576     return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? chosenSampleCount : 0;
    577 }
    578 
    579 
    580 GrDrawContext* GrContext::drawContext(GrRenderTarget* rt, const SkSurfaceProps* surfaceProps) {
    581     ASSERT_SINGLE_OWNER
    582     return fDrawingManager->drawContext(rt, surfaceProps);
    583 }
    584 
    585 bool GrContext::abandoned() const {
    586     ASSERT_SINGLE_OWNER
    587     return fDrawingManager->abandoned();
    588 }
    589 
    590 namespace {
    591 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
    592     GrConfigConversionEffect::PMConversion pmToUPM;
    593     GrConfigConversionEffect::PMConversion upmToPM;
    594     GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
    595     *pmToUPMValue = pmToUPM;
    596     *upmToPMValue = upmToPM;
    597 }
    598 }
    599 
    600 void GrContext::testPMConversionsIfNecessary(uint32_t flags) {
    601     ASSERT_SINGLE_OWNER
    602     if (SkToBool(kUnpremul_PixelOpsFlag & flags)) {
    603         SkAutoMutexAcquire ama(fTestPMConversionsMutex);
    604         if (!fDidTestPMConversions) {
    605             test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
    606             fDidTestPMConversions = true;
    607         }
    608     }
    609 }
    610 
    611 const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture,
    612                                                           const GrSwizzle& swizzle,
    613                                                           const SkMatrix& matrix) const {
    614     ASSERT_SINGLE_OWNER
    615     // We should have already called this->testPMConversionsIfNecessary().
    616     SkASSERT(fDidTestPMConversions);
    617     GrConfigConversionEffect::PMConversion pmToUPM =
    618         static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
    619     if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
    620         return GrConfigConversionEffect::Create(texture, swizzle, pmToUPM, matrix);
    621     } else {
    622         return nullptr;
    623     }
    624 }
    625 
    626 const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
    627                                                           const GrSwizzle& swizzle,
    628                                                           const SkMatrix& matrix) const {
    629     ASSERT_SINGLE_OWNER
    630     // We should have already called this->testPMConversionsIfNecessary().
    631     SkASSERT(fDidTestPMConversions);
    632     GrConfigConversionEffect::PMConversion upmToPM =
    633         static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
    634     if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
    635         return GrConfigConversionEffect::Create(texture, swizzle, upmToPM, matrix);
    636     } else {
    637         return nullptr;
    638     }
    639 }
    640 
    641 bool GrContext::didFailPMUPMConversionTest() const {
    642     ASSERT_SINGLE_OWNER
    643     // We should have already called this->testPMConversionsIfNecessary().
    644     SkASSERT(fDidTestPMConversions);
    645     // The PM<->UPM tests fail or succeed together so we only need to check one.
    646     return GrConfigConversionEffect::kNone_PMConversion == fPMToUPMConversion;
    647 }
    648 
    649 //////////////////////////////////////////////////////////////////////////////
    650 
    651 void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
    652     ASSERT_SINGLE_OWNER
    653     if (maxTextures) {
    654         *maxTextures = fResourceCache->getMaxResourceCount();
    655     }
    656     if (maxTextureBytes) {
    657         *maxTextureBytes = fResourceCache->getMaxResourceBytes();
    658     }
    659 }
    660 
    661 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
    662     ASSERT_SINGLE_OWNER
    663     fResourceCache->setLimits(maxTextures, maxTextureBytes);
    664 }
    665 
    666 //////////////////////////////////////////////////////////////////////////////
    667 
    668 void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
    669     ASSERT_SINGLE_OWNER
    670     fResourceCache->dumpMemoryStatistics(traceMemoryDump);
    671 }
    672