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 "GrBackendSemaphore.h"
      9 #include "GrContext.h"
     10 #include "GrClip.h"
     11 #include "GrContextOptions.h"
     12 #include "GrContextPriv.h"
     13 #include "GrDrawingManager.h"
     14 #include "GrGpu.h"
     15 #include "GrProxyProvider.h"
     16 #include "GrRenderTargetContext.h"
     17 #include "GrRenderTargetProxy.h"
     18 #include "GrResourceCache.h"
     19 #include "GrResourceProvider.h"
     20 #include "GrSemaphore.h"
     21 #include "GrSoftwarePathRenderer.h"
     22 #include "GrSurfaceContext.h"
     23 #include "GrSurfacePriv.h"
     24 #include "GrSurfaceProxyPriv.h"
     25 #include "GrTexture.h"
     26 #include "GrTextureContext.h"
     27 #include "GrTracing.h"
     28 
     29 #include "SkConvertPixels.h"
     30 #include "SkDeferredDisplayList.h"
     31 #include "SkGr.h"
     32 #include "SkJSONWriter.h"
     33 #include "SkMakeUnique.h"
     34 #include "SkTaskGroup.h"
     35 #include "SkUnPreMultiplyPriv.h"
     36 #include "effects/GrConfigConversionEffect.h"
     37 #include "text/GrTextBlobCache.h"
     38 
     39 #include "gl/GrGLGpu.h"
     40 #include "mock/GrMockGpu.h"
     41 #ifdef SK_METAL
     42 #include "mtl/GrMtlTrampoline.h"
     43 #endif
     44 #include "ddl/GrDDLGpu.h"
     45 #ifdef SK_VULKAN
     46 #include "vk/GrVkGpu.h"
     47 #endif
     48 
     49 #define ASSERT_OWNED_PROXY(P) \
     50 SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == this)
     51 #define ASSERT_OWNED_PROXY_PRIV(P) \
     52 SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == fContext)
     53 
     54 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
     55 #define ASSERT_SINGLE_OWNER \
     56     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);)
     57 #define ASSERT_SINGLE_OWNER_PRIV \
     58     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fContext->fSingleOwner);)
     59 #define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; }
     60 #define RETURN_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return; }
     61 #define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; }
     62 #define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return false; }
     63 #define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; }
     64 
     65 ////////////////////////////////////////////////////////////////////////////////
     66 
     67 class SK_API GrDirectContext : public GrContext {
     68 public:
     69     GrDirectContext(GrBackend backend) : INHERITED(backend) { }
     70 
     71 protected:
     72 
     73 private:
     74     typedef GrContext INHERITED;
     75 };
     76 
     77 class SK_API GrDDLContext : public GrContext {
     78 public:
     79     GrDDLContext(GrContextThreadSafeProxy* proxy) : INHERITED(proxy) {}
     80 
     81 protected:
     82 
     83 private:
     84     typedef GrContext INHERITED;
     85 };
     86 
     87 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
     88     GrContextOptions defaultOptions;
     89     return Create(backend, backendContext, defaultOptions);
     90 }
     91 
     92 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
     93                              const GrContextOptions& options) {
     94 
     95     sk_sp<GrContext> context(new GrDirectContext(backend));
     96 
     97     context->fGpu = GrGpu::Make(backend, backendContext, options, context.get());
     98     if (!context->fGpu) {
     99         return nullptr;
    100     }
    101 
    102     if (!context->init(options)) {
    103         return nullptr;
    104     }
    105 
    106     return context.release();
    107 }
    108 
    109 sk_sp<GrContext> GrContext::MakeGL(sk_sp<const GrGLInterface> interface) {
    110     GrContextOptions defaultOptions;
    111     return MakeGL(std::move(interface), defaultOptions);
    112 }
    113 
    114 sk_sp<GrContext> GrContext::MakeGL(sk_sp<const GrGLInterface> interface,
    115                                    const GrContextOptions& options) {
    116     sk_sp<GrContext> context(new GrDirectContext(kOpenGL_GrBackend));
    117 
    118     context->fGpu = GrGLGpu::Make(std::move(interface), options, context.get());
    119     if (!context->fGpu) {
    120         return nullptr;
    121     }
    122     if (!context->init(options)) {
    123         return nullptr;
    124     }
    125     return context;
    126 }
    127 
    128 sk_sp<GrContext> GrContext::MakeGL(const GrGLInterface* interface) {
    129     return MakeGL(sk_ref_sp(interface));
    130 }
    131 
    132 sk_sp<GrContext> GrContext::MakeGL(const GrGLInterface* interface,
    133                                    const GrContextOptions& options) {
    134     return MakeGL(sk_ref_sp(interface), options);
    135 }
    136 
    137 sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions) {
    138     GrContextOptions defaultOptions;
    139     return MakeMock(mockOptions, defaultOptions);
    140 }
    141 
    142 sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions,
    143                                      const GrContextOptions& options) {
    144     sk_sp<GrContext> context(new GrDirectContext(kMock_GrBackend));
    145 
    146     context->fGpu = GrMockGpu::Make(mockOptions, options, context.get());
    147     if (!context->fGpu) {
    148         return nullptr;
    149     }
    150     if (!context->init(options)) {
    151         return nullptr;
    152     }
    153     return context;
    154 }
    155 
    156 #ifdef SK_VULKAN
    157 sk_sp<GrContext> GrContext::MakeVulkan(sk_sp<const GrVkBackendContext> backendContext) {
    158     GrContextOptions defaultOptions;
    159     return MakeVulkan(std::move(backendContext), defaultOptions);
    160 }
    161 
    162 sk_sp<GrContext> GrContext::MakeVulkan(sk_sp<const GrVkBackendContext> backendContext,
    163                                        const GrContextOptions& options) {
    164     sk_sp<GrContext> context(new GrDirectContext(kVulkan_GrBackend));
    165 
    166     context->fGpu = GrVkGpu::Make(std::move(backendContext), options, context.get());
    167     if (!context->fGpu) {
    168         return nullptr;
    169     }
    170     if (!context->init(options)) {
    171         return nullptr;
    172     }
    173     return context;
    174 }
    175 #endif
    176 
    177 #ifdef SK_METAL
    178 sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue) {
    179     GrContextOptions defaultOptions;
    180     return MakeMetal(device, queue, defaultOptions);
    181 }
    182 
    183 sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue, const GrContextOptions& options) {
    184     sk_sp<GrContext> context(new GrContext(kMetal_GrBackend));
    185 
    186     context->fGpu = GrMtlTrampoline::MakeGpu(context.get(), options, device, queue);
    187     if (!context->fGpu) {
    188         return nullptr;
    189     }
    190     if (!context->init(options)) {
    191         return nullptr;
    192     }
    193     return context;
    194 }
    195 #endif
    196 
    197 static int32_t gNextID = 1;
    198 static int32_t next_id() {
    199     int32_t id;
    200     do {
    201         id = sk_atomic_inc(&gNextID);
    202     } while (id == SK_InvalidGenID);
    203     return id;
    204 }
    205 
    206 sk_sp<GrContext> GrContextPriv::MakeDDL(GrContextThreadSafeProxy* proxy) {
    207     sk_sp<GrContext> context(new GrDDLContext(proxy));
    208 
    209     // Note: we aren't creating a Gpu here. This causes the resource provider & cache to
    210     // also not be created
    211     if (!context->init(proxy->fOptions)) {
    212         return nullptr;
    213     }
    214     return context;
    215 }
    216 
    217 GrContext::GrContext(GrBackend backend)
    218         : fUniqueID(next_id())
    219         , fBackend(backend) {
    220     fResourceCache = nullptr;
    221     fResourceProvider = nullptr;
    222     fProxyProvider = nullptr;
    223     fAtlasGlyphCache = nullptr;
    224 }
    225 
    226 GrContext::GrContext(GrContextThreadSafeProxy* proxy)
    227         : fCaps(proxy->fCaps)
    228         , fUniqueID(proxy->fContextUniqueID)
    229         , fBackend(proxy->fBackend) {
    230     fResourceCache = nullptr;
    231     fResourceProvider = nullptr;
    232     fProxyProvider = nullptr;
    233     fAtlasGlyphCache = nullptr;
    234 }
    235 
    236 bool GrContext::init(const GrContextOptions& options) {
    237     ASSERT_SINGLE_OWNER
    238 
    239     if (fGpu) {
    240         fCaps = fGpu->refCaps();
    241         fResourceCache = new GrResourceCache(fCaps.get(), fUniqueID);
    242         fResourceProvider = new GrResourceProvider(fGpu.get(), fResourceCache, &fSingleOwner);
    243     }
    244 
    245     fProxyProvider = new GrProxyProvider(fResourceProvider, fResourceCache, fCaps, &fSingleOwner);
    246 
    247     if (fResourceCache) {
    248         fResourceCache->setProxyProvider(fProxyProvider);
    249     }
    250 
    251     // DDL TODO: we need to think through how the task group & persistent cache
    252     // get passed on to/shared between all the DDLRecorders created with this context.
    253     fThreadSafeProxy.reset(new GrContextThreadSafeProxy(fCaps, this->uniqueID(), fBackend,
    254                                                         options));
    255 
    256     fDisableGpuYUVConversion = options.fDisableGpuYUVConversion;
    257     fDidTestPMConversions = false;
    258 
    259     GrPathRendererChain::Options prcOptions;
    260     prcOptions.fAllowPathMaskCaching = options.fAllowPathMaskCaching;
    261 #if GR_TEST_UTILS
    262     prcOptions.fGpuPathRenderers = options.fGpuPathRenderers;
    263 #endif
    264     if (options.fDisableDistanceFieldPaths) {
    265         prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall;
    266     }
    267 
    268     if (!fResourceCache) {
    269         // DDL TODO: remove this crippling of the path renderer chain
    270         // Disable the small path renderer bc of the proxies in the atlas. They need to be
    271         // unified when the opLists are added back to the destination drawing manager.
    272         prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall;
    273     }
    274 
    275     GrAtlasTextContext::Options atlasTextContextOptions;
    276     atlasTextContextOptions.fMaxDistanceFieldFontSize = options.fGlyphsAsPathsFontSize;
    277     atlasTextContextOptions.fMinDistanceFieldFontSize = options.fMinDistanceFieldFontSize;
    278     atlasTextContextOptions.fDistanceFieldVerticesAlwaysHaveW = false;
    279 #if SK_SUPPORT_ATLAS_TEXT
    280     if (GrContextOptions::Enable::kYes == options.fDistanceFieldGlyphVerticesAlwaysHaveW) {
    281         atlasTextContextOptions.fDistanceFieldVerticesAlwaysHaveW = true;
    282     }
    283 #endif
    284 
    285     fDrawingManager.reset(
    286             new GrDrawingManager(this, prcOptions, atlasTextContextOptions, &fSingleOwner));
    287 
    288     GrDrawOpAtlas::AllowMultitexturing allowMultitexturing;
    289     if (GrContextOptions::Enable::kNo == options.fAllowMultipleGlyphCacheTextures ||
    290         // multitexturing supported only if range can represent the index + texcoords fully
    291         !(fCaps->shaderCaps()->floatIs32Bits() || fCaps->shaderCaps()->integerSupport())) {
    292         allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kNo;
    293     } else {
    294         allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kYes;
    295     }
    296     fAtlasGlyphCache = new GrAtlasGlyphCache(this, options.fGlyphCacheTextureMaximumBytes,
    297                                              allowMultitexturing);
    298     this->contextPriv().addOnFlushCallbackObject(fAtlasGlyphCache);
    299 
    300     fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this, this->uniqueID()));
    301 
    302     if (options.fExecutor) {
    303         fTaskGroup = skstd::make_unique<SkTaskGroup>(*options.fExecutor);
    304     }
    305 
    306     fPersistentCache = options.fPersistentCache;
    307 
    308     return true;
    309 }
    310 
    311 GrContext::~GrContext() {
    312     ASSERT_SINGLE_OWNER
    313 
    314     if (fGpu) {
    315         this->flush();
    316     }
    317 
    318     if (fDrawingManager) {
    319         fDrawingManager->cleanup();
    320     }
    321 
    322     for (int i = 0; i < fCleanUpData.count(); ++i) {
    323         (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
    324     }
    325 
    326     delete fResourceProvider;
    327     delete fResourceCache;
    328     delete fProxyProvider;
    329     delete fAtlasGlyphCache;
    330 }
    331 
    332 sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
    333     return fThreadSafeProxy;
    334 }
    335 
    336 void GrContext::abandonContext() {
    337     ASSERT_SINGLE_OWNER
    338 
    339     fProxyProvider->abandon();
    340     fResourceProvider->abandon();
    341 
    342     // Need to abandon the drawing manager first so all the render targets
    343     // will be released/forgotten before they too are abandoned.
    344     fDrawingManager->abandon();
    345 
    346     // abandon first to so destructors
    347     // don't try to free the resources in the API.
    348     fResourceCache->abandonAll();
    349 
    350     fGpu->disconnect(GrGpu::DisconnectType::kAbandon);
    351 
    352     fAtlasGlyphCache->freeAll();
    353     fTextBlobCache->freeAll();
    354 }
    355 
    356 void GrContext::releaseResourcesAndAbandonContext() {
    357     ASSERT_SINGLE_OWNER
    358 
    359     fProxyProvider->abandon();
    360     fResourceProvider->abandon();
    361 
    362     // Need to abandon the drawing manager first so all the render targets
    363     // will be released/forgotten before they too are abandoned.
    364     fDrawingManager->abandon();
    365 
    366     // Release all resources in the backend 3D API.
    367     fResourceCache->releaseAll();
    368 
    369     fGpu->disconnect(GrGpu::DisconnectType::kCleanup);
    370 
    371     fAtlasGlyphCache->freeAll();
    372     fTextBlobCache->freeAll();
    373 }
    374 
    375 void GrContext::resetContext(uint32_t state) {
    376     ASSERT_SINGLE_OWNER
    377     fGpu->markContextDirty(state);
    378 }
    379 
    380 void GrContext::freeGpuResources() {
    381     ASSERT_SINGLE_OWNER
    382 
    383     this->flush();
    384 
    385     fAtlasGlyphCache->freeAll();
    386 
    387     fDrawingManager->freeGpuResources();
    388 
    389     fResourceCache->purgeAllUnlocked();
    390 }
    391 
    392 void GrContext::performDeferredCleanup(std::chrono::milliseconds msNotUsed) {
    393     ASSERT_SINGLE_OWNER
    394     fResourceCache->purgeAsNeeded();
    395     fResourceCache->purgeResourcesNotUsedSince(GrStdSteadyClock::now() - msNotUsed);
    396 
    397     fTextBlobCache->purgeStaleBlobs();
    398 }
    399 
    400 void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
    401     ASSERT_SINGLE_OWNER
    402     fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources);
    403 }
    404 
    405 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
    406     ASSERT_SINGLE_OWNER
    407 
    408     if (resourceCount) {
    409         *resourceCount = fResourceCache->getBudgetedResourceCount();
    410     }
    411     if (resourceBytes) {
    412         *resourceBytes = fResourceCache->getBudgetedResourceBytes();
    413     }
    414 }
    415 
    416 size_t GrContext::getResourceCachePurgeableBytes() const {
    417     ASSERT_SINGLE_OWNER
    418     return fResourceCache->getPurgeableBytes();
    419 }
    420 
    421 ////////////////////////////////////////////////////////////////////////////////
    422 
    423 void GrContext::TextBlobCacheOverBudgetCB(void* data) {
    424     SkASSERT(data);
    425     // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on
    426     // GrRenderTargetContext to perform a necessary flush.  The solution is to move drawText calls
    427     // to below the GrContext level, but this is not trivial because they call drawPath on
    428     // SkGpuDevice.
    429     GrContext* context = reinterpret_cast<GrContext*>(data);
    430     context->flush();
    431 }
    432 
    433 ////////////////////////////////////////////////////////////////////////////////
    434 
    435 void GrContext::flush() {
    436     ASSERT_SINGLE_OWNER
    437     RETURN_IF_ABANDONED
    438 
    439     fDrawingManager->flush(nullptr);
    440 }
    441 
    442 GrSemaphoresSubmitted GrContext::flushAndSignalSemaphores(int numSemaphores,
    443                                                           GrBackendSemaphore signalSemaphores[]) {
    444     ASSERT_SINGLE_OWNER
    445     if (fDrawingManager->wasAbandoned()) { return GrSemaphoresSubmitted::kNo; }
    446 
    447     return fDrawingManager->flush(nullptr, numSemaphores, signalSemaphores);
    448 }
    449 
    450 void GrContextPriv::flush(GrSurfaceProxy* proxy) {
    451     ASSERT_SINGLE_OWNER_PRIV
    452     RETURN_IF_ABANDONED_PRIV
    453     ASSERT_OWNED_PROXY_PRIV(proxy);
    454 
    455     fContext->fDrawingManager->flush(proxy);
    456 }
    457 
    458 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
    459                           const void* inPixels, size_t outRowBytes, void* outPixels) {
    460     SkColorType colorType;
    461     if (!GrPixelConfigToColorType(srcConfig, &colorType) ||
    462         4 != SkColorTypeBytesPerPixel(colorType))
    463     {
    464         return false;
    465     }
    466 
    467     for (int y = 0; y < height; y++) {
    468         SkOpts::RGBA_to_rgbA((uint32_t*) outPixels, inPixels, width);
    469         outPixels = SkTAddOffset<void>(outPixels, outRowBytes);
    470         inPixels = SkTAddOffset<const void>(inPixels, inRowBytes);
    471     }
    472 
    473     return true;
    474 }
    475 
    476 static bool valid_premul_config(GrPixelConfig config) {
    477     return GrPixelConfigIs8888Unorm(config) || kRGBA_half_GrPixelConfig == config;
    478 }
    479 
    480 static bool valid_pixel_conversion(GrPixelConfig srcConfig, GrPixelConfig dstConfig,
    481                                    bool premulConversion) {
    482     // We don't allow conversion between integer configs and float/fixed configs.
    483     if (GrPixelConfigIsSint(srcConfig) != GrPixelConfigIsSint(dstConfig)) {
    484         return false;
    485     }
    486 
    487     // We only allow premul <-> unpremul conversions for some formats
    488     if (premulConversion && (!valid_premul_config(srcConfig) || !valid_premul_config(dstConfig))) {
    489         return false;
    490     }
    491 
    492     return true;
    493 }
    494 
    495 static bool pm_upm_must_round_trip(GrPixelConfig config, SkColorSpace* colorSpace) {
    496     return !colorSpace &&
    497            (kRGBA_8888_GrPixelConfig == config || kBGRA_8888_GrPixelConfig == config);
    498 }
    499 
    500 bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst,
    501                                        int left, int top, int width, int height,
    502                                        GrPixelConfig srcConfig, SkColorSpace* srcColorSpace,
    503                                        const void* buffer, size_t rowBytes,
    504                                        uint32_t pixelOpsFlags) {
    505     // TODO: Color space conversion
    506 
    507     ASSERT_SINGLE_OWNER_PRIV
    508     RETURN_FALSE_IF_ABANDONED_PRIV
    509     SkASSERT(dst);
    510     ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy());
    511     GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels", fContext);
    512 
    513     if (!dst->asSurfaceProxy()->instantiate(this->resourceProvider())) {
    514         return false;
    515     }
    516 
    517     GrSurfaceProxy* dstProxy = dst->asSurfaceProxy();
    518     GrSurface* dstSurface = dstProxy->priv().peekSurface();
    519 
    520     // The src is unpremul but the dst is premul -> premul the src before or as part of the write
    521     const bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
    522     if (!valid_pixel_conversion(srcConfig, dstProxy->config(), premul)) {
    523         return false;
    524     }
    525 
    526     // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
    527     // without any color spaces attached, and the caller wants us to premul.
    528     bool useConfigConversionEffect =
    529             premul && pm_upm_must_round_trip(srcConfig, srcColorSpace) &&
    530             pm_upm_must_round_trip(dstProxy->config(), dst->colorSpaceInfo().colorSpace());
    531 
    532     // Are we going to try to premul as part of a draw? For the non-legacy case, we always allow
    533     // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
    534     bool premulOnGpu = premul &&
    535                        (!useConfigConversionEffect || fContext->validPMUPMConversionExists());
    536 
    537     // Trim the params here so that if we wind up making a temporary surface it can be as small as
    538     // necessary and because GrGpu::getWritePixelsInfo requires it.
    539     if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(),
    540                                                GrBytesPerPixel(srcConfig), &left, &top, &width,
    541                                                &height, &buffer, &rowBytes)) {
    542         return false;
    543     }
    544 
    545     GrGpu::DrawPreference drawPreference = premulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
    546                                                        : GrGpu::kNoDraw_DrawPreference;
    547     GrGpu::WritePixelTempDrawInfo tempDrawInfo;
    548     if (!fContext->fGpu->getWritePixelsInfo(dstSurface, dstProxy->origin(), width, height,
    549                                             srcConfig, &drawPreference, &tempDrawInfo)) {
    550         return false;
    551     }
    552 
    553     if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) {
    554         this->flush(nullptr); // MDB TODO: tighten this
    555     }
    556 
    557     sk_sp<GrTextureProxy> tempProxy;
    558     if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
    559         tempProxy = this->proxyProvider()->createProxy(tempDrawInfo.fTempSurfaceDesc,
    560                                                        SkBackingFit::kApprox,
    561                                                        SkBudgeted::kYes);
    562         if (!tempProxy && GrGpu::kRequireDraw_DrawPreference == drawPreference) {
    563             return false;
    564         }
    565     }
    566 
    567     // temp buffer for doing sw premul conversion, if needed.
    568     SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
    569     // We need to do sw premul if we were unable to create a RT for drawing, or if we can't do the
    570     // premul on the GPU
    571     if (premul && (!tempProxy || !premulOnGpu)) {
    572         size_t tmpRowBytes = 4 * width;
    573         tmpPixels.reset(width * height);
    574         if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
    575                                   tmpPixels.get())) {
    576             return false;
    577         }
    578         rowBytes = tmpRowBytes;
    579         buffer = tmpPixels.get();
    580     }
    581 
    582     if (tempProxy) {
    583         auto fp = GrSimpleTextureEffect::Make(tempProxy, SkMatrix::I());
    584         if (premulOnGpu) {
    585             fp = fContext->createUPMToPMEffect(std::move(fp), useConfigConversionEffect);
    586         }
    587         fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
    588         if (!fp) {
    589             return false;
    590         }
    591 
    592         if (!tempProxy->instantiate(this->resourceProvider())) {
    593             return false;
    594         }
    595         GrTexture* texture = tempProxy->priv().peekTexture();
    596 
    597         if (tempProxy->priv().hasPendingIO()) {
    598             this->flush(tempProxy.get());
    599         }
    600 
    601         if (!fContext->fGpu->writePixels(texture, tempProxy->origin(), 0, 0, width, height,
    602                                          tempDrawInfo.fWriteConfig, buffer, rowBytes)) {
    603             return false;
    604         }
    605         tempProxy = nullptr;
    606 
    607         SkMatrix matrix;
    608         matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
    609         GrRenderTargetContext* renderTargetContext = dst->asRenderTargetContext();
    610         if (!renderTargetContext) {
    611             return false;
    612         }
    613         GrPaint paint;
    614         paint.addColorFragmentProcessor(std::move(fp));
    615         paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
    616         paint.setAllowSRGBInputs(dst->colorSpaceInfo().isGammaCorrect() ||
    617                                  GrPixelConfigIsSRGB(dst->colorSpaceInfo().config()));
    618         SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
    619         renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, rect,
    620                                         nullptr);
    621 
    622         if (kFlushWrites_PixelOp & pixelOpsFlags) {
    623             this->flushSurfaceWrites(renderTargetContext->asRenderTargetProxy());
    624         }
    625     } else {
    626         return fContext->fGpu->writePixels(dstSurface, dstProxy->origin(), left, top, width,
    627                                            height, srcConfig, buffer, rowBytes);
    628     }
    629     return true;
    630 }
    631 
    632 bool GrContextPriv::readSurfacePixels(GrSurfaceContext* src,
    633                                       int left, int top, int width, int height,
    634                                       GrPixelConfig dstConfig, SkColorSpace* dstColorSpace,
    635                                       void* buffer, size_t rowBytes, uint32_t flags) {
    636     // TODO: Color space conversion
    637 
    638     ASSERT_SINGLE_OWNER_PRIV
    639     RETURN_FALSE_IF_ABANDONED_PRIV
    640     SkASSERT(src);
    641     ASSERT_OWNED_PROXY_PRIV(src->asSurfaceProxy());
    642     GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "readSurfacePixels", fContext);
    643 
    644     // MDB TODO: delay this instantiation until later in the method
    645     if (!src->asSurfaceProxy()->instantiate(this->resourceProvider())) {
    646         return false;
    647     }
    648 
    649     GrSurfaceProxy* srcProxy = src->asSurfaceProxy();
    650     GrSurface* srcSurface = srcProxy->priv().peekSurface();
    651 
    652     // The src is premul but the dst is unpremul -> unpremul the src after or as part of the read
    653     bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
    654     if (!valid_pixel_conversion(srcProxy->config(), dstConfig, unpremul)) {
    655         return false;
    656     }
    657 
    658     // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
    659     // without any color spaces attached, and the caller wants us to unpremul.
    660     bool useConfigConversionEffect =
    661             unpremul &&
    662             pm_upm_must_round_trip(srcProxy->config(), src->colorSpaceInfo().colorSpace()) &&
    663             pm_upm_must_round_trip(dstConfig, dstColorSpace);
    664 
    665     // Are we going to try to unpremul as part of a draw? For the non-legacy case, we always allow
    666     // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
    667     bool unpremulOnGpu = unpremul &&
    668                          (!useConfigConversionEffect || fContext->validPMUPMConversionExists());
    669 
    670     // Adjust the params so that if we wind up using an intermediate surface we've already done
    671     // all the trimming and the temporary can be the min size required.
    672     if (!GrSurfacePriv::AdjustReadPixelParams(srcSurface->width(), srcSurface->height(),
    673                                               GrBytesPerPixel(dstConfig), &left,
    674                                               &top, &width, &height, &buffer, &rowBytes)) {
    675         return false;
    676     }
    677 
    678     GrGpu::DrawPreference drawPreference = unpremulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
    679                                                          : GrGpu::kNoDraw_DrawPreference;
    680     GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
    681     if (!fContext->fGpu->getReadPixelsInfo(srcSurface, srcProxy->origin(), width, height, rowBytes,
    682                                            dstConfig, &drawPreference, &tempDrawInfo)) {
    683         return false;
    684     }
    685 
    686     if (!(kDontFlush_PixelOpsFlag & flags) && srcSurface->surfacePriv().hasPendingWrite()) {
    687         this->flush(nullptr); // MDB TODO: tighten this
    688     }
    689 
    690     sk_sp<GrSurfaceProxy> proxyToRead = src->asSurfaceProxyRef();
    691     bool didTempDraw = false;
    692     if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
    693         if (SkBackingFit::kExact == tempDrawInfo.fTempSurfaceFit) {
    694             // We only respect this when the entire src is being read. Otherwise we can trigger too
    695             // many odd ball texture sizes and trash the cache.
    696             if (width != srcSurface->width() || height != srcSurface->height()) {
    697                 tempDrawInfo.fTempSurfaceFit= SkBackingFit::kApprox;
    698             }
    699         }
    700         // TODO: Need to decide the semantics of this function for color spaces. Do we support
    701         // conversion to a passed-in color space? For now, specifying nullptr means that this
    702         // path will do no conversion, so it will match the behavior of the non-draw path.
    703         sk_sp<GrRenderTargetContext> tempRTC = fContext->makeDeferredRenderTargetContext(
    704                                                            tempDrawInfo.fTempSurfaceFit,
    705                                                            tempDrawInfo.fTempSurfaceDesc.fWidth,
    706                                                            tempDrawInfo.fTempSurfaceDesc.fHeight,
    707                                                            tempDrawInfo.fTempSurfaceDesc.fConfig,
    708                                                            nullptr,
    709                                                            tempDrawInfo.fTempSurfaceDesc.fSampleCnt,
    710                                                            GrMipMapped::kNo,
    711                                                            tempDrawInfo.fTempSurfaceDesc.fOrigin);
    712         if (tempRTC) {
    713             // Adding discard to appease vulkan validation warning about loading uninitialized data
    714             // on draw
    715             tempRTC->discard();
    716             SkMatrix textureMatrix = SkMatrix::MakeTrans(SkIntToScalar(left), SkIntToScalar(top));
    717             sk_sp<GrTextureProxy> proxy = src->asTextureProxyRef();
    718             auto fp = GrSimpleTextureEffect::Make(std::move(proxy), textureMatrix);
    719             if (unpremulOnGpu) {
    720                 fp = fContext->createPMToUPMEffect(std::move(fp), useConfigConversionEffect);
    721                 // We no longer need to do this on CPU after the read back.
    722                 unpremul = false;
    723             }
    724             fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
    725             if (!fp) {
    726                 return false;
    727             }
    728 
    729             GrPaint paint;
    730             paint.addColorFragmentProcessor(std::move(fp));
    731             paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
    732             paint.setAllowSRGBInputs(true);
    733             SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
    734             tempRTC->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect,
    735                                 nullptr);
    736             proxyToRead = tempRTC->asTextureProxyRef();
    737             left = 0;
    738             top = 0;
    739             didTempDraw = true;
    740         }
    741     }
    742 
    743     if (!proxyToRead) {
    744         return false;
    745     }
    746 
    747     if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) {
    748         return false;
    749     }
    750     GrPixelConfig configToRead = dstConfig;
    751     if (didTempDraw) {
    752         this->flushSurfaceWrites(proxyToRead.get());
    753         configToRead = tempDrawInfo.fReadConfig;
    754     }
    755 
    756     if (!proxyToRead->instantiate(this->resourceProvider())) {
    757         return false;
    758     }
    759 
    760     GrSurface* surfaceToRead = proxyToRead->priv().peekSurface();
    761 
    762     if (!fContext->fGpu->readPixels(surfaceToRead, proxyToRead->origin(),
    763                                     left, top, width, height, configToRead, buffer, rowBytes)) {
    764         return false;
    765     }
    766 
    767     // Perform umpremul conversion if we weren't able to perform it as a draw.
    768     if (unpremul) {
    769         SkColorType colorType;
    770         if (!GrPixelConfigToColorType(dstConfig, &colorType) ||
    771             4 != SkColorTypeBytesPerPixel(colorType))
    772         {
    773             return false;
    774         }
    775 
    776         for (int y = 0; y < height; y++) {
    777             SkUnpremultiplyRow<false>((uint32_t*) buffer, (const uint32_t*) buffer, width);
    778             buffer = SkTAddOffset<void>(buffer, rowBytes);
    779         }
    780     }
    781     return true;
    782 }
    783 
    784 void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) {
    785     ASSERT_SINGLE_OWNER_PRIV
    786     RETURN_IF_ABANDONED_PRIV
    787     SkASSERT(proxy);
    788     ASSERT_OWNED_PROXY_PRIV(proxy);
    789     fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy, 0, nullptr);
    790 }
    791 
    792 void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) {
    793     ASSERT_SINGLE_OWNER_PRIV
    794     RETURN_IF_ABANDONED_PRIV
    795     SkASSERT(proxy);
    796     ASSERT_OWNED_PROXY_PRIV(proxy);
    797     if (proxy->priv().hasPendingWrite()) {
    798         this->flush(proxy);
    799     }
    800 }
    801 
    802 void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) {
    803     ASSERT_SINGLE_OWNER_PRIV
    804     RETURN_IF_ABANDONED_PRIV
    805     SkASSERT(proxy);
    806     ASSERT_OWNED_PROXY_PRIV(proxy);
    807     if (proxy->priv().hasPendingIO()) {
    808         this->flush(proxy);
    809     }
    810 }
    811 
    812 ////////////////////////////////////////////////////////////////////////////////
    813 
    814 sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy,
    815                                                                  sk_sp<SkColorSpace> colorSpace,
    816                                                                  const SkSurfaceProps* props) {
    817     ASSERT_SINGLE_OWNER_PRIV
    818 
    819     if (proxy->asRenderTargetProxy()) {
    820         return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
    821                                                                std::move(colorSpace), props);
    822     } else {
    823         SkASSERT(proxy->asTextureProxy());
    824         SkASSERT(!props);
    825         return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
    826     }
    827 }
    828 
    829 sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc,
    830                                                                   GrMipMapped mipMapped,
    831                                                                   SkBackingFit fit,
    832                                                                   SkBudgeted isDstBudgeted) {
    833 
    834     sk_sp<GrTextureProxy> proxy;
    835     if (GrMipMapped::kNo == mipMapped) {
    836         proxy = this->proxyProvider()->createProxy(dstDesc, fit, isDstBudgeted);
    837     } else {
    838         SkASSERT(SkBackingFit::kExact == fit);
    839         proxy = this->proxyProvider()->createMipMapProxy(dstDesc, isDstBudgeted);
    840     }
    841     if (!proxy) {
    842         return nullptr;
    843     }
    844 
    845     sk_sp<GrSurfaceContext> sContext = this->makeWrappedSurfaceContext(std::move(proxy));
    846     if (sContext && sContext->asRenderTargetContext()) {
    847         sContext->asRenderTargetContext()->discard();
    848     }
    849 
    850     return sContext;
    851 }
    852 
    853 sk_sp<GrTextureContext> GrContextPriv::makeBackendTextureContext(const GrBackendTexture& tex,
    854                                                                  GrSurfaceOrigin origin,
    855                                                                  sk_sp<SkColorSpace> colorSpace) {
    856     ASSERT_SINGLE_OWNER_PRIV
    857 
    858     sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->createWrappedTextureProxy(tex, origin);
    859     if (!proxy) {
    860         return nullptr;
    861     }
    862 
    863     return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
    864 }
    865 
    866 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext(
    867                                                                    const GrBackendTexture& tex,
    868                                                                    GrSurfaceOrigin origin,
    869                                                                    int sampleCnt,
    870                                                                    sk_sp<SkColorSpace> colorSpace,
    871                                                                    const SkSurfaceProps* props) {
    872     ASSERT_SINGLE_OWNER_PRIV
    873     SkASSERT(sampleCnt > 0);
    874 
    875     sk_sp<GrTextureProxy> proxy(this->proxyProvider()->createWrappedTextureProxy(tex, origin,
    876                                                                                  sampleCnt));
    877     if (!proxy) {
    878         return nullptr;
    879     }
    880 
    881     return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
    882                                                            std::move(colorSpace), props);
    883 }
    884 
    885 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext(
    886                                                 const GrBackendRenderTarget& backendRT,
    887                                                 GrSurfaceOrigin origin,
    888                                                 sk_sp<SkColorSpace> colorSpace,
    889                                                 const SkSurfaceProps* surfaceProps) {
    890     ASSERT_SINGLE_OWNER_PRIV
    891 
    892     sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->createWrappedRenderTargetProxy(backendRT,
    893                                                                                         origin);
    894     if (!proxy) {
    895         return nullptr;
    896     }
    897 
    898     return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
    899                                                            std::move(colorSpace),
    900                                                            surfaceProps);
    901 }
    902 
    903 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext(
    904                                                      const GrBackendTexture& tex,
    905                                                      GrSurfaceOrigin origin,
    906                                                      int sampleCnt,
    907                                                      sk_sp<SkColorSpace> colorSpace,
    908                                                      const SkSurfaceProps* props) {
    909     ASSERT_SINGLE_OWNER_PRIV
    910     SkASSERT(sampleCnt > 0);
    911     sk_sp<GrSurfaceProxy> proxy(this->proxyProvider()->createWrappedRenderTargetProxy(tex, origin,
    912                                                                                       sampleCnt));
    913     if (!proxy) {
    914         return nullptr;
    915     }
    916 
    917     return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
    918                                                            std::move(colorSpace),
    919                                                            props);
    920 }
    921 
    922 void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
    923     fContext->fDrawingManager->addOnFlushCallbackObject(onFlushCBObject);
    924 }
    925 
    926 void GrContextPriv::moveOpListsToDDL(SkDeferredDisplayList* ddl) {
    927     fContext->fDrawingManager->moveOpListsToDDL(ddl);
    928 }
    929 
    930 void GrContextPriv::copyOpListsFromDDL(const SkDeferredDisplayList* ddl,
    931                                        GrRenderTargetProxy* newDest) {
    932     fContext->fDrawingManager->copyOpListsFromDDL(ddl, newDest);
    933 }
    934 
    935 static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) {
    936     switch (config) {
    937         case kAlpha_8_GrPixelConfig:
    938         case kRGB_565_GrPixelConfig:
    939         case kRGBA_4444_GrPixelConfig:
    940         case kBGRA_8888_GrPixelConfig:
    941             return kRGBA_8888_GrPixelConfig;
    942         case kSBGRA_8888_GrPixelConfig:
    943             return kSRGBA_8888_GrPixelConfig;
    944         case kAlpha_half_GrPixelConfig:
    945             return kRGBA_half_GrPixelConfig;
    946         default:
    947             return kUnknown_GrPixelConfig;
    948     }
    949 }
    950 
    951 sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContextWithFallback(
    952                                                                  SkBackingFit fit,
    953                                                                  int width, int height,
    954                                                                  GrPixelConfig config,
    955                                                                  sk_sp<SkColorSpace> colorSpace,
    956                                                                  int sampleCnt,
    957                                                                  GrMipMapped mipMapped,
    958                                                                  GrSurfaceOrigin origin,
    959                                                                  const SkSurfaceProps* surfaceProps,
    960                                                                  SkBudgeted budgeted) {
    961     SkASSERT(sampleCnt > 0);
    962     if (!this->caps()->isConfigRenderable(config, sampleCnt > 1)) {
    963         config = GrPixelConfigFallback(config);
    964     }
    965 
    966     return this->makeDeferredRenderTargetContext(fit, width, height, config, std::move(colorSpace),
    967                                                  sampleCnt, mipMapped, origin, surfaceProps,
    968                                                  budgeted);
    969 }
    970 
    971 sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContext(
    972                                                         SkBackingFit fit,
    973                                                         int width, int height,
    974                                                         GrPixelConfig config,
    975                                                         sk_sp<SkColorSpace> colorSpace,
    976                                                         int sampleCnt,
    977                                                         GrMipMapped mipMapped,
    978                                                         GrSurfaceOrigin origin,
    979                                                         const SkSurfaceProps* surfaceProps,
    980                                                         SkBudgeted budgeted) {
    981     SkASSERT(sampleCnt > 0);
    982     if (this->abandoned()) {
    983         return nullptr;
    984     }
    985 
    986     GrSurfaceDesc desc;
    987     desc.fFlags = kRenderTarget_GrSurfaceFlag;
    988     desc.fOrigin = origin;
    989     desc.fWidth = width;
    990     desc.fHeight = height;
    991     desc.fConfig = config;
    992     desc.fSampleCnt = sampleCnt;
    993 
    994     sk_sp<GrTextureProxy> rtp;
    995     if (GrMipMapped::kNo == mipMapped) {
    996         rtp = fProxyProvider->createProxy(desc, fit, budgeted);
    997     } else {
    998         rtp = fProxyProvider->createMipMapProxy(desc, budgeted);
    999     }
   1000     if (!rtp) {
   1001         return nullptr;
   1002     }
   1003 
   1004     sk_sp<GrRenderTargetContext> renderTargetContext(
   1005         fDrawingManager->makeRenderTargetContext(std::move(rtp),
   1006                                                  std::move(colorSpace),
   1007                                                  surfaceProps));
   1008     if (!renderTargetContext) {
   1009         return nullptr;
   1010     }
   1011 
   1012     renderTargetContext->discard();
   1013 
   1014     return renderTargetContext;
   1015 }
   1016 
   1017 bool GrContext::abandoned() const {
   1018     ASSERT_SINGLE_OWNER
   1019     return fDrawingManager->wasAbandoned();
   1020 }
   1021 
   1022 std::unique_ptr<GrFragmentProcessor> GrContext::createPMToUPMEffect(
   1023         std::unique_ptr<GrFragmentProcessor> fp, bool useConfigConversionEffect) {
   1024     ASSERT_SINGLE_OWNER
   1025     // We have specialized effects that guarantee round-trip conversion for some formats
   1026     if (useConfigConversionEffect) {
   1027         // We should have already called this->validPMUPMConversionExists() in this case
   1028         SkASSERT(fDidTestPMConversions);
   1029         // ...and it should have succeeded
   1030         SkASSERT(this->validPMUPMConversionExists());
   1031 
   1032         return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToUnpremul);
   1033     } else {
   1034         // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
   1035         // explicitly round the results. Just do the obvious, naive thing in the shader.
   1036         return GrFragmentProcessor::UnpremulOutput(std::move(fp));
   1037     }
   1038 }
   1039 
   1040 std::unique_ptr<GrFragmentProcessor> GrContext::createUPMToPMEffect(
   1041         std::unique_ptr<GrFragmentProcessor> fp, bool useConfigConversionEffect) {
   1042     ASSERT_SINGLE_OWNER
   1043     // We have specialized effects that guarantee round-trip conversion for these formats
   1044     if (useConfigConversionEffect) {
   1045         // We should have already called this->validPMUPMConversionExists() in this case
   1046         SkASSERT(fDidTestPMConversions);
   1047         // ...and it should have succeeded
   1048         SkASSERT(this->validPMUPMConversionExists());
   1049 
   1050         return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToPremul);
   1051     } else {
   1052         // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
   1053         // explicitly round the results. Just do the obvious, naive thing in the shader.
   1054         return GrFragmentProcessor::PremulOutput(std::move(fp));
   1055     }
   1056 }
   1057 
   1058 bool GrContext::validPMUPMConversionExists() {
   1059     ASSERT_SINGLE_OWNER
   1060     if (!fDidTestPMConversions) {
   1061         fPMUPMConversionsRoundTrip = GrConfigConversionEffect::TestForPreservingPMConversions(this);
   1062         fDidTestPMConversions = true;
   1063     }
   1064 
   1065     // The PM<->UPM tests fail or succeed together so we only need to check one.
   1066     return fPMUPMConversionsRoundTrip;
   1067 }
   1068 
   1069 //////////////////////////////////////////////////////////////////////////////
   1070 
   1071 void GrContext::getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const {
   1072     ASSERT_SINGLE_OWNER
   1073     if (maxResources) {
   1074         *maxResources = fResourceCache->getMaxResourceCount();
   1075     }
   1076     if (maxResourceBytes) {
   1077         *maxResourceBytes = fResourceCache->getMaxResourceBytes();
   1078     }
   1079 }
   1080 
   1081 void GrContext::setResourceCacheLimits(int maxResources, size_t maxResourceBytes) {
   1082     ASSERT_SINGLE_OWNER
   1083     fResourceCache->setLimits(maxResources, maxResourceBytes);
   1084 }
   1085 
   1086 //////////////////////////////////////////////////////////////////////////////
   1087 
   1088 void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
   1089     ASSERT_SINGLE_OWNER
   1090     fResourceCache->dumpMemoryStatistics(traceMemoryDump);
   1091 }
   1092 
   1093 //////////////////////////////////////////////////////////////////////////////
   1094 
   1095 SkString GrContext::dump() const {
   1096     SkDynamicMemoryWStream stream;
   1097     SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty);
   1098     writer.beginObject();
   1099 
   1100     static const char* kBackendStr[] = {
   1101         "Metal",
   1102         "OpenGL",
   1103         "Vulkan",
   1104         "Mock",
   1105     };
   1106     GR_STATIC_ASSERT(0 == kMetal_GrBackend);
   1107     GR_STATIC_ASSERT(1 == kOpenGL_GrBackend);
   1108     GR_STATIC_ASSERT(2 == kVulkan_GrBackend);
   1109     GR_STATIC_ASSERT(3 == kMock_GrBackend);
   1110     writer.appendString("backend", kBackendStr[fBackend]);
   1111 
   1112     writer.appendName("caps");
   1113     fCaps->dumpJSON(&writer);
   1114 
   1115     writer.appendName("gpu");
   1116     fGpu->dumpJSON(&writer);
   1117 
   1118     // Flush JSON to the memory stream
   1119     writer.endObject();
   1120     writer.flush();
   1121 
   1122     // Null terminate the JSON data in the memory stream
   1123     stream.write8(0);
   1124 
   1125     // Allocate a string big enough to hold all the data, then copy out of the stream
   1126     SkString result(stream.bytesWritten());
   1127     stream.copyToAndReset(result.writable_str());
   1128     return result;
   1129 }
   1130