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 "GrBackendSemaphore.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 #include "SkConvertPixels.h"
     29 #include "SkDeferredDisplayList.h"
     30 #include "SkGr.h"
     31 #include "SkImageInfoPriv.h"
     32 #include "SkJSONWriter.h"
     33 #include "SkMakeUnique.h"
     34 #include "SkTaskGroup.h"
     35 #include "SkUnPreMultiplyPriv.h"
     36 #include "effects/GrConfigConversionEffect.h"
     37 #include "gl/GrGLGpu.h"
     38 #include "mock/GrMockGpu.h"
     39 #include "text/GrTextBlobCache.h"
     40 #ifdef SK_METAL
     41 #include "mtl/GrMtlTrampoline.h"
     42 #endif
     43 #ifdef SK_VULKAN
     44 #include "vk/GrVkGpu.h"
     45 #endif
     46 
     47 #define ASSERT_OWNED_PROXY(P) \
     48 SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == this)
     49 #define ASSERT_OWNED_PROXY_PRIV(P) \
     50 SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == fContext)
     51 
     52 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
     53 #define ASSERT_SINGLE_OWNER \
     54     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);)
     55 #define ASSERT_SINGLE_OWNER_PRIV \
     56     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fContext->fSingleOwner);)
     57 #define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; }
     58 #define RETURN_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return; }
     59 #define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; }
     60 #define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return false; }
     61 #define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; }
     62 
     63 ////////////////////////////////////////////////////////////////////////////////
     64 
     65 class SK_API GrDirectContext : public GrContext {
     66 public:
     67     GrDirectContext(GrBackend backend)
     68             : INHERITED(backend)
     69             , fFullAtlasManager(nullptr) {
     70     }
     71 
     72     ~GrDirectContext() override {
     73         // this if-test protects against the case where the context is being destroyed
     74         // before having been fully created
     75         if (this->contextPriv().getGpu()) {
     76             this->flush();
     77         }
     78 
     79         delete fFullAtlasManager;
     80     }
     81 
     82     void abandonContext() override {
     83         INHERITED::abandonContext();
     84         fFullAtlasManager->freeAll();
     85     }
     86 
     87     void releaseResourcesAndAbandonContext() override {
     88         INHERITED::releaseResourcesAndAbandonContext();
     89         fFullAtlasManager->freeAll();
     90     }
     91 
     92     void freeGpuResources() override {
     93         this->flush();
     94         fFullAtlasManager->freeAll();
     95 
     96         INHERITED::freeGpuResources();
     97     }
     98 
     99 protected:
    100     bool init(const GrContextOptions& options) override {
    101         SkASSERT(fCaps);  // should've been set in ctor
    102         SkASSERT(!fThreadSafeProxy);
    103 
    104         fThreadSafeProxy.reset(new GrContextThreadSafeProxy(fCaps, this->uniqueID(),
    105                                                             fBackend, options));
    106 
    107         if (!INHERITED::initCommon(options)) {
    108             return false;
    109         }
    110 
    111         GrDrawOpAtlas::AllowMultitexturing allowMultitexturing;
    112         if (GrContextOptions::Enable::kNo == options.fAllowMultipleGlyphCacheTextures ||
    113             // multitexturing supported only if range can represent the index + texcoords fully
    114             !(fCaps->shaderCaps()->floatIs32Bits() || fCaps->shaderCaps()->integerSupport())) {
    115             allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kNo;
    116         } else {
    117             allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kYes;
    118         }
    119 
    120         GrGlyphCache* glyphCache = this->contextPriv().getGlyphCache();
    121         GrProxyProvider* proxyProvider = this->contextPriv().proxyProvider();
    122 
    123         fFullAtlasManager = new GrAtlasManager(proxyProvider, glyphCache,
    124                                                options.fGlyphCacheTextureMaximumBytes,
    125                                                allowMultitexturing);
    126         this->contextPriv().addOnFlushCallbackObject(fFullAtlasManager);
    127 
    128         glyphCache->setGlyphSizeLimit(fFullAtlasManager->getGlyphSizeLimit());
    129         return true;
    130     }
    131 
    132     GrRestrictedAtlasManager* onGetRestrictedAtlasManager() override { return fFullAtlasManager; }
    133     GrAtlasManager* onGetFullAtlasManager() override { return fFullAtlasManager; }
    134 
    135 private:
    136     GrAtlasManager* fFullAtlasManager;
    137 
    138     typedef GrContext INHERITED;
    139 };
    140 
    141 /**
    142  * The DDL Context is the one in effect during DDL Recording. It isn't backed by a GrGPU and
    143  * cannot allocate any GPU resources.
    144  */
    145 class SK_API GrDDLContext : public GrContext {
    146 public:
    147     GrDDLContext(sk_sp<GrContextThreadSafeProxy> proxy)
    148             : INHERITED(proxy->fBackend, proxy->fContextUniqueID)
    149             , fRestrictedAtlasManager(nullptr) {
    150         fCaps = proxy->fCaps;
    151         fThreadSafeProxy = std::move(proxy);
    152     }
    153 
    154     ~GrDDLContext() override {
    155         // The GrDDLContext doesn't actually own the fRestrictedAtlasManager so don't delete it
    156     }
    157 
    158     void abandonContext() override {
    159         SkASSERT(0); // abandoning in a DDL Recorder doesn't make a whole lot of sense
    160         INHERITED::abandonContext();
    161     }
    162 
    163     void releaseResourcesAndAbandonContext() override {
    164         SkASSERT(0); // abandoning in a DDL Recorder doesn't make a whole lot of sense
    165         INHERITED::releaseResourcesAndAbandonContext();
    166     }
    167 
    168     void freeGpuResources() override {
    169         SkASSERT(0); // freeing resources in a DDL Recorder doesn't make a whole lot of sense
    170         INHERITED::freeGpuResources();
    171     }
    172 
    173 protected:
    174     bool init(const GrContextOptions& options) override {
    175         SkASSERT(fCaps);  // should've been set in ctor
    176         SkASSERT(fThreadSafeProxy); // should've been set in the ctor
    177 
    178         if (!INHERITED::initCommon(options)) {
    179             return false;
    180         }
    181 
    182         // DDL TODO: in DDL-mode grab a GrRestrictedAtlasManager from the thread-proxy and
    183         // do not add an onFlushCB
    184         return true;
    185     }
    186 
    187     GrRestrictedAtlasManager* onGetRestrictedAtlasManager() override {
    188         return fRestrictedAtlasManager;
    189     }
    190 
    191     GrAtlasManager* onGetFullAtlasManager() override {
    192         SkASSERT(0);   // the DDL Recorders should never invoke this
    193         return nullptr;
    194     }
    195 
    196 private:
    197     GrRestrictedAtlasManager* fRestrictedAtlasManager;
    198 
    199     typedef GrContext INHERITED;
    200 };
    201 
    202 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
    203     GrContextOptions defaultOptions;
    204     return Create(backend, backendContext, defaultOptions);
    205 }
    206 
    207 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
    208                              const GrContextOptions& options) {
    209 
    210     sk_sp<GrContext> context(new GrDirectContext(backend));
    211 
    212     context->fGpu = GrGpu::Make(backend, backendContext, options, context.get());
    213     if (!context->fGpu) {
    214         return nullptr;
    215     }
    216 
    217     context->fCaps = context->fGpu->refCaps();
    218     if (!context->init(options)) {
    219         return nullptr;
    220     }
    221 
    222     return context.release();
    223 }
    224 
    225 sk_sp<GrContext> GrContext::MakeGL(sk_sp<const GrGLInterface> interface) {
    226     GrContextOptions defaultOptions;
    227     return MakeGL(std::move(interface), defaultOptions);
    228 }
    229 
    230 sk_sp<GrContext> GrContext::MakeGL(sk_sp<const GrGLInterface> interface,
    231                                    const GrContextOptions& options) {
    232     sk_sp<GrContext> context(new GrDirectContext(kOpenGL_GrBackend));
    233 
    234     context->fGpu = GrGLGpu::Make(std::move(interface), options, context.get());
    235     if (!context->fGpu) {
    236         return nullptr;
    237     }
    238 
    239     context->fCaps = context->fGpu->refCaps();
    240     if (!context->init(options)) {
    241         return nullptr;
    242     }
    243     return context;
    244 }
    245 
    246 sk_sp<GrContext> GrContext::MakeGL(const GrGLInterface* interface) {
    247     return MakeGL(sk_ref_sp(interface));
    248 }
    249 
    250 sk_sp<GrContext> GrContext::MakeGL(const GrGLInterface* interface,
    251                                    const GrContextOptions& options) {
    252     return MakeGL(sk_ref_sp(interface), options);
    253 }
    254 
    255 sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions) {
    256     GrContextOptions defaultOptions;
    257     return MakeMock(mockOptions, defaultOptions);
    258 }
    259 
    260 sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions,
    261                                      const GrContextOptions& options) {
    262     sk_sp<GrContext> context(new GrDirectContext(kMock_GrBackend));
    263 
    264     context->fGpu = GrMockGpu::Make(mockOptions, options, context.get());
    265     if (!context->fGpu) {
    266         return nullptr;
    267     }
    268 
    269     context->fCaps = context->fGpu->refCaps();
    270     if (!context->init(options)) {
    271         return nullptr;
    272     }
    273     return context;
    274 }
    275 
    276 #ifdef SK_VULKAN
    277 sk_sp<GrContext> GrContext::MakeVulkan(sk_sp<const GrVkBackendContext> backendContext) {
    278     GrContextOptions defaultOptions;
    279     return MakeVulkan(std::move(backendContext), defaultOptions);
    280 }
    281 
    282 sk_sp<GrContext> GrContext::MakeVulkan(sk_sp<const GrVkBackendContext> backendContext,
    283                                        const GrContextOptions& options) {
    284     sk_sp<GrContext> context(new GrDirectContext(kVulkan_GrBackend));
    285 
    286     context->fGpu = GrVkGpu::Make(std::move(backendContext), options, context.get());
    287     if (!context->fGpu) {
    288         return nullptr;
    289     }
    290 
    291     context->fCaps = context->fGpu->refCaps();
    292     if (!context->init(options)) {
    293         return nullptr;
    294     }
    295     return context;
    296 }
    297 #endif
    298 
    299 #ifdef SK_METAL
    300 sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue) {
    301     GrContextOptions defaultOptions;
    302     return MakeMetal(device, queue, defaultOptions);
    303 }
    304 
    305 sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue, const GrContextOptions& options) {
    306     sk_sp<GrContext> context(new GrDirectContext(kMetal_GrBackend));
    307 
    308     context->fGpu = GrMtlTrampoline::MakeGpu(context.get(), options, device, queue);
    309     if (!context->fGpu) {
    310         return nullptr;
    311     }
    312     if (!context->init(options)) {
    313         return nullptr;
    314     }
    315     return context;
    316 }
    317 #endif
    318 
    319 static int32_t gNextID = 1;
    320 static int32_t next_id() {
    321     int32_t id;
    322     do {
    323         id = sk_atomic_inc(&gNextID);
    324     } while (id == SK_InvalidGenID);
    325     return id;
    326 }
    327 
    328 sk_sp<GrContext> GrContextPriv::MakeDDL(sk_sp<GrContextThreadSafeProxy> proxy) {
    329     sk_sp<GrContext> context(new GrDDLContext(proxy));
    330 
    331     // Note: we aren't creating a Gpu here. This causes the resource provider & cache to
    332     // also not be created
    333     if (!context->init(proxy->fOptions)) {
    334         return nullptr;
    335     }
    336     return context;
    337 }
    338 
    339 GrContext::GrContext(GrBackend backend, int32_t id)
    340         : fBackend(backend)
    341         , fUniqueID(SK_InvalidGenID == id ? next_id() : id) {
    342     fResourceCache = nullptr;
    343     fResourceProvider = nullptr;
    344     fProxyProvider = nullptr;
    345     fGlyphCache = nullptr;
    346 }
    347 
    348 bool GrContext::initCommon(const GrContextOptions& options) {
    349     ASSERT_SINGLE_OWNER
    350     SkASSERT(fCaps);  // needs to have been initialized by derived classes
    351     SkASSERT(fThreadSafeProxy); // needs to have been initialized by derived classes
    352 
    353     if (fGpu) {
    354         fCaps = fGpu->refCaps();
    355         fResourceCache = new GrResourceCache(fCaps.get(), fUniqueID);
    356         fResourceProvider = new GrResourceProvider(fGpu.get(), fResourceCache, &fSingleOwner,
    357                                                    options.fExplicitlyAllocateGPUResources);
    358     }
    359 
    360     fProxyProvider = new GrProxyProvider(fResourceProvider, fResourceCache, fCaps, &fSingleOwner);
    361 
    362     if (fResourceCache) {
    363         fResourceCache->setProxyProvider(fProxyProvider);
    364     }
    365 
    366     fDisableGpuYUVConversion = options.fDisableGpuYUVConversion;
    367     fSharpenMipmappedTextures = options.fSharpenMipmappedTextures;
    368     fDidTestPMConversions = false;
    369 
    370     GrPathRendererChain::Options prcOptions;
    371     prcOptions.fAllowPathMaskCaching = options.fAllowPathMaskCaching;
    372 #if GR_TEST_UTILS
    373     prcOptions.fGpuPathRenderers = options.fGpuPathRenderers;
    374 #endif
    375     if (options.fDisableDistanceFieldPaths) {
    376         prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall;
    377     }
    378 
    379     if (!fResourceCache) {
    380         // DDL TODO: remove this crippling of the path renderer chain
    381         // Disable the small path renderer bc of the proxies in the atlas. They need to be
    382         // unified when the opLists are added back to the destination drawing manager.
    383         prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall;
    384     }
    385 
    386     GrAtlasTextContext::Options atlasTextContextOptions;
    387     atlasTextContextOptions.fMaxDistanceFieldFontSize = options.fGlyphsAsPathsFontSize;
    388     atlasTextContextOptions.fMinDistanceFieldFontSize = options.fMinDistanceFieldFontSize;
    389     atlasTextContextOptions.fDistanceFieldVerticesAlwaysHaveW = false;
    390 #if SK_SUPPORT_ATLAS_TEXT
    391     if (GrContextOptions::Enable::kYes == options.fDistanceFieldGlyphVerticesAlwaysHaveW) {
    392         atlasTextContextOptions.fDistanceFieldVerticesAlwaysHaveW = true;
    393     }
    394 #endif
    395 
    396     fDrawingManager.reset(new GrDrawingManager(this, prcOptions, atlasTextContextOptions,
    397                                                &fSingleOwner, options.fSortRenderTargets));
    398 
    399     fGlyphCache = new GrGlyphCache;
    400 
    401     fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB,
    402                                              this, this->uniqueID(), SkToBool(fGpu)));
    403 
    404     // DDL TODO: we need to think through how the task group & persistent cache
    405     // get passed on to/shared between all the DDLRecorders created with this context.
    406     if (options.fExecutor) {
    407         fTaskGroup = skstd::make_unique<SkTaskGroup>(*options.fExecutor);
    408     }
    409 
    410     fPersistentCache = options.fPersistentCache;
    411 
    412     return true;
    413 }
    414 
    415 GrContext::~GrContext() {
    416     ASSERT_SINGLE_OWNER
    417 
    418     if (fDrawingManager) {
    419         fDrawingManager->cleanup();
    420     }
    421 
    422     for (int i = 0; i < fCleanUpData.count(); ++i) {
    423         (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
    424     }
    425 
    426     delete fResourceProvider;
    427     delete fResourceCache;
    428     delete fProxyProvider;
    429     delete fGlyphCache;
    430 }
    431 
    432 sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
    433     return fThreadSafeProxy;
    434 }
    435 
    436 SkSurfaceCharacterization GrContextThreadSafeProxy::createCharacterization(
    437                                      size_t cacheMaxResourceBytes,
    438                                      const SkImageInfo& ii, const GrBackendFormat& backendFormat,
    439                                      int sampleCnt, GrSurfaceOrigin origin,
    440                                      const SkSurfaceProps& surfaceProps,
    441                                      bool isMipMapped) {
    442     if (!backendFormat.isValid()) {
    443         return SkSurfaceCharacterization(); // return an invalid characterization
    444     }
    445 
    446     // We're assuming GrFSAAType::kMixedSamples will never be specified via this code path
    447     GrFSAAType FSAAType = sampleCnt > 1 ? GrFSAAType::kUnifiedMSAA : GrFSAAType::kNone;
    448 
    449     if (!fCaps->mipMapSupport()) {
    450         isMipMapped = false;
    451     }
    452 
    453     GrPixelConfig config = kUnknown_GrPixelConfig;
    454     if (!fCaps->getConfigFromBackendFormat(backendFormat, ii.colorType(), &config)) {
    455         return SkSurfaceCharacterization(); // return an invalid characterization
    456     }
    457 
    458     // This surface characterization factory assumes that the resulting characterization is
    459     // textureable.
    460     if (!fCaps->isConfigTexturable(config)) {
    461         return SkSurfaceCharacterization(); // return an invalid characterization
    462     }
    463 
    464     return SkSurfaceCharacterization(sk_ref_sp<GrContextThreadSafeProxy>(this),
    465                                      cacheMaxResourceBytes,
    466                                      origin, ii.width(), ii.height(), config, FSAAType, sampleCnt,
    467                                      SkSurfaceCharacterization::Textureable(true),
    468                                      SkSurfaceCharacterization::MipMapped(isMipMapped),
    469                                      ii.refColorSpace(), surfaceProps);
    470 }
    471 
    472 void GrContext::abandonContext() {
    473     ASSERT_SINGLE_OWNER
    474 
    475     fProxyProvider->abandon();
    476     fResourceProvider->abandon();
    477 
    478     // Need to abandon the drawing manager first so all the render targets
    479     // will be released/forgotten before they too are abandoned.
    480     fDrawingManager->abandon();
    481 
    482     // abandon first to so destructors
    483     // don't try to free the resources in the API.
    484     fResourceCache->abandonAll();
    485 
    486     fGpu->disconnect(GrGpu::DisconnectType::kAbandon);
    487 
    488     fGlyphCache->freeAll();
    489     fTextBlobCache->freeAll();
    490 }
    491 
    492 void GrContext::releaseResourcesAndAbandonContext() {
    493     ASSERT_SINGLE_OWNER
    494 
    495     fProxyProvider->abandon();
    496     fResourceProvider->abandon();
    497 
    498     // Need to abandon the drawing manager first so all the render targets
    499     // will be released/forgotten before they too are abandoned.
    500     fDrawingManager->abandon();
    501 
    502     // Release all resources in the backend 3D API.
    503     fResourceCache->releaseAll();
    504 
    505     fGpu->disconnect(GrGpu::DisconnectType::kCleanup);
    506 
    507     fGlyphCache->freeAll();
    508     fTextBlobCache->freeAll();
    509 }
    510 
    511 void GrContext::resetContext(uint32_t state) {
    512     ASSERT_SINGLE_OWNER
    513     fGpu->markContextDirty(state);
    514 }
    515 
    516 void GrContext::freeGpuResources() {
    517     ASSERT_SINGLE_OWNER
    518 
    519     fGlyphCache->freeAll();
    520 
    521     fDrawingManager->freeGpuResources();
    522 
    523     fResourceCache->purgeAllUnlocked();
    524 }
    525 
    526 void GrContext::purgeUnlockedResources(bool scratchResourcesOnly) {
    527     ASSERT_SINGLE_OWNER
    528     fResourceCache->purgeUnlockedResources(scratchResourcesOnly);
    529     fResourceCache->purgeAsNeeded();
    530     fTextBlobCache->purgeStaleBlobs();
    531 }
    532 
    533 void GrContext::performDeferredCleanup(std::chrono::milliseconds msNotUsed) {
    534     ASSERT_SINGLE_OWNER
    535     fResourceCache->purgeAsNeeded();
    536     fResourceCache->purgeResourcesNotUsedSince(GrStdSteadyClock::now() - msNotUsed);
    537 
    538     fTextBlobCache->purgeStaleBlobs();
    539 }
    540 
    541 void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
    542     ASSERT_SINGLE_OWNER
    543     fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources);
    544 }
    545 
    546 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
    547     ASSERT_SINGLE_OWNER
    548 
    549     if (resourceCount) {
    550         *resourceCount = fResourceCache->getBudgetedResourceCount();
    551     }
    552     if (resourceBytes) {
    553         *resourceBytes = fResourceCache->getBudgetedResourceBytes();
    554     }
    555 }
    556 
    557 size_t GrContext::getResourceCachePurgeableBytes() const {
    558     ASSERT_SINGLE_OWNER
    559     return fResourceCache->getPurgeableBytes();
    560 }
    561 
    562 ////////////////////////////////////////////////////////////////////////////////
    563 
    564 bool GrContext::colorTypeSupportedAsImage(SkColorType colorType) const {
    565     GrPixelConfig config = SkImageInfo2GrPixelConfig(colorType, nullptr, *this->caps());
    566     return this->caps()->isConfigTexturable(config);
    567 }
    568 
    569 int GrContext::maxSurfaceSampleCountForColorType(SkColorType colorType) const {
    570     GrPixelConfig config = SkImageInfo2GrPixelConfig(colorType, nullptr, *this->caps());
    571     return this->caps()->maxRenderTargetSampleCount(config);
    572 }
    573 
    574 ////////////////////////////////////////////////////////////////////////////////
    575 
    576 void GrContext::TextBlobCacheOverBudgetCB(void* data) {
    577     SkASSERT(data);
    578     // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on
    579     // GrRenderTargetContext to perform a necessary flush.  The solution is to move drawText calls
    580     // to below the GrContext level, but this is not trivial because they call drawPath on
    581     // SkGpuDevice.
    582     GrContext* context = reinterpret_cast<GrContext*>(data);
    583     context->flush();
    584 }
    585 
    586 ////////////////////////////////////////////////////////////////////////////////
    587 
    588 void GrContext::flush() {
    589     ASSERT_SINGLE_OWNER
    590     RETURN_IF_ABANDONED
    591 
    592     fDrawingManager->flush(nullptr);
    593 }
    594 
    595 GrSemaphoresSubmitted GrContext::flushAndSignalSemaphores(int numSemaphores,
    596                                                           GrBackendSemaphore signalSemaphores[]) {
    597     ASSERT_SINGLE_OWNER
    598     if (fDrawingManager->wasAbandoned()) { return GrSemaphoresSubmitted::kNo; }
    599 
    600     return fDrawingManager->flush(nullptr, numSemaphores, signalSemaphores);
    601 }
    602 
    603 void GrContextPriv::flush(GrSurfaceProxy* proxy) {
    604     ASSERT_SINGLE_OWNER_PRIV
    605     RETURN_IF_ABANDONED_PRIV
    606     ASSERT_OWNED_PROXY_PRIV(proxy);
    607 
    608     fContext->fDrawingManager->flush(proxy);
    609 }
    610 
    611 bool sw_convert_to_premul(GrColorType srcColorType, int width, int height, size_t inRowBytes,
    612                           const void* inPixels, size_t outRowBytes, void* outPixels) {
    613     SkColorType colorType = GrColorTypeToSkColorType(srcColorType);
    614     if (kUnknown_SkColorType == colorType || 4 != SkColorTypeBytesPerPixel(colorType)) {
    615         return false;
    616     }
    617 
    618     for (int y = 0; y < height; y++) {
    619         SkOpts::RGBA_to_rgbA((uint32_t*) outPixels, inPixels, width);
    620         outPixels = SkTAddOffset<void>(outPixels, outRowBytes);
    621         inPixels = SkTAddOffset<const void>(inPixels, inRowBytes);
    622     }
    623 
    624     return true;
    625 }
    626 
    627 // TODO: This will be removed when GrSurfaceContexts are aware of their color types.
    628 // (skbug.com/6718)
    629 static bool valid_premul_config(GrPixelConfig config) {
    630     switch (config) {
    631         case kUnknown_GrPixelConfig:            return false;
    632         case kAlpha_8_GrPixelConfig:            return false;
    633         case kGray_8_GrPixelConfig:             return false;
    634         case kRGB_565_GrPixelConfig:            return false;
    635         case kRGBA_4444_GrPixelConfig:          return true;
    636         case kRGBA_8888_GrPixelConfig:          return true;
    637         case kBGRA_8888_GrPixelConfig:          return true;
    638         case kSRGBA_8888_GrPixelConfig:         return true;
    639         case kSBGRA_8888_GrPixelConfig:         return true;
    640         case kRGBA_1010102_GrPixelConfig:       return true;
    641         case kRGBA_float_GrPixelConfig:         return true;
    642         case kRG_float_GrPixelConfig:           return false;
    643         case kAlpha_half_GrPixelConfig:         return false;
    644         case kRGBA_half_GrPixelConfig:          return true;
    645         case kAlpha_8_as_Alpha_GrPixelConfig:   return false;
    646         case kAlpha_8_as_Red_GrPixelConfig:     return false;
    647         case kAlpha_half_as_Red_GrPixelConfig:  return false;
    648         case kGray_8_as_Lum_GrPixelConfig:      return false;
    649         case kGray_8_as_Red_GrPixelConfig:      return false;
    650     }
    651     SK_ABORT("Invalid GrPixelConfig");
    652     return false;
    653 }
    654 
    655 static bool valid_premul_color_type(GrColorType ct) {
    656     switch (ct) {
    657         case GrColorType::kUnknown:      return false;
    658         case GrColorType::kAlpha_8:      return false;
    659         case GrColorType::kRGB_565:      return false;
    660         case GrColorType::kABGR_4444:    return true;
    661         case GrColorType::kRGBA_8888:    return true;
    662         case GrColorType::kBGRA_8888:    return true;
    663         case GrColorType::kRGBA_1010102: return true;
    664         case GrColorType::kGray_8:       return false;
    665         case GrColorType::kAlpha_F16:    return false;
    666         case GrColorType::kRGBA_F16:     return true;
    667         case GrColorType::kRG_F32:       return false;
    668         case GrColorType::kRGBA_F32:     return true;
    669     }
    670     SK_ABORT("Invalid GrColorType");
    671     return false;
    672 }
    673 
    674 static bool valid_pixel_conversion(GrColorType cpuColorType, GrPixelConfig gpuConfig,
    675                                    bool premulConversion) {
    676     // We only allow premul <-> unpremul conversions for some formats
    677     if (premulConversion &&
    678         (!valid_premul_color_type(cpuColorType) || !valid_premul_config(gpuConfig))) {
    679         return false;
    680     }
    681 
    682     return true;
    683 }
    684 
    685 static bool pm_upm_must_round_trip(GrColorType cpuColorType, const SkColorSpace* cpuColorSpace) {
    686     return !cpuColorSpace &&
    687            (GrColorType::kRGBA_8888 == cpuColorType || GrColorType::kBGRA_8888 == cpuColorType);
    688 }
    689 
    690 // TODO: This will be removed when GrSurfaceContexts are aware of their color types.
    691 // (skbug.com/6718)
    692 static bool pm_upm_must_round_trip(GrPixelConfig surfaceConfig,
    693                                    const SkColorSpace* surfaceColorSpace) {
    694     return !surfaceColorSpace &&
    695            (kRGBA_8888_GrPixelConfig == surfaceConfig || kBGRA_8888_GrPixelConfig == surfaceConfig);
    696 }
    697 
    698 static GrSRGBConversion determine_write_pixels_srgb_conversion(GrColorType srcColorType,
    699                                                                const SkColorSpace* srcColorSpace,
    700                                                                GrSRGBEncoded dstSRGBEncoded,
    701                                                                const SkColorSpace* dstColorSpace,
    702                                                                const GrCaps& caps) {
    703     // No support for sRGB-encoded alpha.
    704     if (GrColorTypeIsAlphaOnly(srcColorType)) {
    705         return GrSRGBConversion::kNone;
    706     }
    707     // No conversions without GPU support for sRGB. (Legacy mode)
    708     if (!caps.srgbSupport()) {
    709         return GrSRGBConversion::kNone;
    710     }
    711     // If the GrSurfaceContext has no color space then it is in legacy mode.
    712     if (!dstColorSpace) {
    713         return GrSRGBConversion::kNone;
    714     }
    715 
    716     bool srcColorSpaceIsSRGB = srcColorSpace && srcColorSpace->gammaCloseToSRGB();
    717     bool dstColorSpaceIsSRGB = dstColorSpace->gammaCloseToSRGB();
    718 
    719     // For now we are assuming that if color space of the dst does not have sRGB gamma then the
    720     // texture format is not sRGB encoded and vice versa. Note that we already checked for "legacy"
    721     // mode being forced on by caps above. This may change in the future. We will then have to
    722     // perform shader based conversions.
    723     SkASSERT(dstColorSpaceIsSRGB == (GrSRGBEncoded::kYes == dstSRGBEncoded));
    724 
    725     if (srcColorSpaceIsSRGB == dstColorSpaceIsSRGB) {
    726         return GrSRGBConversion::kNone;
    727     }
    728     return srcColorSpaceIsSRGB ? GrSRGBConversion::kSRGBToLinear : GrSRGBConversion::kLinearToSRGB;
    729 }
    730 
    731 static GrSRGBConversion determine_read_pixels_srgb_conversion(GrSRGBEncoded srcSRGBEncoded,
    732                                                               const SkColorSpace* srcColorSpace,
    733                                                               GrColorType dstColorType,
    734                                                               const SkColorSpace* dstColorSpace,
    735                                                               const GrCaps& caps) {
    736     // This is symmetrical with the write version.
    737     switch (determine_write_pixels_srgb_conversion(dstColorType, dstColorSpace, srcSRGBEncoded,
    738                                                    srcColorSpace, caps)) {
    739         case GrSRGBConversion::kNone:         return GrSRGBConversion::kNone;
    740         case GrSRGBConversion::kLinearToSRGB: return GrSRGBConversion::kSRGBToLinear;
    741         case GrSRGBConversion::kSRGBToLinear: return GrSRGBConversion::kLinearToSRGB;
    742     }
    743     return GrSRGBConversion::kNone;
    744 }
    745 
    746 bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst, int left, int top, int width,
    747                                        int height, GrColorType srcColorType,
    748                                        SkColorSpace* srcColorSpace, const void* buffer,
    749                                        size_t rowBytes, uint32_t pixelOpsFlags) {
    750 #ifndef SK_LEGACY_GPU_PIXEL_OPS
    751     return this->writeSurfacePixels2(dst, left, top, width, height, srcColorType, srcColorSpace,
    752                                      buffer, rowBytes, pixelOpsFlags);
    753 #endif
    754 
    755     // TODO: Color space conversion
    756 
    757     ASSERT_SINGLE_OWNER_PRIV
    758     RETURN_FALSE_IF_ABANDONED_PRIV
    759     SkASSERT(dst);
    760     ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy());
    761     GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels", fContext);
    762 
    763     if (!dst->asSurfaceProxy()->instantiate(this->resourceProvider())) {
    764         return false;
    765     }
    766 
    767     GrSurfaceProxy* dstProxy = dst->asSurfaceProxy();
    768     GrSurface* dstSurface = dstProxy->priv().peekSurface();
    769 
    770     // The src is unpremul but the dst is premul -> premul the src before or as part of the write
    771     const bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
    772 
    773     if (!valid_pixel_conversion(srcColorType, dstProxy->config(), premul)) {
    774         return false;
    775     }
    776 
    777     // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
    778     // without any color spaces attached, and the caller wants us to premul.
    779     bool useConfigConversionEffect =
    780             premul && pm_upm_must_round_trip(srcColorType, srcColorSpace) &&
    781             pm_upm_must_round_trip(dstProxy->config(), dst->colorSpaceInfo().colorSpace());
    782 
    783     // Are we going to try to premul as part of a draw? For the non-legacy case, we always allow
    784     // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
    785     bool premulOnGpu = premul &&
    786                        (!useConfigConversionEffect || fContext->validPMUPMConversionExists());
    787 
    788     // Trim the params here so that if we wind up making a temporary surface it can be as small as
    789     // necessary and because GrGpu::getWritePixelsInfo requires it.
    790     if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(),
    791                                                GrColorTypeBytesPerPixel(srcColorType), &left, &top,
    792                                                &width, &height, &buffer, &rowBytes)) {
    793         return false;
    794     }
    795 
    796     GrGpu::DrawPreference drawPreference = premulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
    797                                                        : GrGpu::kNoDraw_DrawPreference;
    798     GrGpu::WritePixelTempDrawInfo tempDrawInfo;
    799     GrSRGBConversion srgbConversion = determine_write_pixels_srgb_conversion(
    800             srcColorType, srcColorSpace, GrPixelConfigIsSRGBEncoded(dstProxy->config()),
    801             dst->colorSpaceInfo().colorSpace(), *fContext->caps());
    802     if (!fContext->fGpu->getWritePixelsInfo(dstSurface, dstProxy->origin(), width, height,
    803                                             srcColorType, srgbConversion, &drawPreference,
    804                                             &tempDrawInfo)) {
    805         return false;
    806     }
    807 
    808     if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) {
    809         this->flush(nullptr); // MDB TODO: tighten this
    810     }
    811 
    812     sk_sp<GrTextureProxy> tempProxy;
    813     if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
    814         tempProxy = this->proxyProvider()->createProxy(tempDrawInfo.fTempSurfaceDesc,
    815                                                        SkBackingFit::kApprox,
    816                                                        SkBudgeted::kYes);
    817         if (!tempProxy && GrGpu::kRequireDraw_DrawPreference == drawPreference) {
    818             return false;
    819         }
    820     }
    821 
    822     // temp buffer for doing sw premul conversion, if needed.
    823     SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
    824     // We need to do sw premul if we were unable to create a RT for drawing, or if we can't do the
    825     // premul on the GPU
    826     if (premul && (!tempProxy || !premulOnGpu)) {
    827         size_t tmpRowBytes = 4 * width;
    828         tmpPixels.reset(width * height);
    829         if (!sw_convert_to_premul(srcColorType, width, height, rowBytes, buffer, tmpRowBytes,
    830                                   tmpPixels.get())) {
    831             return false;
    832         }
    833         rowBytes = tmpRowBytes;
    834         buffer = tmpPixels.get();
    835     }
    836 
    837     if (tempProxy) {
    838         auto fp = GrSimpleTextureEffect::Make(tempProxy, SkMatrix::I());
    839         if (premulOnGpu) {
    840             fp = fContext->createUPMToPMEffect(std::move(fp), useConfigConversionEffect);
    841         }
    842         fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
    843         if (!fp) {
    844             return false;
    845         }
    846 
    847         if (!tempProxy->instantiate(this->resourceProvider())) {
    848             return false;
    849         }
    850         GrTexture* texture = tempProxy->priv().peekTexture();
    851 
    852         if (tempProxy->priv().hasPendingIO()) {
    853             this->flush(tempProxy.get());
    854         }
    855 
    856         if (!fContext->fGpu->writePixels(texture, tempProxy->origin(), 0, 0, width, height,
    857                                          tempDrawInfo.fWriteColorType, buffer, rowBytes)) {
    858             return false;
    859         }
    860         tempProxy = nullptr;
    861 
    862         SkMatrix matrix;
    863         matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
    864         GrRenderTargetContext* renderTargetContext = dst->asRenderTargetContext();
    865         if (!renderTargetContext) {
    866             return false;
    867         }
    868         GrPaint paint;
    869         paint.addColorFragmentProcessor(std::move(fp));
    870         paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
    871         paint.setAllowSRGBInputs(dst->colorSpaceInfo().isGammaCorrect() ||
    872                                  GrPixelConfigIsSRGB(dst->colorSpaceInfo().config()));
    873         SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
    874         renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, rect,
    875                                         nullptr);
    876 
    877         if (kFlushWrites_PixelOp & pixelOpsFlags) {
    878             this->flushSurfaceWrites(renderTargetContext->asRenderTargetProxy());
    879         }
    880     } else {
    881         return fContext->fGpu->writePixels(dstSurface, dstProxy->origin(), left, top, width, height,
    882                                            srcColorType, buffer, rowBytes);
    883     }
    884     return true;
    885 }
    886 
    887 bool GrContextPriv::readSurfacePixels(GrSurfaceContext* src, int left, int top, int width,
    888                                       int height, GrColorType dstColorType,
    889                                       SkColorSpace* dstColorSpace, void* buffer, size_t rowBytes,
    890                                       uint32_t flags) {
    891     // TODO: Color space conversion
    892 
    893     ASSERT_SINGLE_OWNER_PRIV
    894     RETURN_FALSE_IF_ABANDONED_PRIV
    895     SkASSERT(src);
    896     ASSERT_OWNED_PROXY_PRIV(src->asSurfaceProxy());
    897     GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "readSurfacePixels", fContext);
    898 
    899     // MDB TODO: delay this instantiation until later in the method
    900     if (!src->asSurfaceProxy()->instantiate(this->resourceProvider())) {
    901         return false;
    902     }
    903 
    904     GrSurfaceProxy* srcProxy = src->asSurfaceProxy();
    905     GrSurface* srcSurface = srcProxy->priv().peekSurface();
    906 
    907     // The src is premul but the dst is unpremul -> unpremul the src after or as part of the read
    908     bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
    909 
    910     if (!valid_pixel_conversion(dstColorType, srcProxy->config(), unpremul)) {
    911         return false;
    912     }
    913 
    914     // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
    915     // without any color spaces attached, and the caller wants us to unpremul.
    916     bool useConfigConversionEffect =
    917             unpremul &&
    918             pm_upm_must_round_trip(srcProxy->config(), src->colorSpaceInfo().colorSpace()) &&
    919             pm_upm_must_round_trip(dstColorType, dstColorSpace);
    920 
    921     // Are we going to try to unpremul as part of a draw? For the non-legacy case, we always allow
    922     // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
    923     bool unpremulOnGpu = unpremul &&
    924                          (!useConfigConversionEffect || fContext->validPMUPMConversionExists());
    925 
    926     // Adjust the params so that if we wind up using an intermediate surface we've already done
    927     // all the trimming and the temporary can be the min size required.
    928     if (!GrSurfacePriv::AdjustReadPixelParams(srcSurface->width(), srcSurface->height(),
    929                                               GrColorTypeBytesPerPixel(dstColorType), &left, &top,
    930                                               &width, &height, &buffer, &rowBytes)) {
    931         return false;
    932     }
    933 
    934     GrGpu::DrawPreference drawPreference = unpremulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
    935                                                          : GrGpu::kNoDraw_DrawPreference;
    936     GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
    937     GrSRGBConversion srgbConversion = determine_read_pixels_srgb_conversion(
    938             GrPixelConfigIsSRGBEncoded(srcProxy->config()), src->colorSpaceInfo().colorSpace(),
    939             dstColorType, dstColorSpace, *fContext->caps());
    940 
    941     if (!fContext->fGpu->getReadPixelsInfo(srcSurface, srcProxy->origin(), width, height, rowBytes,
    942                                            dstColorType, srgbConversion, &drawPreference,
    943                                            &tempDrawInfo)) {
    944         return false;
    945     }
    946 
    947     if (!(kDontFlush_PixelOpsFlag & flags) && srcSurface->surfacePriv().hasPendingWrite()) {
    948         this->flush(nullptr); // MDB TODO: tighten this
    949     }
    950 
    951     sk_sp<GrSurfaceProxy> proxyToRead = src->asSurfaceProxyRef();
    952     bool didTempDraw = false;
    953     if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
    954         if (SkBackingFit::kExact == tempDrawInfo.fTempSurfaceFit) {
    955             // We only respect this when the entire src is being read. Otherwise we can trigger too
    956             // many odd ball texture sizes and trash the cache.
    957             if (width != srcSurface->width() || height != srcSurface->height()) {
    958                 tempDrawInfo.fTempSurfaceFit= SkBackingFit::kApprox;
    959             }
    960         }
    961         // TODO: Need to decide the semantics of this function for color spaces. Do we support
    962         // conversion to a passed-in color space? For now, specifying nullptr means that this
    963         // path will do no conversion, so it will match the behavior of the non-draw path. For
    964         // now we simply infer an sRGB color space if the config is sRGB in order to avoid an
    965         // illegal combination.
    966         sk_sp<SkColorSpace> colorSpace;
    967         if (GrPixelConfigIsSRGB(tempDrawInfo.fTempSurfaceDesc.fConfig)) {
    968             colorSpace = SkColorSpace::MakeSRGB();
    969         }
    970         sk_sp<GrRenderTargetContext> tempRTC =
    971                 fContext->makeDeferredRenderTargetContext(tempDrawInfo.fTempSurfaceFit,
    972                                                           tempDrawInfo.fTempSurfaceDesc.fWidth,
    973                                                           tempDrawInfo.fTempSurfaceDesc.fHeight,
    974                                                           tempDrawInfo.fTempSurfaceDesc.fConfig,
    975                                                           std::move(colorSpace),
    976                                                           tempDrawInfo.fTempSurfaceDesc.fSampleCnt,
    977                                                           GrMipMapped::kNo,
    978                                                           tempDrawInfo.fTempSurfaceDesc.fOrigin);
    979         if (tempRTC) {
    980             // Adding discard to appease vulkan validation warning about loading uninitialized data
    981             // on draw
    982             tempRTC->discard();
    983             SkMatrix textureMatrix = SkMatrix::MakeTrans(SkIntToScalar(left), SkIntToScalar(top));
    984             sk_sp<GrTextureProxy> proxy = src->asTextureProxyRef();
    985             auto fp = GrSimpleTextureEffect::Make(std::move(proxy), textureMatrix);
    986             if (unpremulOnGpu) {
    987                 fp = fContext->createPMToUPMEffect(std::move(fp), useConfigConversionEffect);
    988                 // We no longer need to do this on CPU after the read back.
    989                 unpremul = false;
    990             }
    991             fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
    992             if (!fp) {
    993                 return false;
    994             }
    995 
    996             GrPaint paint;
    997             paint.addColorFragmentProcessor(std::move(fp));
    998             paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
    999             paint.setAllowSRGBInputs(true);
   1000             SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
   1001             tempRTC->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect,
   1002                                 nullptr);
   1003             proxyToRead = tempRTC->asTextureProxyRef();
   1004             left = 0;
   1005             top = 0;
   1006             didTempDraw = true;
   1007         }
   1008     }
   1009 
   1010     if (!proxyToRead) {
   1011         return false;
   1012     }
   1013 
   1014     if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) {
   1015         return false;
   1016     }
   1017     GrColorType colorTypeToRead = dstColorType;
   1018     if (didTempDraw) {
   1019         this->flushSurfaceWrites(proxyToRead.get());
   1020         colorTypeToRead = tempDrawInfo.fReadColorType;
   1021     }
   1022 
   1023     if (!proxyToRead->instantiate(this->resourceProvider())) {
   1024         return false;
   1025     }
   1026 
   1027     GrSurface* surfaceToRead = proxyToRead->priv().peekSurface();
   1028 
   1029     if (!fContext->fGpu->readPixels(surfaceToRead, proxyToRead->origin(), left, top, width, height,
   1030                                     colorTypeToRead, buffer, rowBytes)) {
   1031         return false;
   1032     }
   1033 
   1034     // Perform umpremul conversion if we weren't able to perform it as a draw.
   1035     if (unpremul) {
   1036         SkColorType colorType = GrColorTypeToSkColorType(dstColorType);
   1037         if (kUnknown_SkColorType == colorType || 4 != SkColorTypeBytesPerPixel(colorType)) {
   1038             return false;
   1039         }
   1040 
   1041         for (int y = 0; y < height; y++) {
   1042             SkUnpremultiplyRow<false>((uint32_t*) buffer, (const uint32_t*) buffer, width);
   1043             buffer = SkTAddOffset<void>(buffer, rowBytes);
   1044         }
   1045     }
   1046     return true;
   1047 }
   1048 
   1049 bool GrContextPriv::writeSurfacePixels2(GrSurfaceContext* dst, int left, int top, int width,
   1050                                         int height, GrColorType srcColorType,
   1051                                         SkColorSpace* srcColorSpace, const void* buffer,
   1052                                         size_t rowBytes, uint32_t pixelOpsFlags) {
   1053     ASSERT_SINGLE_OWNER_PRIV
   1054     RETURN_FALSE_IF_ABANDONED_PRIV
   1055     SkASSERT(dst);
   1056     SkASSERT(buffer);
   1057     ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy());
   1058     GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels2", fContext);
   1059 
   1060     if (GrColorType::kUnknown == srcColorType) {
   1061         return false;
   1062     }
   1063 
   1064     if (!dst->asSurfaceProxy()->instantiate(this->resourceProvider())) {
   1065         return false;
   1066     }
   1067 
   1068     GrSurfaceProxy* dstProxy = dst->asSurfaceProxy();
   1069     GrSurface* dstSurface = dstProxy->priv().peekSurface();
   1070 
   1071     if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(),
   1072                                                GrColorTypeBytesPerPixel(srcColorType), &left, &top,
   1073                                                &width, &height, &buffer, &rowBytes)) {
   1074         return false;
   1075     }
   1076 
   1077     if (!fContext->caps()->surfaceSupportsWritePixels(dstSurface)) {
   1078         GrSurfaceDesc desc;
   1079         desc.fConfig = dstProxy->config();
   1080         desc.fWidth = width;
   1081         desc.fHeight = height;
   1082         desc.fSampleCnt = 1;
   1083         desc.fOrigin = kTopLeft_GrSurfaceOrigin;
   1084         auto tempProxy =
   1085                 this->proxyProvider()->createProxy(desc, SkBackingFit::kApprox, SkBudgeted::kYes);
   1086         if (!tempProxy) {
   1087             return false;
   1088         }
   1089         auto tempCtx = this->drawingManager()->makeTextureContext(
   1090                 tempProxy, dst->colorSpaceInfo().refColorSpace());
   1091         if (!tempCtx) {
   1092             return false;
   1093         }
   1094         if (!this->writeSurfacePixels2(tempCtx.get(), 0, 0, width, height, srcColorType,
   1095                                        srcColorSpace, buffer, rowBytes, pixelOpsFlags)) {
   1096             return false;
   1097         }
   1098         return dst->copy(tempProxy.get(), SkIRect::MakeWH(width, height), {left, top});
   1099     }
   1100 
   1101     // TODO: Make GrSurfaceContext know its alpha type and pass src buffer's alpha type.
   1102     bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
   1103     bool convert = premul;
   1104 
   1105     if (!valid_pixel_conversion(srcColorType, dstProxy->config(), premul)) {
   1106         return false;
   1107     }
   1108 
   1109     GrColorType allowedColorType =
   1110             fContext->caps()->supportedWritePixelsColorType(dstProxy->config(), srcColorType);
   1111     convert = convert || (srcColorType != allowedColorType);
   1112 
   1113     if (!dst->colorSpaceInfo().colorSpace()) {
   1114         // "Legacy" mode - no color space conversions.
   1115         srcColorSpace = nullptr;
   1116     }
   1117     convert = convert || !SkColorSpace::Equals(srcColorSpace, dst->colorSpaceInfo().colorSpace());
   1118 
   1119     std::unique_ptr<char[]> tempBuffer;
   1120     if (convert) {
   1121         auto srcSkColorType = GrColorTypeToSkColorType(srcColorType);
   1122         auto dstSkColorType = GrColorTypeToSkColorType(allowedColorType);
   1123         if (kUnknown_SkColorType == srcSkColorType || kUnknown_SkColorType == dstSkColorType) {
   1124             return false;
   1125         }
   1126         auto srcAlphaType = premul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
   1127         SkPixmap src(SkImageInfo::Make(width, height, srcSkColorType, srcAlphaType,
   1128                                        sk_ref_sp(srcColorSpace)),
   1129                      buffer, rowBytes);
   1130         auto tempSrcII = SkImageInfo::Make(width, height, dstSkColorType, kPremul_SkAlphaType,
   1131                                            dst->colorSpaceInfo().refColorSpace());
   1132         auto size = tempSrcII.computeMinByteSize();
   1133         if (!size) {
   1134             return false;
   1135         }
   1136         tempBuffer.reset(new char[size]);
   1137         SkPixmap tempSrc(tempSrcII, tempBuffer.get(), tempSrcII.minRowBytes());
   1138         if (!src.readPixels(tempSrc)) {
   1139             return false;
   1140         }
   1141         srcColorType = allowedColorType;
   1142         buffer = tempSrc.addr();
   1143         rowBytes = tempSrc.rowBytes();
   1144         if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) {
   1145             std::unique_ptr<char[]> row(new char[rowBytes]);
   1146             for (int y = 0; y < height / 2; ++y) {
   1147                 memcpy(row.get(), tempSrc.addr(0, y), rowBytes);
   1148                 memcpy(tempSrc.writable_addr(0, y), tempSrc.addr(0, height - 1 - y), rowBytes);
   1149                 memcpy(tempSrc.writable_addr(0, height - 1 - y), row.get(), rowBytes);
   1150             }
   1151             top = dstProxy->height() - top - height;
   1152         }
   1153     } else if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) {
   1154         size_t trimRowBytes = GrColorTypeBytesPerPixel(srcColorType) * width;
   1155         tempBuffer.reset(new char[trimRowBytes * height]);
   1156         char* dst = reinterpret_cast<char*>(tempBuffer.get()) + trimRowBytes * (height - 1);
   1157         const char* src = reinterpret_cast<const char*>(buffer);
   1158         for (int i = 0; i < height; ++i, src += rowBytes, dst -= trimRowBytes) {
   1159             memcpy(dst, src, trimRowBytes);
   1160         }
   1161         buffer = tempBuffer.get();
   1162         rowBytes = trimRowBytes;
   1163         top = dstProxy->height() - top - height;
   1164     }
   1165 
   1166     if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) {
   1167         this->flush(nullptr);  // MDB TODO: tighten this
   1168     }
   1169 
   1170     return this->getGpu()->writePixels(dstSurface, left, top, width, height, srcColorType, buffer,
   1171                                        rowBytes);
   1172 }
   1173 
   1174 void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) {
   1175     ASSERT_SINGLE_OWNER_PRIV
   1176     RETURN_IF_ABANDONED_PRIV
   1177     SkASSERT(proxy);
   1178     ASSERT_OWNED_PROXY_PRIV(proxy);
   1179     fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy, 0, nullptr);
   1180 }
   1181 
   1182 void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) {
   1183     ASSERT_SINGLE_OWNER_PRIV
   1184     RETURN_IF_ABANDONED_PRIV
   1185     SkASSERT(proxy);
   1186     ASSERT_OWNED_PROXY_PRIV(proxy);
   1187     if (proxy->priv().hasPendingWrite()) {
   1188         this->flush(proxy);
   1189     }
   1190 }
   1191 
   1192 void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) {
   1193     ASSERT_SINGLE_OWNER_PRIV
   1194     RETURN_IF_ABANDONED_PRIV
   1195     SkASSERT(proxy);
   1196     ASSERT_OWNED_PROXY_PRIV(proxy);
   1197     if (proxy->priv().hasPendingIO()) {
   1198         this->flush(proxy);
   1199     }
   1200 }
   1201 
   1202 ////////////////////////////////////////////////////////////////////////////////
   1203 
   1204 sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy,
   1205                                                                  sk_sp<SkColorSpace> colorSpace,
   1206                                                                  const SkSurfaceProps* props) {
   1207     ASSERT_SINGLE_OWNER_PRIV
   1208 
   1209     // sRGB pixel configs may only be used with near-sRGB gamma color spaces.
   1210     if (GrPixelConfigIsSRGB(proxy->config())) {
   1211         if (!colorSpace || !colorSpace->gammaCloseToSRGB()) {
   1212             return nullptr;
   1213         }
   1214     }
   1215     if (proxy->asRenderTargetProxy()) {
   1216         return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
   1217                                                                std::move(colorSpace), props);
   1218     } else {
   1219         SkASSERT(proxy->asTextureProxy());
   1220         SkASSERT(!props);
   1221         return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
   1222     }
   1223 }
   1224 
   1225 sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc,
   1226                                                                   GrMipMapped mipMapped,
   1227                                                                   SkBackingFit fit,
   1228                                                                   SkBudgeted isDstBudgeted,
   1229                                                                   sk_sp<SkColorSpace> colorSpace,
   1230                                                                   const SkSurfaceProps* props) {
   1231     sk_sp<GrTextureProxy> proxy;
   1232     if (GrMipMapped::kNo == mipMapped) {
   1233         proxy = this->proxyProvider()->createProxy(dstDesc, fit, isDstBudgeted);
   1234     } else {
   1235         SkASSERT(SkBackingFit::kExact == fit);
   1236         proxy = this->proxyProvider()->createMipMapProxy(dstDesc, isDstBudgeted);
   1237     }
   1238     if (!proxy) {
   1239         return nullptr;
   1240     }
   1241 
   1242     return this->makeWrappedSurfaceContext(std::move(proxy), std::move(colorSpace), props);
   1243 }
   1244 
   1245 sk_sp<GrTextureContext> GrContextPriv::makeBackendTextureContext(const GrBackendTexture& tex,
   1246                                                                  GrSurfaceOrigin origin,
   1247                                                                  sk_sp<SkColorSpace> colorSpace) {
   1248     ASSERT_SINGLE_OWNER_PRIV
   1249 
   1250     sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->createWrappedTextureProxy(tex, origin);
   1251     if (!proxy) {
   1252         return nullptr;
   1253     }
   1254 
   1255     return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
   1256 }
   1257 
   1258 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext(
   1259                                                                    const GrBackendTexture& tex,
   1260                                                                    GrSurfaceOrigin origin,
   1261                                                                    int sampleCnt,
   1262                                                                    sk_sp<SkColorSpace> colorSpace,
   1263                                                                    const SkSurfaceProps* props) {
   1264     ASSERT_SINGLE_OWNER_PRIV
   1265     SkASSERT(sampleCnt > 0);
   1266 
   1267     sk_sp<GrTextureProxy> proxy(this->proxyProvider()->createWrappedTextureProxy(tex, origin,
   1268                                                                                  sampleCnt));
   1269     if (!proxy) {
   1270         return nullptr;
   1271     }
   1272 
   1273     return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
   1274                                                            std::move(colorSpace), props);
   1275 }
   1276 
   1277 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext(
   1278                                                 const GrBackendRenderTarget& backendRT,
   1279                                                 GrSurfaceOrigin origin,
   1280                                                 sk_sp<SkColorSpace> colorSpace,
   1281                                                 const SkSurfaceProps* surfaceProps) {
   1282     ASSERT_SINGLE_OWNER_PRIV
   1283 
   1284     sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->createWrappedRenderTargetProxy(backendRT,
   1285                                                                                         origin);
   1286     if (!proxy) {
   1287         return nullptr;
   1288     }
   1289 
   1290     return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
   1291                                                            std::move(colorSpace),
   1292                                                            surfaceProps);
   1293 }
   1294 
   1295 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext(
   1296                                                      const GrBackendTexture& tex,
   1297                                                      GrSurfaceOrigin origin,
   1298                                                      int sampleCnt,
   1299                                                      sk_sp<SkColorSpace> colorSpace,
   1300                                                      const SkSurfaceProps* props) {
   1301     ASSERT_SINGLE_OWNER_PRIV
   1302     SkASSERT(sampleCnt > 0);
   1303     sk_sp<GrSurfaceProxy> proxy(this->proxyProvider()->createWrappedRenderTargetProxy(tex, origin,
   1304                                                                                       sampleCnt));
   1305     if (!proxy) {
   1306         return nullptr;
   1307     }
   1308 
   1309     return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
   1310                                                            std::move(colorSpace),
   1311                                                            props);
   1312 }
   1313 
   1314 void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
   1315     fContext->fDrawingManager->addOnFlushCallbackObject(onFlushCBObject);
   1316 }
   1317 
   1318 void GrContextPriv::moveOpListsToDDL(SkDeferredDisplayList* ddl) {
   1319     fContext->fDrawingManager->moveOpListsToDDL(ddl);
   1320 }
   1321 
   1322 void GrContextPriv::copyOpListsFromDDL(const SkDeferredDisplayList* ddl,
   1323                                        GrRenderTargetProxy* newDest) {
   1324     fContext->fDrawingManager->copyOpListsFromDDL(ddl, newDest);
   1325 }
   1326 
   1327 static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) {
   1328     switch (config) {
   1329         case kAlpha_8_GrPixelConfig:
   1330         case kRGB_565_GrPixelConfig:
   1331         case kRGBA_4444_GrPixelConfig:
   1332         case kBGRA_8888_GrPixelConfig:
   1333         case kRGBA_1010102_GrPixelConfig:
   1334             return kRGBA_8888_GrPixelConfig;
   1335         case kSBGRA_8888_GrPixelConfig:
   1336             return kSRGBA_8888_GrPixelConfig;
   1337         case kAlpha_half_GrPixelConfig:
   1338             return kRGBA_half_GrPixelConfig;
   1339         default:
   1340             return kUnknown_GrPixelConfig;
   1341     }
   1342 }
   1343 
   1344 sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContextWithFallback(
   1345                                                                  SkBackingFit fit,
   1346                                                                  int width, int height,
   1347                                                                  GrPixelConfig config,
   1348                                                                  sk_sp<SkColorSpace> colorSpace,
   1349                                                                  int sampleCnt,
   1350                                                                  GrMipMapped mipMapped,
   1351                                                                  GrSurfaceOrigin origin,
   1352                                                                  const SkSurfaceProps* surfaceProps,
   1353                                                                  SkBudgeted budgeted) {
   1354     SkASSERT(sampleCnt > 0);
   1355     if (0 == this->caps()->getRenderTargetSampleCount(sampleCnt, config)) {
   1356         config = GrPixelConfigFallback(config);
   1357     }
   1358 
   1359     return this->makeDeferredRenderTargetContext(fit, width, height, config, std::move(colorSpace),
   1360                                                  sampleCnt, mipMapped, origin, surfaceProps,
   1361                                                  budgeted);
   1362 }
   1363 
   1364 sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContext(
   1365                                                         SkBackingFit fit,
   1366                                                         int width, int height,
   1367                                                         GrPixelConfig config,
   1368                                                         sk_sp<SkColorSpace> colorSpace,
   1369                                                         int sampleCnt,
   1370                                                         GrMipMapped mipMapped,
   1371                                                         GrSurfaceOrigin origin,
   1372                                                         const SkSurfaceProps* surfaceProps,
   1373                                                         SkBudgeted budgeted) {
   1374     SkASSERT(sampleCnt > 0);
   1375     if (this->abandoned()) {
   1376         return nullptr;
   1377     }
   1378 
   1379     GrSurfaceDesc desc;
   1380     desc.fFlags = kRenderTarget_GrSurfaceFlag;
   1381     desc.fOrigin = origin;
   1382     desc.fWidth = width;
   1383     desc.fHeight = height;
   1384     desc.fConfig = config;
   1385     desc.fSampleCnt = sampleCnt;
   1386 
   1387     sk_sp<GrTextureProxy> rtp;
   1388     if (GrMipMapped::kNo == mipMapped) {
   1389         rtp = fProxyProvider->createProxy(desc, fit, budgeted);
   1390     } else {
   1391         rtp = fProxyProvider->createMipMapProxy(desc, budgeted);
   1392     }
   1393     if (!rtp) {
   1394         return nullptr;
   1395     }
   1396 
   1397     sk_sp<GrRenderTargetContext> renderTargetContext(
   1398         fDrawingManager->makeRenderTargetContext(std::move(rtp),
   1399                                                  std::move(colorSpace),
   1400                                                  surfaceProps));
   1401     if (!renderTargetContext) {
   1402         return nullptr;
   1403     }
   1404 
   1405     renderTargetContext->discard();
   1406 
   1407     return renderTargetContext;
   1408 }
   1409 
   1410 bool GrContext::abandoned() const {
   1411     ASSERT_SINGLE_OWNER
   1412     return fDrawingManager->wasAbandoned();
   1413 }
   1414 
   1415 std::unique_ptr<GrFragmentProcessor> GrContext::createPMToUPMEffect(
   1416         std::unique_ptr<GrFragmentProcessor> fp, bool useConfigConversionEffect) {
   1417     ASSERT_SINGLE_OWNER
   1418     // We have specialized effects that guarantee round-trip conversion for some formats
   1419     if (useConfigConversionEffect) {
   1420         // We should have already called this->validPMUPMConversionExists() in this case
   1421         SkASSERT(fDidTestPMConversions);
   1422         // ...and it should have succeeded
   1423         SkASSERT(this->validPMUPMConversionExists());
   1424 
   1425         return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToUnpremul);
   1426     } else {
   1427         // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
   1428         // explicitly round the results. Just do the obvious, naive thing in the shader.
   1429         return GrFragmentProcessor::UnpremulOutput(std::move(fp));
   1430     }
   1431 }
   1432 
   1433 std::unique_ptr<GrFragmentProcessor> GrContext::createUPMToPMEffect(
   1434         std::unique_ptr<GrFragmentProcessor> fp, bool useConfigConversionEffect) {
   1435     ASSERT_SINGLE_OWNER
   1436     // We have specialized effects that guarantee round-trip conversion for these formats
   1437     if (useConfigConversionEffect) {
   1438         // We should have already called this->validPMUPMConversionExists() in this case
   1439         SkASSERT(fDidTestPMConversions);
   1440         // ...and it should have succeeded
   1441         SkASSERT(this->validPMUPMConversionExists());
   1442 
   1443         return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToPremul);
   1444     } else {
   1445         // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
   1446         // explicitly round the results. Just do the obvious, naive thing in the shader.
   1447         return GrFragmentProcessor::PremulOutput(std::move(fp));
   1448     }
   1449 }
   1450 
   1451 bool GrContext::validPMUPMConversionExists() {
   1452     ASSERT_SINGLE_OWNER
   1453     if (!fDidTestPMConversions) {
   1454         fPMUPMConversionsRoundTrip = GrConfigConversionEffect::TestForPreservingPMConversions(this);
   1455         fDidTestPMConversions = true;
   1456     }
   1457 
   1458     // The PM<->UPM tests fail or succeed together so we only need to check one.
   1459     return fPMUPMConversionsRoundTrip;
   1460 }
   1461 
   1462 //////////////////////////////////////////////////////////////////////////////
   1463 
   1464 // DDL TODO: remove 'maxResources'
   1465 void GrContext::getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const {
   1466     ASSERT_SINGLE_OWNER
   1467     if (maxResources) {
   1468         *maxResources = fResourceCache->getMaxResourceCount();
   1469     }
   1470     if (maxResourceBytes) {
   1471         *maxResourceBytes = fResourceCache->getMaxResourceBytes();
   1472     }
   1473 }
   1474 
   1475 void GrContext::setResourceCacheLimits(int maxResources, size_t maxResourceBytes) {
   1476     ASSERT_SINGLE_OWNER
   1477     fResourceCache->setLimits(maxResources, maxResourceBytes);
   1478 }
   1479 
   1480 //////////////////////////////////////////////////////////////////////////////
   1481 
   1482 void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
   1483     ASSERT_SINGLE_OWNER
   1484     fResourceCache->dumpMemoryStatistics(traceMemoryDump);
   1485 }
   1486 
   1487 //////////////////////////////////////////////////////////////////////////////
   1488 
   1489 SkString GrContext::dump() const {
   1490     SkDynamicMemoryWStream stream;
   1491     SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty);
   1492     writer.beginObject();
   1493 
   1494     static const char* kBackendStr[] = {
   1495         "Metal",
   1496         "OpenGL",
   1497         "Vulkan",
   1498         "Mock",
   1499     };
   1500     GR_STATIC_ASSERT(0 == kMetal_GrBackend);
   1501     GR_STATIC_ASSERT(1 == kOpenGL_GrBackend);
   1502     GR_STATIC_ASSERT(2 == kVulkan_GrBackend);
   1503     GR_STATIC_ASSERT(3 == kMock_GrBackend);
   1504     writer.appendString("backend", kBackendStr[fBackend]);
   1505 
   1506     writer.appendName("caps");
   1507     fCaps->dumpJSON(&writer);
   1508 
   1509     writer.appendName("gpu");
   1510     fGpu->dumpJSON(&writer);
   1511 
   1512     // Flush JSON to the memory stream
   1513     writer.endObject();
   1514     writer.flush();
   1515 
   1516     // Null terminate the JSON data in the memory stream
   1517     stream.write8(0);
   1518 
   1519     // Allocate a string big enough to hold all the data, then copy out of the stream
   1520     SkString result(stream.bytesWritten());
   1521     stream.copyToAndReset(result.writable_str());
   1522     return result;
   1523 }
   1524