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 "GrClip.h"
     10 #include "GrContextOptions.h"
     11 #include "GrContextPriv.h"
     12 #include "GrDrawingManager.h"
     13 #include "GrGpu.h"
     14 #include "GrRenderTargetContext.h"
     15 #include "GrRenderTargetProxy.h"
     16 #include "GrResourceCache.h"
     17 #include "GrResourceProvider.h"
     18 #include "GrSemaphore.h"
     19 #include "GrSoftwarePathRenderer.h"
     20 #include "GrSurfaceContext.h"
     21 #include "GrSurfacePriv.h"
     22 #include "GrSurfaceProxyPriv.h"
     23 #include "GrTexture.h"
     24 #include "GrTextureContext.h"
     25 #include "GrTracing.h"
     26 #include "SkConvertPixels.h"
     27 #include "SkGr.h"
     28 #include "SkUnPreMultiplyPriv.h"
     29 #include "effects/GrConfigConversionEffect.h"
     30 #include "text/GrTextBlobCache.h"
     31 
     32 #ifdef SK_METAL
     33 #include "mtl/GrMtlTrampoline.h"
     34 #endif
     35 
     36 #define ASSERT_OWNED_PROXY(P) \
     37 SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == this)
     38 #define ASSERT_OWNED_PROXY_PRIV(P) \
     39 SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == fContext)
     40 
     41 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
     42 #define ASSERT_SINGLE_OWNER \
     43     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);)
     44 #define ASSERT_SINGLE_OWNER_PRIV \
     45     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fContext->fSingleOwner);)
     46 #define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; }
     47 #define RETURN_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return; }
     48 #define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; }
     49 #define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return false; }
     50 #define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; }
     51 
     52 ////////////////////////////////////////////////////////////////////////////////
     53 
     54 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
     55     GrContextOptions defaultOptions;
     56     return Create(backend, backendContext, defaultOptions);
     57 }
     58 
     59 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
     60                              const GrContextOptions& options) {
     61     sk_sp<GrContext> context(new GrContext);
     62 
     63     if (!context->init(backend, backendContext, options)) {
     64         return nullptr;
     65     }
     66     return context.release();
     67 }
     68 
     69 #ifdef SK_METAL
     70 sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue, const GrContextOptions& options) {
     71     sk_sp<GrContext> context(new GrContext);
     72     context->fGpu = GrMtlTrampoline::CreateGpu(context.get(), options, device, queue);
     73     if (!context->fGpu) {
     74         return nullptr;
     75     }
     76     context->fBackend = kMetal_GrBackend;
     77     if (!context->init(options)) {
     78         return nullptr;
     79     }
     80     return context;
     81 }
     82 #endif
     83 
     84 static int32_t gNextID = 1;
     85 static int32_t next_id() {
     86     int32_t id;
     87     do {
     88         id = sk_atomic_inc(&gNextID);
     89     } while (id == SK_InvalidGenID);
     90     return id;
     91 }
     92 
     93 GrContext::GrContext() : fUniqueID(next_id()) {
     94     fGpu = nullptr;
     95     fCaps = nullptr;
     96     fResourceCache = nullptr;
     97     fResourceProvider = nullptr;
     98     fAtlasGlyphCache = nullptr;
     99 }
    100 
    101 bool GrContext::init(GrBackend backend, GrBackendContext backendContext,
    102                      const GrContextOptions& options) {
    103     ASSERT_SINGLE_OWNER
    104     SkASSERT(!fGpu);
    105 
    106     fBackend = backend;
    107 
    108     fGpu = GrGpu::Create(backend, backendContext, options, this);
    109     if (!fGpu) {
    110         return false;
    111     }
    112     return this->init(options);
    113 }
    114 
    115 bool GrContext::init(const GrContextOptions& options) {
    116     ASSERT_SINGLE_OWNER
    117     fCaps = SkRef(fGpu->caps());
    118     fResourceCache = new GrResourceCache(fCaps, fUniqueID);
    119     fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner);
    120 
    121     fDisableGpuYUVConversion = options.fDisableGpuYUVConversion;
    122     fDidTestPMConversions = false;
    123 
    124     GrPathRendererChain::Options prcOptions;
    125     prcOptions.fAllowPathMaskCaching = options.fAllowPathMaskCaching;
    126     prcOptions.fGpuPathRenderers = options.fGpuPathRenderers;
    127     fDrawingManager.reset(new GrDrawingManager(this, prcOptions, &fSingleOwner));
    128 
    129     fAtlasGlyphCache = new GrAtlasGlyphCache(this, options.fGlyphCacheTextureMaximumBytes);
    130 
    131     fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this));
    132 
    133     return true;
    134 }
    135 
    136 GrContext::~GrContext() {
    137     ASSERT_SINGLE_OWNER
    138 
    139     if (!fGpu) {
    140         SkASSERT(!fCaps);
    141         return;
    142     }
    143 
    144     this->flush();
    145 
    146     fDrawingManager->cleanup();
    147 
    148     for (int i = 0; i < fCleanUpData.count(); ++i) {
    149         (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
    150     }
    151 
    152     delete fResourceProvider;
    153     delete fResourceCache;
    154     delete fAtlasGlyphCache;
    155 
    156     fGpu->unref();
    157     fCaps->unref();
    158 }
    159 
    160 sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
    161     if (!fThreadSafeProxy) {
    162         fThreadSafeProxy.reset(new GrContextThreadSafeProxy(sk_ref_sp(fCaps), this->uniqueID()));
    163     }
    164     return fThreadSafeProxy;
    165 }
    166 
    167 void GrContext::abandonContext() {
    168     ASSERT_SINGLE_OWNER
    169 
    170     fResourceProvider->abandon();
    171 
    172     // Need to abandon the drawing manager first so all the render targets
    173     // will be released/forgotten before they too are abandoned.
    174     fDrawingManager->abandon();
    175 
    176     // abandon first to so destructors
    177     // don't try to free the resources in the API.
    178     fResourceCache->abandonAll();
    179 
    180     fGpu->disconnect(GrGpu::DisconnectType::kAbandon);
    181 
    182     fAtlasGlyphCache->freeAll();
    183     fTextBlobCache->freeAll();
    184 }
    185 
    186 void GrContext::releaseResourcesAndAbandonContext() {
    187     ASSERT_SINGLE_OWNER
    188 
    189     fResourceProvider->abandon();
    190 
    191     // Need to abandon the drawing manager first so all the render targets
    192     // will be released/forgotten before they too are abandoned.
    193     fDrawingManager->abandon();
    194 
    195     // Release all resources in the backend 3D API.
    196     fResourceCache->releaseAll();
    197 
    198     fGpu->disconnect(GrGpu::DisconnectType::kCleanup);
    199 
    200     fAtlasGlyphCache->freeAll();
    201     fTextBlobCache->freeAll();
    202 }
    203 
    204 void GrContext::resetContext(uint32_t state) {
    205     ASSERT_SINGLE_OWNER
    206     fGpu->markContextDirty(state);
    207 }
    208 
    209 void GrContext::freeGpuResources() {
    210     ASSERT_SINGLE_OWNER
    211 
    212     this->flush();
    213 
    214     fAtlasGlyphCache->freeAll();
    215 
    216     fDrawingManager->freeGpuResources();
    217 
    218     fResourceCache->purgeAllUnlocked();
    219 }
    220 
    221 void GrContext::purgeResourcesNotUsedInMs(std::chrono::milliseconds ms) {
    222     ASSERT_SINGLE_OWNER
    223     fResourceCache->purgeResourcesNotUsedSince(GrStdSteadyClock::now() - ms);
    224 }
    225 
    226 void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
    227     ASSERT_SINGLE_OWNER
    228     fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources);
    229 }
    230 
    231 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
    232     ASSERT_SINGLE_OWNER
    233 
    234     if (resourceCount) {
    235         *resourceCount = fResourceCache->getBudgetedResourceCount();
    236     }
    237     if (resourceBytes) {
    238         *resourceBytes = fResourceCache->getBudgetedResourceBytes();
    239     }
    240 }
    241 
    242 size_t GrContext::getResourceCachePurgeableBytes() const {
    243     ASSERT_SINGLE_OWNER
    244     return fResourceCache->getPurgeableBytes();
    245 }
    246 
    247 ////////////////////////////////////////////////////////////////////////////////
    248 
    249 void GrContext::TextBlobCacheOverBudgetCB(void* data) {
    250     SkASSERT(data);
    251     // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on
    252     // GrRenderTargetContext to perform a necessary flush.  The solution is to move drawText calls
    253     // to below the GrContext level, but this is not trivial because they call drawPath on
    254     // SkGpuDevice.
    255     GrContext* context = reinterpret_cast<GrContext*>(data);
    256     context->flush();
    257 }
    258 
    259 ////////////////////////////////////////////////////////////////////////////////
    260 
    261 void GrContext::flush() {
    262     ASSERT_SINGLE_OWNER
    263     RETURN_IF_ABANDONED
    264 
    265     fDrawingManager->flush(nullptr);
    266 }
    267 
    268 void GrContextPriv::flush(GrSurfaceProxy* proxy) {
    269     ASSERT_SINGLE_OWNER_PRIV
    270     RETURN_IF_ABANDONED_PRIV
    271     ASSERT_OWNED_PROXY_PRIV(proxy);
    272 
    273     fContext->fDrawingManager->flush(proxy);
    274 }
    275 
    276 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
    277                           const void* inPixels, size_t outRowBytes, void* outPixels) {
    278     SkColorType colorType;
    279     if (!GrPixelConfigToColorType(srcConfig, &colorType) ||
    280         4 != SkColorTypeBytesPerPixel(colorType))
    281     {
    282         return false;
    283     }
    284 
    285     for (int y = 0; y < height; y++) {
    286         SkOpts::RGBA_to_rgbA((uint32_t*) outPixels, inPixels, width);
    287         outPixels = SkTAddOffset<void>(outPixels, outRowBytes);
    288         inPixels = SkTAddOffset<const void>(inPixels, inRowBytes);
    289     }
    290 
    291     return true;
    292 }
    293 
    294 static bool valid_premul_config(GrPixelConfig config) {
    295     return GrPixelConfigIs8888Unorm(config) || kRGBA_half_GrPixelConfig == config;
    296 }
    297 
    298 static bool valid_pixel_conversion(GrPixelConfig srcConfig, GrPixelConfig dstConfig,
    299                                    bool premulConversion) {
    300     // We don't allow conversion between integer configs and float/fixed configs.
    301     if (GrPixelConfigIsSint(srcConfig) != GrPixelConfigIsSint(dstConfig)) {
    302         return false;
    303     }
    304 
    305     // We only allow premul <-> unpremul conversions for some formats
    306     if (premulConversion && (!valid_premul_config(srcConfig) || !valid_premul_config(dstConfig))) {
    307         return false;
    308     }
    309 
    310     return true;
    311 }
    312 
    313 static bool pm_upm_must_round_trip(GrPixelConfig config, SkColorSpace* colorSpace) {
    314     return !colorSpace &&
    315            (kRGBA_8888_GrPixelConfig == config || kBGRA_8888_GrPixelConfig == config);
    316 }
    317 
    318 bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst,
    319                                        int left, int top, int width, int height,
    320                                        GrPixelConfig srcConfig, SkColorSpace* srcColorSpace,
    321                                        const void* buffer, size_t rowBytes,
    322                                        uint32_t pixelOpsFlags) {
    323     // TODO: Color space conversion
    324 
    325     ASSERT_SINGLE_OWNER_PRIV
    326     RETURN_FALSE_IF_ABANDONED_PRIV
    327     SkASSERT(dst);
    328     ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy());
    329     GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels", fContext);
    330 
    331     if (!dst->asSurfaceProxy()->instantiate(fContext->resourceProvider())) {
    332         return false;
    333     }
    334 
    335     GrSurface* dstSurface = dst->asSurfaceProxy()->priv().peekSurface();
    336 
    337     // The src is unpremul but the dst is premul -> premul the src before or as part of the write
    338     const bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
    339     if (!valid_pixel_conversion(srcConfig, dstSurface->config(), premul)) {
    340         return false;
    341     }
    342 
    343     // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
    344     // without any color spaces attached, and the caller wants us to premul.
    345     bool useConfigConversionEffect =
    346                         premul &&
    347                         pm_upm_must_round_trip(srcConfig, srcColorSpace) &&
    348                         pm_upm_must_round_trip(dstSurface->config(), dst->getColorSpace());
    349 
    350     // Are we going to try to premul as part of a draw? For the non-legacy case, we always allow
    351     // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
    352     bool premulOnGpu = premul &&
    353                        (!useConfigConversionEffect || fContext->validPMUPMConversionExists());
    354 
    355     // Trim the params here so that if we wind up making a temporary surface it can be as small as
    356     // necessary and because GrGpu::getWritePixelsInfo requires it.
    357     if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(),
    358                                                GrBytesPerPixel(srcConfig), &left, &top, &width,
    359                                                &height, &buffer, &rowBytes)) {
    360         return false;
    361     }
    362 
    363     GrGpu::DrawPreference drawPreference = premulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
    364                                                        : GrGpu::kNoDraw_DrawPreference;
    365     GrGpu::WritePixelTempDrawInfo tempDrawInfo;
    366     if (!fContext->fGpu->getWritePixelsInfo(dstSurface, width, height, srcConfig,
    367                                             &drawPreference, &tempDrawInfo)) {
    368         return false;
    369     }
    370 
    371     if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) {
    372         this->flush(nullptr); // MDB TODO: tighten this
    373     }
    374 
    375     sk_sp<GrTextureProxy> tempProxy;
    376     if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
    377         tempProxy = GrSurfaceProxy::MakeDeferred(fContext->resourceProvider(),
    378                                                  tempDrawInfo.fTempSurfaceDesc,
    379                                                  SkBackingFit::kApprox,
    380                                                  SkBudgeted::kYes);
    381         if (!tempProxy && GrGpu::kRequireDraw_DrawPreference == drawPreference) {
    382             return false;
    383         }
    384     }
    385 
    386     // temp buffer for doing sw premul conversion, if needed.
    387     SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
    388     // We need to do sw premul if we were unable to create a RT for drawing, or if we can't do the
    389     // premul on the GPU
    390     if (premul && (!tempProxy || !premulOnGpu)) {
    391         size_t tmpRowBytes = 4 * width;
    392         tmpPixels.reset(width * height);
    393         if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
    394                                   tmpPixels.get())) {
    395             return false;
    396         }
    397         rowBytes = tmpRowBytes;
    398         buffer = tmpPixels.get();
    399     }
    400 
    401     if (tempProxy) {
    402         sk_sp<GrFragmentProcessor> fp = GrSimpleTextureEffect::Make(
    403                 tempProxy, nullptr, SkMatrix::I());
    404         if (premulOnGpu) {
    405             fp = fContext->createUPMToPMEffect(std::move(fp), useConfigConversionEffect);
    406         }
    407         fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
    408         if (!fp) {
    409             return false;
    410         }
    411 
    412         if (tempProxy->priv().hasPendingIO()) {
    413             this->flush(tempProxy.get());
    414         }
    415         if (!tempProxy->instantiate(fContext->resourceProvider())) {
    416             return false;
    417         }
    418         GrTexture* texture = tempProxy->priv().peekTexture();
    419         if (!fContext->fGpu->writePixels(texture, 0, 0, width, height, tempDrawInfo.fWriteConfig,
    420                                          buffer, rowBytes)) {
    421             return false;
    422         }
    423         SkMatrix matrix;
    424         matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
    425         GrRenderTargetContext* renderTargetContext = dst->asRenderTargetContext();
    426         if (!renderTargetContext) {
    427             return false;
    428         }
    429         GrPaint paint;
    430         paint.addColorFragmentProcessor(std::move(fp));
    431         paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
    432         paint.setAllowSRGBInputs(SkToBool(dst->getColorSpace()) ||
    433                                  GrPixelConfigIsSRGB(renderTargetContext->config()));
    434         SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
    435         renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, rect,
    436                                         nullptr);
    437 
    438         if (kFlushWrites_PixelOp & pixelOpsFlags) {
    439             this->flushSurfaceWrites(renderTargetContext->asRenderTargetProxy());
    440         }
    441     } else {
    442         return fContext->fGpu->writePixels(dstSurface, left, top, width, height, srcConfig,
    443                                            buffer, rowBytes);
    444     }
    445     return true;
    446 }
    447 
    448 bool GrContextPriv::readSurfacePixels(GrSurfaceContext* src,
    449                                       int left, int top, int width, int height,
    450                                       GrPixelConfig dstConfig, SkColorSpace* dstColorSpace,
    451                                       void* buffer, size_t rowBytes, uint32_t flags) {
    452     // TODO: Color space conversion
    453 
    454     ASSERT_SINGLE_OWNER_PRIV
    455     RETURN_FALSE_IF_ABANDONED_PRIV
    456     SkASSERT(src);
    457     ASSERT_OWNED_PROXY_PRIV(src->asSurfaceProxy());
    458     GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "readSurfacePixels", fContext);
    459 
    460     // MDB TODO: delay this instantiation until later in the method
    461     if (!src->asSurfaceProxy()->instantiate(fContext->resourceProvider())) {
    462         return false;
    463     }
    464 
    465     GrSurface* srcSurface = src->asSurfaceProxy()->priv().peekSurface();
    466 
    467     // The src is premul but the dst is unpremul -> unpremul the src after or as part of the read
    468     bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
    469     if (!valid_pixel_conversion(srcSurface->config(), dstConfig, unpremul)) {
    470         return false;
    471     }
    472 
    473     // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
    474     // without any color spaces attached, and the caller wants us to unpremul.
    475     bool useConfigConversionEffect =
    476                     unpremul &&
    477                     pm_upm_must_round_trip(srcSurface->config(), src->getColorSpace()) &&
    478                     pm_upm_must_round_trip(dstConfig, dstColorSpace);
    479 
    480     // Are we going to try to unpremul as part of a draw? For the non-legacy case, we always allow
    481     // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
    482     bool unpremulOnGpu = unpremul &&
    483                          (!useConfigConversionEffect || fContext->validPMUPMConversionExists());
    484 
    485     // Adjust the params so that if we wind up using an intermediate surface we've already done
    486     // all the trimming and the temporary can be the min size required.
    487     if (!GrSurfacePriv::AdjustReadPixelParams(srcSurface->width(), srcSurface->height(),
    488                                               GrBytesPerPixel(dstConfig), &left,
    489                                               &top, &width, &height, &buffer, &rowBytes)) {
    490         return false;
    491     }
    492 
    493     GrGpu::DrawPreference drawPreference = unpremulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
    494                                                          : GrGpu::kNoDraw_DrawPreference;
    495     GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
    496     if (!fContext->fGpu->getReadPixelsInfo(srcSurface, width, height, rowBytes, dstConfig,
    497                                            &drawPreference, &tempDrawInfo)) {
    498         return false;
    499     }
    500 
    501     if (!(kDontFlush_PixelOpsFlag & flags) && srcSurface->surfacePriv().hasPendingWrite()) {
    502         this->flush(nullptr); // MDB TODO: tighten this
    503     }
    504 
    505     sk_sp<GrSurfaceProxy> proxyToRead = src->asSurfaceProxyRef();
    506     bool didTempDraw = false;
    507     if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
    508         if (SkBackingFit::kExact == tempDrawInfo.fTempSurfaceFit) {
    509             // We only respect this when the entire src is being read. Otherwise we can trigger too
    510             // many odd ball texture sizes and trash the cache.
    511             if (width != srcSurface->width() || height != srcSurface->height()) {
    512                 tempDrawInfo.fTempSurfaceFit= SkBackingFit::kApprox;
    513             }
    514         }
    515         // TODO: Need to decide the semantics of this function for color spaces. Do we support
    516         // conversion to a passed-in color space? For now, specifying nullptr means that this
    517         // path will do no conversion, so it will match the behavior of the non-draw path.
    518         sk_sp<GrRenderTargetContext> tempRTC = fContext->makeDeferredRenderTargetContext(
    519                                                            tempDrawInfo.fTempSurfaceFit,
    520                                                            tempDrawInfo.fTempSurfaceDesc.fWidth,
    521                                                            tempDrawInfo.fTempSurfaceDesc.fHeight,
    522                                                            tempDrawInfo.fTempSurfaceDesc.fConfig,
    523                                                            nullptr,
    524                                                            tempDrawInfo.fTempSurfaceDesc.fSampleCnt,
    525                                                            tempDrawInfo.fTempSurfaceDesc.fOrigin);
    526         if (tempRTC) {
    527             SkMatrix textureMatrix = SkMatrix::MakeTrans(SkIntToScalar(left), SkIntToScalar(top));
    528             sk_sp<GrTextureProxy> proxy = src->asTextureProxyRef();
    529             sk_sp<GrFragmentProcessor> fp = GrSimpleTextureEffect::Make(
    530                     std::move(proxy), nullptr, textureMatrix);
    531             if (unpremulOnGpu) {
    532                 fp = fContext->createPMToUPMEffect(std::move(fp), useConfigConversionEffect);
    533                 // We no longer need to do this on CPU after the read back.
    534                 unpremul = false;
    535             }
    536             fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
    537             if (!fp) {
    538                 return false;
    539             }
    540 
    541             GrPaint paint;
    542             paint.addColorFragmentProcessor(std::move(fp));
    543             paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
    544             paint.setAllowSRGBInputs(true);
    545             SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
    546             tempRTC->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect,
    547                                 nullptr);
    548             proxyToRead = tempRTC->asTextureProxyRef();
    549             left = 0;
    550             top = 0;
    551             didTempDraw = true;
    552         }
    553     }
    554 
    555     if (!proxyToRead) {
    556         return false;
    557     }
    558 
    559     if (!proxyToRead->instantiate(fContext->resourceProvider())) {
    560         return false;
    561     }
    562 
    563     GrSurface* surfaceToRead = proxyToRead->priv().peekSurface();
    564 
    565     if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) {
    566         return false;
    567     }
    568     GrPixelConfig configToRead = dstConfig;
    569     if (didTempDraw) {
    570         this->flushSurfaceWrites(proxyToRead.get());
    571         configToRead = tempDrawInfo.fReadConfig;
    572     }
    573     if (!fContext->fGpu->readPixels(surfaceToRead, left, top, width, height, configToRead,
    574                                     buffer, rowBytes)) {
    575         return false;
    576     }
    577 
    578     // Perform umpremul conversion if we weren't able to perform it as a draw.
    579     if (unpremul) {
    580         SkColorType colorType;
    581         if (!GrPixelConfigToColorType(dstConfig, &colorType) ||
    582             4 != SkColorTypeBytesPerPixel(colorType))
    583         {
    584             return false;
    585         }
    586 
    587         for (int y = 0; y < height; y++) {
    588             SkUnpremultiplyRow<false>((uint32_t*) buffer, (const uint32_t*) buffer, width);
    589             buffer = SkTAddOffset<void>(buffer, rowBytes);
    590         }
    591     }
    592     return true;
    593 }
    594 
    595 void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) {
    596     ASSERT_SINGLE_OWNER_PRIV
    597     RETURN_IF_ABANDONED_PRIV
    598     SkASSERT(proxy);
    599     ASSERT_OWNED_PROXY_PRIV(proxy);
    600     fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy);
    601 }
    602 
    603 void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) {
    604     ASSERT_SINGLE_OWNER_PRIV
    605     RETURN_IF_ABANDONED_PRIV
    606     SkASSERT(proxy);
    607     ASSERT_OWNED_PROXY_PRIV(proxy);
    608     if (proxy->priv().hasPendingWrite()) {
    609         this->flush(proxy);
    610     }
    611 }
    612 
    613 void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) {
    614     ASSERT_SINGLE_OWNER_PRIV
    615     RETURN_IF_ABANDONED_PRIV
    616     SkASSERT(proxy);
    617     ASSERT_OWNED_PROXY_PRIV(proxy);
    618     if (proxy->priv().hasPendingIO()) {
    619         this->flush(proxy);
    620     }
    621 }
    622 
    623 ////////////////////////////////////////////////////////////////////////////////
    624 int GrContext::getRecommendedSampleCount(GrPixelConfig config,
    625                                          SkScalar dpi) const {
    626     ASSERT_SINGLE_OWNER
    627 
    628     if (!this->caps()->isConfigRenderable(config, true)) {
    629         return 0;
    630     }
    631     int chosenSampleCount = 0;
    632     if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) {
    633         if (dpi >= 250.0f) {
    634             chosenSampleCount = 4;
    635         } else {
    636             chosenSampleCount = 16;
    637         }
    638     }
    639     int supportedSampleCount = fGpu->caps()->getSampleCount(chosenSampleCount, config);
    640     return chosenSampleCount <= supportedSampleCount ? supportedSampleCount : 0;
    641 }
    642 
    643 sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy,
    644                                                                  sk_sp<SkColorSpace> colorSpace) {
    645     ASSERT_SINGLE_OWNER_PRIV
    646 
    647     if (proxy->asRenderTargetProxy()) {
    648         return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
    649                                                                std::move(colorSpace), nullptr);
    650     } else {
    651         SkASSERT(proxy->asTextureProxy());
    652         return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
    653     }
    654 }
    655 
    656 sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc,
    657                                                                   SkBackingFit fit,
    658                                                                   SkBudgeted isDstBudgeted) {
    659 
    660     sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeDeferred(fContext->resourceProvider(),
    661                                                                dstDesc, fit, isDstBudgeted);
    662     if (!proxy) {
    663         return nullptr;
    664     }
    665 
    666     return this->makeWrappedSurfaceContext(std::move(proxy), nullptr);
    667 }
    668 
    669 sk_sp<GrSurfaceContext> GrContextPriv::makeBackendSurfaceContext(const GrBackendTexture& tex,
    670                                                                  GrSurfaceOrigin origin,
    671                                                                  GrBackendTextureFlags flags,
    672                                                                  int sampleCnt,
    673                                                                  sk_sp<SkColorSpace> colorSpace) {
    674     ASSERT_SINGLE_OWNER_PRIV
    675 
    676     sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTexture(tex, origin,
    677                                                                               flags, sampleCnt));
    678     if (!surface) {
    679         return nullptr;
    680     }
    681 
    682     sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
    683     if (!proxy) {
    684         return nullptr;
    685     }
    686 
    687     return this->makeWrappedSurfaceContext(std::move(proxy), std::move(colorSpace));
    688 }
    689 
    690 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext(
    691                                                                    const GrBackendTexture& tex,
    692                                                                    GrSurfaceOrigin origin,
    693                                                                    int sampleCnt,
    694                                                                    sk_sp<SkColorSpace> colorSpace,
    695                                                                    const SkSurfaceProps* props) {
    696     ASSERT_SINGLE_OWNER_PRIV
    697 
    698     static const GrBackendTextureFlags kForceRT = kRenderTarget_GrBackendTextureFlag;
    699     sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTexture(tex, origin, kForceRT,
    700                                                                               sampleCnt));
    701     if (!surface) {
    702         return nullptr;
    703     }
    704 
    705     sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
    706     if (!proxy) {
    707         return nullptr;
    708     }
    709 
    710     return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
    711                                                            std::move(colorSpace), props);
    712 }
    713 
    714 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext(
    715                                                 const GrBackendRenderTarget& backendRT,
    716                                                 GrSurfaceOrigin origin,
    717                                                 sk_sp<SkColorSpace> colorSpace,
    718                                                 const SkSurfaceProps* surfaceProps) {
    719     ASSERT_SINGLE_OWNER_PRIV
    720 
    721     sk_sp<GrRenderTarget> rt(fContext->resourceProvider()->wrapBackendRenderTarget(backendRT,
    722                                                                                    origin));
    723     if (!rt) {
    724         return nullptr;
    725     }
    726 
    727     sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(rt)));
    728     if (!proxy) {
    729         return nullptr;
    730     }
    731 
    732     return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
    733                                                            std::move(colorSpace),
    734                                                            surfaceProps);
    735 }
    736 
    737 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext(
    738                                                      const GrBackendTexture& tex,
    739                                                      GrSurfaceOrigin origin,
    740                                                      int sampleCnt,
    741                                                      sk_sp<SkColorSpace> colorSpace,
    742                                                      const SkSurfaceProps* surfaceProps) {
    743     ASSERT_SINGLE_OWNER_PRIV
    744 
    745     sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTextureAsRenderTarget(
    746                                                                                         tex,
    747                                                                                         origin,
    748                                                                                         sampleCnt));
    749     if (!surface) {
    750         return nullptr;
    751     }
    752 
    753     sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
    754     if (!proxy) {
    755         return nullptr;
    756     }
    757 
    758     return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
    759                                                            std::move(colorSpace),
    760                                                            surfaceProps);
    761 }
    762 
    763 void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
    764     fContext->fDrawingManager->addOnFlushCallbackObject(onFlushCBObject);
    765 }
    766 
    767 
    768 static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) {
    769     switch (config) {
    770         case kAlpha_8_GrPixelConfig:
    771         case kRGB_565_GrPixelConfig:
    772         case kRGBA_4444_GrPixelConfig:
    773         case kBGRA_8888_GrPixelConfig:
    774             return kRGBA_8888_GrPixelConfig;
    775         case kSBGRA_8888_GrPixelConfig:
    776             return kSRGBA_8888_GrPixelConfig;
    777         case kAlpha_half_GrPixelConfig:
    778             return kRGBA_half_GrPixelConfig;
    779         default:
    780             return kUnknown_GrPixelConfig;
    781     }
    782 }
    783 
    784 sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContextWithFallback(
    785                                                                  SkBackingFit fit,
    786                                                                  int width, int height,
    787                                                                  GrPixelConfig config,
    788                                                                  sk_sp<SkColorSpace> colorSpace,
    789                                                                  int sampleCnt,
    790                                                                  GrSurfaceOrigin origin,
    791                                                                  const SkSurfaceProps* surfaceProps,
    792                                                                  SkBudgeted budgeted) {
    793     if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) {
    794         config = GrPixelConfigFallback(config);
    795     }
    796 
    797     return this->makeDeferredRenderTargetContext(fit, width, height, config, std::move(colorSpace),
    798                                                  sampleCnt, origin, surfaceProps, budgeted);
    799 }
    800 
    801 sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContext(
    802                                                         SkBackingFit fit,
    803                                                         int width, int height,
    804                                                         GrPixelConfig config,
    805                                                         sk_sp<SkColorSpace> colorSpace,
    806                                                         int sampleCnt,
    807                                                         GrSurfaceOrigin origin,
    808                                                         const SkSurfaceProps* surfaceProps,
    809                                                         SkBudgeted budgeted) {
    810     SkASSERT(kDefault_GrSurfaceOrigin != origin);
    811 
    812     if (this->abandoned()) {
    813         return nullptr;
    814     }
    815 
    816     GrSurfaceDesc desc;
    817     desc.fFlags = kRenderTarget_GrSurfaceFlag;
    818     desc.fOrigin = origin;
    819     desc.fWidth = width;
    820     desc.fHeight = height;
    821     desc.fConfig = config;
    822     desc.fSampleCnt = sampleCnt;
    823 
    824     sk_sp<GrTextureProxy> rtp = GrSurfaceProxy::MakeDeferred(this->resourceProvider(),
    825                                                              desc, fit, budgeted);
    826     if (!rtp) {
    827         return nullptr;
    828     }
    829 
    830     sk_sp<GrRenderTargetContext> renderTargetContext(
    831         fDrawingManager->makeRenderTargetContext(std::move(rtp),
    832                                                  std::move(colorSpace),
    833                                                  surfaceProps));
    834     if (!renderTargetContext) {
    835         return nullptr;
    836     }
    837 
    838     renderTargetContext->discard();
    839 
    840     return renderTargetContext;
    841 }
    842 
    843 bool GrContext::abandoned() const {
    844     ASSERT_SINGLE_OWNER
    845     return fDrawingManager->wasAbandoned();
    846 }
    847 
    848 sk_sp<GrFragmentProcessor> GrContext::createPMToUPMEffect(sk_sp<GrFragmentProcessor> fp,
    849                                                           bool useConfigConversionEffect) {
    850     ASSERT_SINGLE_OWNER
    851     // We have specialized effects that guarantee round-trip conversion for some formats
    852     if (useConfigConversionEffect) {
    853         // We should have already called this->validPMUPMConversionExists() in this case
    854         SkASSERT(fDidTestPMConversions);
    855         // ...and it should have succeeded
    856         SkASSERT(this->validPMUPMConversionExists());
    857 
    858         return GrConfigConversionEffect::Make(std::move(fp),
    859                                               GrConfigConversionEffect::kToUnpremul_PMConversion);
    860     } else {
    861         // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
    862         // explicitly round the results. Just do the obvious, naive thing in the shader.
    863         return GrFragmentProcessor::UnpremulOutput(std::move(fp));
    864     }
    865 }
    866 
    867 sk_sp<GrFragmentProcessor> GrContext::createUPMToPMEffect(sk_sp<GrFragmentProcessor> fp,
    868                                                           bool useConfigConversionEffect) {
    869     ASSERT_SINGLE_OWNER
    870     // We have specialized effects that guarantee round-trip conversion for these formats
    871     if (useConfigConversionEffect) {
    872         // We should have already called this->validPMUPMConversionExists() in this case
    873         SkASSERT(fDidTestPMConversions);
    874         // ...and it should have succeeded
    875         SkASSERT(this->validPMUPMConversionExists());
    876 
    877         return GrConfigConversionEffect::Make(std::move(fp),
    878                                               GrConfigConversionEffect::kToPremul_PMConversion);
    879     } else {
    880         // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
    881         // explicitly round the results. Just do the obvious, naive thing in the shader.
    882         return GrFragmentProcessor::PremulOutput(std::move(fp));
    883     }
    884 }
    885 
    886 bool GrContext::validPMUPMConversionExists() {
    887     ASSERT_SINGLE_OWNER
    888     if (!fDidTestPMConversions) {
    889         fPMUPMConversionsRoundTrip = GrConfigConversionEffect::TestForPreservingPMConversions(this);
    890         fDidTestPMConversions = true;
    891     }
    892 
    893     // The PM<->UPM tests fail or succeed together so we only need to check one.
    894     return fPMUPMConversionsRoundTrip;
    895 }
    896 
    897 //////////////////////////////////////////////////////////////////////////////
    898 
    899 void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
    900     ASSERT_SINGLE_OWNER
    901     if (maxTextures) {
    902         *maxTextures = fResourceCache->getMaxResourceCount();
    903     }
    904     if (maxTextureBytes) {
    905         *maxTextureBytes = fResourceCache->getMaxResourceBytes();
    906     }
    907 }
    908 
    909 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
    910     ASSERT_SINGLE_OWNER
    911     fResourceCache->setLimits(maxTextures, maxTextureBytes);
    912 }
    913 
    914 //////////////////////////////////////////////////////////////////////////////
    915 
    916 void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
    917     ASSERT_SINGLE_OWNER
    918     fResourceCache->dumpMemoryStatistics(traceMemoryDump);
    919 }
    920