Home | History | Annotate | Download | only in image
      1 /*
      2  * Copyright 2012 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 <cstddef>
      9 #include <cstring>
     10 #include <type_traits>
     11 
     12 #include "SkAutoPixmapStorage.h"
     13 #include "GrBackendSurface.h"
     14 #include "GrBackendTextureImageGenerator.h"
     15 #include "GrAHardwareBufferImageGenerator.h"
     16 #include "GrBitmapTextureMaker.h"
     17 #include "GrCaps.h"
     18 #include "GrContext.h"
     19 #include "GrContextPriv.h"
     20 #include "GrGpu.h"
     21 #include "GrImageTextureMaker.h"
     22 #include "GrProxyProvider.h"
     23 #include "GrRenderTargetContext.h"
     24 #include "GrResourceProvider.h"
     25 #include "GrSemaphore.h"
     26 #include "GrSurfacePriv.h"
     27 #include "GrTextureAdjuster.h"
     28 #include "GrTexture.h"
     29 #include "GrTexturePriv.h"
     30 #include "GrTextureProxy.h"
     31 #include "effects/GrNonlinearColorSpaceXformEffect.h"
     32 #include "effects/GrYUVtoRGBEffect.h"
     33 #include "SkCanvas.h"
     34 #include "SkBitmapCache.h"
     35 #include "SkGr.h"
     36 #include "SkImage_Gpu.h"
     37 #include "SkImageCacherator.h"
     38 #include "SkImageInfoPriv.h"
     39 #include "SkMipMap.h"
     40 #include "SkPixelRef.h"
     41 #include "SkReadPixelsRec.h"
     42 
     43 SkImage_Gpu::SkImage_Gpu(GrContext* context, uint32_t uniqueID, SkAlphaType at,
     44                          sk_sp<GrTextureProxy> proxy,
     45                          sk_sp<SkColorSpace> colorSpace, SkBudgeted budgeted)
     46     : INHERITED(proxy->worstCaseWidth(), proxy->worstCaseHeight(), uniqueID)
     47     , fContext(context)
     48     , fProxy(std::move(proxy))
     49     , fAlphaType(at)
     50     , fBudgeted(budgeted)
     51     , fColorSpace(std::move(colorSpace))
     52     , fAddedRasterVersionToCache(false) {
     53 }
     54 
     55 SkImage_Gpu::~SkImage_Gpu() {
     56     if (fAddedRasterVersionToCache.load()) {
     57         SkNotifyBitmapGenIDIsStale(this->uniqueID());
     58     }
     59 }
     60 
     61 SkImageInfo SkImage_Gpu::onImageInfo() const {
     62     SkColorType ct;
     63     if (!GrPixelConfigToColorType(fProxy->config(), &ct)) {
     64         ct = kUnknown_SkColorType;
     65     }
     66     return SkImageInfo::Make(fProxy->width(), fProxy->height(), ct, fAlphaType, fColorSpace);
     67 }
     68 
     69 bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkColorSpace*, CachingHint chint) const {
     70     // The SkColorSpace parameter "dstColorSpace" is really just a hint about how/where the bitmap
     71     // will be used. The client doesn't expect that we convert to that color space, it's intended
     72     // for codec-backed images, to drive our decoding heuristic. In theory we *could* read directly
     73     // into that color space (to save the client some effort in whatever they're about to do), but
     74     // that would make our use of the bitmap cache incorrect (or much less efficient, assuming we
     75     // rolled the dstColorSpace into the key).
     76     const auto desc = SkBitmapCacheDesc::Make(this);
     77     if (SkBitmapCache::Find(desc, dst)) {
     78         SkASSERT(dst->getGenerationID() == this->uniqueID());
     79         SkASSERT(dst->isImmutable());
     80         SkASSERT(dst->getPixels());
     81         return true;
     82     }
     83 
     84     SkBitmapCache::RecPtr rec = nullptr;
     85     SkPixmap pmap;
     86     if (kAllow_CachingHint == chint) {
     87         rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap);
     88         if (!rec) {
     89             return false;
     90         }
     91     } else {
     92         if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) {
     93             return false;
     94         }
     95     }
     96 
     97     sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
     98                                                                                     fProxy,
     99                                                                                     fColorSpace);
    100     if (!sContext) {
    101         return false;
    102     }
    103 
    104     if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
    105         return false;
    106     }
    107 
    108     if (rec) {
    109         SkBitmapCache::Add(std::move(rec), dst);
    110         fAddedRasterVersionToCache.store(true);
    111     }
    112     return true;
    113 }
    114 
    115 sk_sp<GrTextureProxy> SkImage_Gpu::asTextureProxyRef(GrContext* context,
    116                                                      const GrSamplerState& params,
    117                                                      SkColorSpace* dstColorSpace,
    118                                                      sk_sp<SkColorSpace>* texColorSpace,
    119                                                      SkScalar scaleAdjust[2]) const {
    120     if (context != fContext) {
    121         SkASSERT(0);
    122         return nullptr;
    123     }
    124 
    125     if (texColorSpace) {
    126         *texColorSpace = this->fColorSpace;
    127     }
    128 
    129     GrTextureAdjuster adjuster(fContext, fProxy, this->alphaType(), this->uniqueID(),
    130                                this->fColorSpace.get());
    131     return adjuster.refTextureProxySafeForParams(params, scaleAdjust);
    132 }
    133 
    134 static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
    135     switch (info.colorType()) {
    136         case kRGBA_8888_SkColorType:
    137         case kBGRA_8888_SkColorType:
    138             break;
    139         default:
    140             return; // nothing to do
    141     }
    142 
    143     // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian,
    144     // and in either case, the alpha-byte is always in the same place, so we can safely call
    145     // SkPreMultiplyColor()
    146     //
    147     SkColor* row = (SkColor*)pixels;
    148     for (int y = 0; y < info.height(); ++y) {
    149         for (int x = 0; x < info.width(); ++x) {
    150             row[x] = SkPreMultiplyColor(row[x]);
    151         }
    152     }
    153 }
    154 
    155 GrBackendObject SkImage_Gpu::onGetTextureHandle(bool flushPendingGrContextIO,
    156                                                 GrSurfaceOrigin* origin) const {
    157     SkASSERT(fProxy);
    158 
    159     if (!fContext->contextPriv().resourceProvider() && !fProxy->priv().isInstantiated()) {
    160         // This image was created with a DDL context and cannot be instantiated. Thus we return 0
    161         // here which is considered invalid for all backends.
    162         return 0;
    163     }
    164 
    165     if (GrSurfaceProxy::LazyState::kNot != fProxy->lazyInstantiationState()) {
    166         SkASSERT(fContext->contextPriv().resourceProvider());
    167         fProxy->priv().doLazyInstantiation(fContext->contextPriv().resourceProvider());
    168         if (!fProxy->priv().isInstantiated()) {
    169             // We failed to instantiate the lazy proxy. Thus we return 0 here which is considered
    170             // invalid for all backends.
    171             return 0;
    172         }
    173     }
    174 
    175     if (!fProxy->instantiate(fContext->contextPriv().resourceProvider())) {
    176         return 0;
    177     }
    178 
    179     GrTexture* texture = fProxy->priv().peekTexture();
    180 
    181     if (texture) {
    182         if (flushPendingGrContextIO) {
    183             fContext->contextPriv().prepareSurfaceForExternalIO(fProxy.get());
    184         }
    185         if (origin) {
    186             *origin = fProxy->origin();
    187         }
    188         return texture->getTextureHandle();
    189     }
    190     return 0;
    191 }
    192 
    193 GrTexture* SkImage_Gpu::onGetTexture() const {
    194     GrTextureProxy* proxy = this->peekProxy();
    195     if (!proxy) {
    196         return nullptr;
    197     }
    198 
    199     if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) {
    200         return nullptr;
    201     }
    202 
    203     return proxy->priv().peekTexture();
    204 }
    205 
    206 bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
    207                                int srcX, int srcY, CachingHint) const {
    208     if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) {
    209         return false;
    210     }
    211 
    212     SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, srcX, srcY);
    213     if (!rec.trim(this->width(), this->height())) {
    214         return false;
    215     }
    216 
    217     // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and
    218     // GrRenderTargetContext::onReadPixels
    219     uint32_t flags = 0;
    220     if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) {
    221         // let the GPU perform this transformation for us
    222         flags = GrContextPriv::kUnpremul_PixelOpsFlag;
    223     }
    224 
    225     // This hack allows us to call makeNonTextureImage on images with arbitrary color spaces.
    226     // Otherwise, we'll be unable to create a render target context.
    227     // TODO: This shouldn't be necessary - we need more robust support for images (and surfaces)
    228     // with arbitrary color spaces. Unfortunately, this is one spot where we go from image to
    229     // surface (rather than the opposite), and our lenient image rules break our (currently) more
    230     // strict surface rules.
    231     // We treat null-dst color space as always equal to fColorSpace for this kind of read-back.
    232     sk_sp<SkColorSpace> surfaceColorSpace = fColorSpace;
    233     if (!flags) {
    234         if (!dstInfo.colorSpace() ||
    235                 SkColorSpace::Equals(fColorSpace.get(), dstInfo.colorSpace())) {
    236             surfaceColorSpace = nullptr;
    237         }
    238     }
    239 
    240     sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
    241             fProxy, surfaceColorSpace);
    242     if (!sContext) {
    243         return false;
    244     }
    245 
    246     if (!sContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, flags)) {
    247         return false;
    248     }
    249 
    250     // do we have to manually fix-up the alpha channel?
    251     //      src         dst
    252     //      unpremul    premul      fix manually
    253     //      premul      unpremul    done by kUnpremul_PixelOpsFlag
    254     // all other combos need to change.
    255     //
    256     // Should this be handled by Ganesh? todo:?
    257     //
    258     if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
    259         apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes);
    260     }
    261     return true;
    262 }
    263 
    264 sk_sp<SkImage> SkImage_Gpu::onMakeSubset(const SkIRect& subset) const {
    265     GrSurfaceDesc desc;
    266     desc.fOrigin = fProxy->origin();
    267     desc.fWidth = subset.width();
    268     desc.fHeight = subset.height();
    269     desc.fConfig = fProxy->config();
    270 
    271     sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext(
    272                                                                         desc,
    273                                                                         GrMipMapped::kNo,
    274                                                                         SkBackingFit::kExact,
    275                                                                         fBudgeted));
    276     if (!sContext) {
    277         return nullptr;
    278     }
    279 
    280     if (!sContext->copy(fProxy.get(), subset, SkIPoint::Make(0, 0))) {
    281         return nullptr;
    282     }
    283 
    284     // MDB: this call is okay bc we know 'sContext' was kExact
    285     return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
    286                                    fAlphaType, sContext->asTextureProxyRef(),
    287                                    fColorSpace, fBudgeted);
    288 }
    289 
    290 ///////////////////////////////////////////////////////////////////////////////////////////////////
    291 
    292 static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx,
    293                                                  const GrBackendTexture& backendTex,
    294                                                  GrSurfaceOrigin origin,
    295                                                  SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
    296                                                  GrWrapOwnership ownership,
    297                                                  SkImage::TextureReleaseProc releaseProc,
    298                                                  SkImage::ReleaseContext releaseCtx) {
    299     if (backendTex.width() <= 0 || backendTex.height() <= 0) {
    300         return nullptr;
    301     }
    302 
    303     GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
    304     sk_sp<GrTextureProxy> proxy = proxyProvider->createWrappedTextureProxy(
    305                                         backendTex, origin, ownership, releaseProc, releaseCtx);
    306     if (!proxy) {
    307         return nullptr;
    308     }
    309 
    310     return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
    311                                    at, std::move(proxy), std::move(colorSpace), SkBudgeted::kNo);
    312 }
    313 
    314 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
    315                                         const GrBackendTexture& tex, GrSurfaceOrigin origin,
    316                                         SkAlphaType at, sk_sp<SkColorSpace> cs,
    317                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
    318     if (!ctx) {
    319         return nullptr;
    320     }
    321     return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kBorrow_GrWrapOwnership,
    322                                       releaseP, releaseC);
    323 }
    324 
    325 bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex, GrPixelConfig* config,
    326                               SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs) {
    327     // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
    328     // create a fake image info here.
    329     SkImageInfo info = SkImageInfo::Make(1, 1, ct, at, cs);
    330     if (!SkImageInfoIsValidAllowNumericalCS(info)) {
    331         return false;
    332     }
    333 
    334     return ctx->caps()->validateBackendTexture(tex, ct, config);
    335 }
    336 
    337 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
    338                                         const GrBackendTexture& tex, GrSurfaceOrigin origin,
    339                                         SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
    340                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
    341     if (!ctx) {
    342         return nullptr;
    343     }
    344     GrBackendTexture texCopy = tex;
    345     if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
    346         return nullptr;
    347     }
    348     return MakeFromTexture(ctx, texCopy, origin, at, cs, releaseP, releaseC);
    349 }
    350 
    351 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
    352                                                const GrBackendTexture& tex, GrSurfaceOrigin origin,
    353                                                SkAlphaType at, sk_sp<SkColorSpace> cs) {
    354     if (!ctx->contextPriv().resourceProvider()) {
    355         // We have a DDL context and we don't support adopted textures for them.
    356         return nullptr;
    357     }
    358     return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kAdopt_GrWrapOwnership,
    359                                       nullptr, nullptr);
    360 }
    361 
    362 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
    363                                                const GrBackendTexture& tex, GrSurfaceOrigin origin,
    364                                                SkColorType ct, SkAlphaType at,
    365                                                sk_sp<SkColorSpace> cs) {
    366     GrBackendTexture texCopy = tex;
    367     if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
    368         return nullptr;
    369     }
    370     return MakeFromAdoptedTexture(ctx, texCopy, origin, at, cs);
    371 }
    372 
    373 static GrBackendTexture make_backend_texture_from_handle(GrBackend backend,
    374                                                          int width, int height,
    375                                                          GrPixelConfig config,
    376                                                          GrBackendObject handle) {
    377     switch (backend) {
    378         case kOpenGL_GrBackend: {
    379             const GrGLTextureInfo* glInfo = (const GrGLTextureInfo*)(handle);
    380             return GrBackendTexture(width, height, config, *glInfo);
    381         }
    382 #ifdef SK_VULKAN
    383         case kVulkan_GrBackend: {
    384             const GrVkImageInfo* vkInfo = (const GrVkImageInfo*)(handle);
    385             return GrBackendTexture(width, height, *vkInfo);
    386         }
    387 #endif
    388         case kMock_GrBackend: {
    389             const GrMockTextureInfo* mockInfo = (const GrMockTextureInfo*)(handle);
    390             return GrBackendTexture(width, height, config, *mockInfo);
    391         }
    392         default:
    393             return GrBackendTexture();
    394     }
    395 }
    396 
    397 static bool are_yuv_sizes_valid(const SkISize yuvSizes[], bool nv12) {
    398     if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 ||
    399         yuvSizes[1].fWidth <= 0 || yuvSizes[1].fHeight <= 0) {
    400         return false;
    401     }
    402     if (!nv12 && (yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0)) {
    403         return false;
    404     }
    405 
    406     return true;
    407 }
    408 
    409 static sk_sp<SkImage> make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpace colorSpace,
    410                                                   bool nv12,
    411                                                   const GrBackendTexture yuvBackendTextures[],
    412                                                   const SkISize yuvSizes[],
    413                                                   GrSurfaceOrigin origin,
    414                                                   sk_sp<SkColorSpace> imageColorSpace) {
    415     GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
    416 
    417     if (!are_yuv_sizes_valid(yuvSizes, nv12)) {
    418         return nullptr;
    419     }
    420 
    421     sk_sp<GrTextureProxy> yProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[0],
    422                                                                             origin);
    423     sk_sp<GrTextureProxy> uProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[1],
    424                                                                             origin);
    425     sk_sp<GrTextureProxy> vProxy;
    426 
    427     if (nv12) {
    428         vProxy = uProxy;
    429     } else {
    430         vProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[2], origin);
    431     }
    432     if (!yProxy || !uProxy || !vProxy) {
    433         return nullptr;
    434     }
    435 
    436     const int width = yuvSizes[0].fWidth;
    437     const int height = yuvSizes[0].fHeight;
    438 
    439     // Needs to be a render target in order to draw to it for the yuv->rgb conversion.
    440     sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeDeferredRenderTargetContext(
    441             SkBackingFit::kExact, width, height, kRGBA_8888_GrPixelConfig,
    442             std::move(imageColorSpace), 1, GrMipMapped::kNo, origin));
    443     if (!renderTargetContext) {
    444         return nullptr;
    445     }
    446 
    447     GrPaint paint;
    448     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
    449     paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Make(yProxy, uProxy, vProxy,
    450                                                            yuvSizes, colorSpace, nv12));
    451 
    452     const SkRect rect = SkRect::MakeIWH(width, height);
    453 
    454     renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
    455 
    456     if (!renderTargetContext->asSurfaceProxy()) {
    457         return nullptr;
    458     }
    459     ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());
    460 
    461     // MDB: this call is okay bc we know 'renderTargetContext' was exact
    462     return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID, kOpaque_SkAlphaType,
    463                                    renderTargetContext->asTextureProxyRef(),
    464                                    renderTargetContext->colorSpaceInfo().refColorSpace(),
    465                                    SkBudgeted::kYes);
    466 }
    467 
    468 static sk_sp<SkImage> make_from_yuv_objects_copy(GrContext* ctx, SkYUVColorSpace colorSpace,
    469                                                  bool nv12,
    470                                                  const GrBackendObject yuvTextureHandles[],
    471                                                  const SkISize yuvSizes[],
    472                                                  GrSurfaceOrigin origin,
    473                                                  sk_sp<SkColorSpace> imageColorSpace) {
    474     if (!are_yuv_sizes_valid(yuvSizes, nv12)) {
    475         return nullptr;
    476     }
    477 
    478     GrBackendTexture backendTextures[3];
    479 
    480     const GrPixelConfig kConfig = nv12 ? kRGBA_8888_GrPixelConfig : kAlpha_8_GrPixelConfig;
    481 
    482     GrBackend backend = ctx->contextPriv().getBackend();
    483     backendTextures[0] = make_backend_texture_from_handle(backend,
    484                                                           yuvSizes[0].fWidth,
    485                                                           yuvSizes[0].fHeight,
    486                                                           kConfig,
    487                                                           yuvTextureHandles[0]);
    488     backendTextures[1] = make_backend_texture_from_handle(backend,
    489                                                           yuvSizes[1].fWidth,
    490                                                           yuvSizes[1].fHeight,
    491                                                           kConfig,
    492                                                           yuvTextureHandles[1]);
    493 
    494     if (!nv12) {
    495         backendTextures[2] = make_backend_texture_from_handle(backend,
    496                                                               yuvSizes[2].fWidth,
    497                                                               yuvSizes[2].fHeight,
    498                                                               kConfig,
    499                                                               yuvTextureHandles[2]);
    500     }
    501 
    502     return make_from_yuv_textures_copy(ctx, colorSpace, nv12,
    503                                        backendTextures, yuvSizes, origin,
    504                                        std::move(imageColorSpace));
    505 }
    506 
    507 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
    508                                                 const GrBackendObject yuvTextureHandles[3],
    509                                                 const SkISize yuvSizes[3], GrSurfaceOrigin origin,
    510                                                 sk_sp<SkColorSpace> imageColorSpace) {
    511     return make_from_yuv_objects_copy(ctx, colorSpace, false, yuvTextureHandles, yuvSizes, origin,
    512                                       std::move(imageColorSpace));
    513 }
    514 
    515 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
    516                                                  const GrBackendObject yuvTextureHandles[2],
    517                                                  const SkISize yuvSizes[2],
    518                                                  GrSurfaceOrigin origin,
    519                                                  sk_sp<SkColorSpace> imageColorSpace) {
    520     return make_from_yuv_objects_copy(ctx, colorSpace, true, yuvTextureHandles, yuvSizes, origin,
    521                                       std::move(imageColorSpace));
    522 }
    523 
    524 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
    525                                                 const GrBackendTexture yuvBackendTextures[3],
    526                                                 const SkISize yuvSizes[3], GrSurfaceOrigin origin,
    527                                                 sk_sp<SkColorSpace> imageColorSpace) {
    528     return make_from_yuv_textures_copy(ctx, colorSpace, false, yuvBackendTextures, yuvSizes, origin,
    529                                        std::move(imageColorSpace));
    530 }
    531 
    532 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
    533                                                  const GrBackendTexture yuvBackendTextures[2],
    534                                                  const SkISize yuvSizes[2],
    535                                                  GrSurfaceOrigin origin,
    536                                                  sk_sp<SkColorSpace> imageColorSpace) {
    537     return make_from_yuv_textures_copy(ctx, colorSpace, true, yuvBackendTextures, yuvSizes, origin,
    538                                        std::move(imageColorSpace));
    539 }
    540 
    541 static sk_sp<SkImage> create_image_from_maker(GrContext* context, GrTextureMaker* maker,
    542                                               SkAlphaType at, uint32_t id,
    543                                               SkColorSpace* dstColorSpace) {
    544     sk_sp<SkColorSpace> texColorSpace;
    545     sk_sp<GrTextureProxy> proxy(maker->refTextureProxyForParams(
    546             GrSamplerState::ClampNearest(), dstColorSpace, &texColorSpace, nullptr));
    547     if (!proxy) {
    548         return nullptr;
    549     }
    550     return sk_make_sp<SkImage_Gpu>(context, id, at,
    551                                    std::move(proxy), std::move(texColorSpace), SkBudgeted::kNo);
    552 }
    553 
    554 sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const {
    555     if (!context) {
    556         return nullptr;
    557     }
    558     if (GrContext* incumbent = as_IB(this)->context()) {
    559         return incumbent == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr;
    560     }
    561 
    562     if (this->isLazyGenerated()) {
    563         GrImageTextureMaker maker(context, this, kDisallow_CachingHint);
    564         return create_image_from_maker(context, &maker, this->alphaType(),
    565                                        this->uniqueID(), dstColorSpace);
    566     }
    567 
    568     if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
    569         GrBitmapTextureMaker maker(context, *bmp);
    570         return create_image_from_maker(context, &maker, this->alphaType(),
    571                                        this->uniqueID(), dstColorSpace);
    572     }
    573     return nullptr;
    574 }
    575 
    576 sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> encoded,
    577                                                     bool buildMips, SkColorSpace* dstColorSpace) {
    578     sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded));
    579     if (!codecImage) {
    580         return nullptr;
    581     }
    582 
    583     // Some backends or drivers don't support (safely) moving resources between contexts
    584     if (!context || !context->caps()->crossContextTextureSupport()) {
    585         return codecImage;
    586     }
    587 
    588     // Turn the codec image into a GrTextureProxy
    589     GrImageTextureMaker maker(context, codecImage.get(), kDisallow_CachingHint);
    590     sk_sp<SkColorSpace> texColorSpace;
    591     GrSamplerState samplerState(
    592             GrSamplerState::WrapMode::kClamp,
    593             buildMips ? GrSamplerState::Filter::kMipMap : GrSamplerState::Filter::kBilerp);
    594     sk_sp<GrTextureProxy> proxy(
    595             maker.refTextureProxyForParams(samplerState, dstColorSpace, &texColorSpace, nullptr));
    596     if (!proxy) {
    597         return codecImage;
    598     }
    599 
    600     if (!proxy->instantiate(context->contextPriv().resourceProvider())) {
    601         return codecImage;
    602     }
    603     sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
    604 
    605     // Flush any writes or uploads
    606     context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
    607 
    608     GrGpu* gpu = context->contextPriv().getGpu();
    609     sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
    610 
    611     auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
    612                                                     std::move(sema), codecImage->alphaType(),
    613                                                     std::move(texColorSpace));
    614     return SkImage::MakeFromGenerator(std::move(gen));
    615 }
    616 
    617 sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrContext* context, const SkPixmap& pixmap,
    618                                                    bool buildMips, SkColorSpace* dstColorSpace) {
    619     // Some backends or drivers don't support (safely) moving resources between contexts
    620     if (!context || !context->caps()->crossContextTextureSupport()) {
    621         return SkImage::MakeRasterCopy(pixmap);
    622     }
    623 
    624     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
    625     // Turn the pixmap into a GrTextureProxy
    626     sk_sp<GrTextureProxy> proxy;
    627     if (buildMips) {
    628         SkBitmap bmp;
    629         bmp.installPixels(pixmap);
    630         proxy = GrGenerateMipMapsAndUploadToTextureProxy(proxyProvider, bmp, dstColorSpace);
    631     } else {
    632         proxy = GrUploadPixmapToTextureProxy(proxyProvider, pixmap, SkBudgeted::kYes,
    633                                              dstColorSpace);
    634     }
    635 
    636     if (!proxy) {
    637         return SkImage::MakeRasterCopy(pixmap);
    638     }
    639 
    640     sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
    641 
    642     // Flush any writes or uploads
    643     context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
    644     GrGpu* gpu = context->contextPriv().getGpu();
    645 
    646     sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
    647 
    648     auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
    649                                                     std::move(sema), pixmap.alphaType(),
    650                                                     pixmap.info().refColorSpace());
    651     return SkImage::MakeFromGenerator(std::move(gen));
    652 }
    653 
    654 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
    655 sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at,
    656                                                sk_sp<SkColorSpace> cs) {
    657     auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs);
    658     return SkImage::MakeFromGenerator(std::move(gen));
    659 }
    660 #endif
    661 
    662 ///////////////////////////////////////////////////////////////////////////////////////////////////
    663 
    664 namespace {
    665 struct MipMapLevelData {
    666     void* fPixelData;
    667     size_t fRowBytes;
    668 };
    669 
    670 struct DeferredTextureImage {
    671     uint32_t                      fContextUniqueID;
    672     // Right now, the destination color mode is only considered when generating mipmaps
    673     SkDestinationSurfaceColorMode fColorMode;
    674     // We don't store a SkImageInfo because it contains a ref-counted SkColorSpace.
    675     int                           fWidth;
    676     int                           fHeight;
    677     SkColorType                   fColorType;
    678     SkAlphaType                   fAlphaType;
    679     void*                         fColorSpace;
    680     size_t                        fColorSpaceSize;
    681     int                           fMipMapLevelCount;
    682     // The fMipMapLevelData array may contain more than 1 element.
    683     // It contains fMipMapLevelCount elements.
    684     // That means this struct's size is not known at compile-time.
    685     MipMapLevelData               fMipMapLevelData[1];
    686 };
    687 }  // anonymous namespace
    688 
    689 static bool should_use_mip_maps(const SkImage::DeferredTextureImageUsageParams & param) {
    690     // There is a bug in the mipmap pre-generation logic in use in getDeferredTextureImageData.
    691     // This can cause runaway memory leaks, so we are disabling this path until we can
    692     // investigate further. crbug.com/669775
    693     return false;
    694 }
    695 
    696 namespace {
    697 
    698 class DTIBufferFiller
    699 {
    700 public:
    701     explicit DTIBufferFiller(char* bufferAsCharPtr)
    702         : bufferAsCharPtr_(bufferAsCharPtr) {}
    703 
    704     void fillMember(const void* source, size_t memberOffset, size_t size) {
    705         memcpy(bufferAsCharPtr_ + memberOffset, source, size);
    706     }
    707 
    708 private:
    709 
    710     char* bufferAsCharPtr_;
    711 };
    712 }
    713 
    714 #define FILL_MEMBER(bufferFiller, member, source) \
    715     bufferFiller.fillMember(source, \
    716                offsetof(DeferredTextureImage, member), \
    717                sizeof(DeferredTextureImage::member));
    718 
    719 static bool SupportsColorSpace(SkColorType colorType) {
    720     switch (colorType) {
    721         case kRGBA_8888_SkColorType:
    722         case kBGRA_8888_SkColorType:
    723         case kRGBA_F16_SkColorType:
    724             return true;
    725         default:
    726             return false;
    727     }
    728 }
    729 
    730 size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& proxy,
    731                                             const DeferredTextureImageUsageParams params[],
    732                                             int paramCnt, void* buffer,
    733                                             SkColorSpace* dstColorSpace,
    734                                             SkColorType dstColorType) const {
    735     // Some quick-rejects where is makes no sense to return CPU data
    736     //  e.g.
    737     //      - texture backed
    738     //      - picture backed
    739     //
    740     if (this->isTextureBacked()) {
    741         return 0;
    742     }
    743     if (as_IB(this)->onCanLazyGenerateOnGPU()) {
    744         return 0;
    745     }
    746 
    747     bool supportsColorSpace = SupportsColorSpace(dstColorType);
    748     // Quick reject if the caller requests a color space with an unsupported color type.
    749     if (SkToBool(dstColorSpace) && !supportsColorSpace) {
    750         return 0;
    751     }
    752 
    753     // Extract relevant min/max values from the params array.
    754     int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel;
    755     SkFilterQuality highestFilterQuality = params[0].fQuality;
    756     bool useMipMaps = should_use_mip_maps(params[0]);
    757     for (int i = 1; i < paramCnt; ++i) {
    758         if (lowestPreScaleMipLevel > params[i].fPreScaleMipLevel)
    759             lowestPreScaleMipLevel = params[i].fPreScaleMipLevel;
    760         if (highestFilterQuality < params[i].fQuality)
    761             highestFilterQuality = params[i].fQuality;
    762         useMipMaps |= should_use_mip_maps(params[i]);
    763     }
    764 
    765     const bool fillMode = SkToBool(buffer);
    766     if (fillMode && !SkIsAlign8(reinterpret_cast<intptr_t>(buffer))) {
    767         return 0;
    768     }
    769 
    770     // Calculate scaling parameters.
    771     bool isScaled = lowestPreScaleMipLevel != 0;
    772 
    773     SkISize scaledSize;
    774     if (isScaled) {
    775         // SkMipMap::ComputeLevelSize takes an index into an SkMipMap. SkMipMaps don't contain the
    776         // base level, so to get an SkMipMap index we must subtract one from the GL MipMap level.
    777         scaledSize = SkMipMap::ComputeLevelSize(this->width(), this->height(),
    778                                                 lowestPreScaleMipLevel - 1);
    779     } else {
    780         scaledSize = SkISize::Make(this->width(), this->height());
    781     }
    782 
    783     // We never want to scale at higher than SW medium quality, as SW medium matches GPU high.
    784     SkFilterQuality scaleFilterQuality = highestFilterQuality;
    785     if (scaleFilterQuality > kMedium_SkFilterQuality) {
    786         scaleFilterQuality = kMedium_SkFilterQuality;
    787     }
    788 
    789     const int maxTextureSize = proxy.fCaps->maxTextureSize();
    790     if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) {
    791         return 0;
    792     }
    793 
    794     SkAutoPixmapStorage pixmap;
    795     SkImageInfo info;
    796     size_t pixelSize = 0;
    797     if (!isScaled && this->peekPixels(&pixmap) && pixmap.info().colorType() == dstColorType) {
    798         info = pixmap.info();
    799         pixelSize = SkAlign8(pixmap.computeByteSize());
    800         if (!dstColorSpace) {
    801             pixmap.setColorSpace(nullptr);
    802             info = info.makeColorSpace(nullptr);
    803         }
    804     } else {
    805         if (!this->isLazyGenerated() && !this->peekPixels(nullptr)) {
    806             return 0;
    807         }
    808         if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
    809             // Generator backed image. Tweak info to trigger correct kind of decode.
    810             SkImageCacherator::CachedFormat cacheFormat = cacher->chooseCacheFormat(
    811                 dstColorSpace, proxy.fCaps.get());
    812             info = cacher->buildCacheInfo(cacheFormat).makeWH(scaledSize.width(),
    813                                                               scaledSize.height());
    814         } else {
    815             info = as_IB(this)->onImageInfo().makeWH(scaledSize.width(), scaledSize.height());
    816             if (!dstColorSpace) {
    817                 info = info.makeColorSpace(nullptr);
    818             }
    819         }
    820         // Force color type to be the requested type.
    821         info = info.makeColorType(dstColorType);
    822         pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr));
    823         if (fillMode) {
    824             // Always decode to N32 and convert to the requested type if necessary.
    825             SkImageInfo decodeInfo = info.makeColorType(kN32_SkColorType);
    826             SkAutoPixmapStorage decodePixmap;
    827             decodePixmap.alloc(decodeInfo);
    828 
    829             if (isScaled) {
    830                 if (!this->scalePixels(decodePixmap, scaleFilterQuality,
    831                                        SkImage::kDisallow_CachingHint)) {
    832                     return 0;
    833                 }
    834             } else {
    835                 if (!this->readPixels(decodePixmap, 0, 0, SkImage::kDisallow_CachingHint)) {
    836                     return 0;
    837                 }
    838             }
    839 
    840             if (decodeInfo.colorType() != info.colorType()) {
    841                 pixmap.alloc(info);
    842                 // Convert and copy the decoded pixmap to the target pixmap.
    843                 decodePixmap.readPixels(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes(), 0,
    844                                         0);
    845             } else {
    846                 pixmap = std::move(decodePixmap);
    847             }
    848         }
    849     }
    850     int mipMapLevelCount = 1;
    851     if (useMipMaps) {
    852         // SkMipMap only deals with the mipmap levels it generates, which does
    853         // not include the base level.
    854         // That means it generates and holds levels 1-x instead of 0-x.
    855         // So the total mipmap level count is 1 more than what
    856         // SkMipMap::ComputeLevelCount returns.
    857         mipMapLevelCount = SkMipMap::ComputeLevelCount(scaledSize.width(), scaledSize.height()) + 1;
    858 
    859         // We already initialized pixelSize to the size of the base level.
    860         // SkMipMap will generate the extra mipmap levels. Their sizes need to
    861         // be added to the total.
    862         // Index 0 here does not refer to the base mipmap level -- it is
    863         // SkMipMap's first generated mipmap level (level 1).
    864         for (int currentMipMapLevelIndex = mipMapLevelCount - 2; currentMipMapLevelIndex >= 0;
    865              currentMipMapLevelIndex--) {
    866             SkISize mipSize = SkMipMap::ComputeLevelSize(scaledSize.width(), scaledSize.height(),
    867                                                          currentMipMapLevelIndex);
    868             SkImageInfo mipInfo = info.makeWH(mipSize.fWidth, mipSize.fHeight);
    869             pixelSize += SkAlign8(SkAutoPixmapStorage::AllocSize(mipInfo, nullptr));
    870         }
    871     }
    872     size_t size = 0;
    873     size_t dtiSize = SkAlign8(sizeof(DeferredTextureImage));
    874     size += dtiSize;
    875     size += (mipMapLevelCount - 1) * sizeof(MipMapLevelData);
    876     // We subtract 1 because DeferredTextureImage already includes the base
    877     // level in its size
    878     size_t pixelOffset = size;
    879     size += pixelSize;
    880     size_t colorSpaceOffset = 0;
    881     size_t colorSpaceSize = 0;
    882     SkColorSpaceTransferFn fn;
    883     if (info.colorSpace()) {
    884         SkASSERT(dstColorSpace);
    885         SkASSERT(supportsColorSpace);
    886         colorSpaceOffset = size;
    887         colorSpaceSize = info.colorSpace()->writeToMemory(nullptr);
    888         size += colorSpaceSize;
    889     } else if (supportsColorSpace && this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn)) {
    890         // In legacy mode, preserve the color space tag on the SkImage.  This is only
    891         // supported if the color space has a parametric transfer function.
    892         SkASSERT(!dstColorSpace);
    893         colorSpaceOffset = size;
    894         colorSpaceSize = this->colorSpace()->writeToMemory(nullptr);
    895         size += colorSpaceSize;
    896     }
    897     if (!fillMode) {
    898         return size;
    899     }
    900     char* bufferAsCharPtr = reinterpret_cast<char*>(buffer);
    901     char* pixelsAsCharPtr = bufferAsCharPtr + pixelOffset;
    902     void* pixels = pixelsAsCharPtr;
    903 
    904     memcpy(reinterpret_cast<void*>(SkAlign8(reinterpret_cast<uintptr_t>(pixelsAsCharPtr))),
    905                                    pixmap.addr(), pixmap.computeByteSize());
    906 
    907     // If the context has sRGB support, and we're intending to render to a surface with an attached
    908     // color space, and the image has an sRGB-like color space attached, then use our gamma (sRGB)
    909     // aware mip-mapping.
    910     SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy;
    911     if (proxy.fCaps->srgbSupport() && SkToBool(dstColorSpace) &&
    912         info.colorSpace() && info.colorSpace()->gammaCloseToSRGB()) {
    913         SkASSERT(supportsColorSpace);
    914         colorMode = SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware;
    915     }
    916 
    917     SkASSERT(info == pixmap.info());
    918     size_t rowBytes = pixmap.rowBytes();
    919     static_assert(std::is_standard_layout<DeferredTextureImage>::value,
    920                   "offsetof, which we use below, requires the type have standard layout");
    921     auto dtiBufferFiller = DTIBufferFiller{bufferAsCharPtr};
    922     FILL_MEMBER(dtiBufferFiller, fColorMode, &colorMode);
    923     FILL_MEMBER(dtiBufferFiller, fContextUniqueID, &proxy.fContextUniqueID);
    924     int width = info.width();
    925     FILL_MEMBER(dtiBufferFiller, fWidth, &width);
    926     int height = info.height();
    927     FILL_MEMBER(dtiBufferFiller, fHeight, &height);
    928     SkColorType colorType = info.colorType();
    929     FILL_MEMBER(dtiBufferFiller, fColorType, &colorType);
    930     SkAlphaType alphaType = info.alphaType();
    931     FILL_MEMBER(dtiBufferFiller, fAlphaType, &alphaType);
    932     FILL_MEMBER(dtiBufferFiller, fMipMapLevelCount, &mipMapLevelCount);
    933     memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fPixelData),
    934            &pixels, sizeof(pixels));
    935     memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fRowBytes),
    936            &rowBytes, sizeof(rowBytes));
    937     if (colorSpaceSize) {
    938         void* colorSpace = bufferAsCharPtr + colorSpaceOffset;
    939         FILL_MEMBER(dtiBufferFiller, fColorSpace, &colorSpace);
    940         FILL_MEMBER(dtiBufferFiller, fColorSpaceSize, &colorSpaceSize);
    941         if (info.colorSpace()) {
    942             info.colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset);
    943         } else {
    944             SkASSERT(this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn));
    945             SkASSERT(!dstColorSpace);
    946             this->colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset);
    947         }
    948     } else {
    949         memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpace),
    950                0, sizeof(DeferredTextureImage::fColorSpace));
    951         memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpaceSize),
    952                0, sizeof(DeferredTextureImage::fColorSpaceSize));
    953     }
    954 
    955     // Fill in the mipmap levels if they exist
    956     char* mipLevelPtr = pixelsAsCharPtr + SkAlign8(pixmap.computeByteSize());
    957 
    958     if (useMipMaps) {
    959         static_assert(std::is_standard_layout<MipMapLevelData>::value,
    960                       "offsetof, which we use below, requires the type have a standard layout");
    961 
    962         std::unique_ptr<SkMipMap> mipmaps(SkMipMap::Build(pixmap, colorMode, nullptr));
    963         // SkMipMap holds only the mipmap levels it generates.
    964         // A programmer can use the data they provided to SkMipMap::Build as level 0.
    965         // So the SkMipMap provides levels 1-x but it stores them in its own
    966         // range 0-(x-1).
    967         for (int generatedMipLevelIndex = 0; generatedMipLevelIndex < mipMapLevelCount - 1;
    968              generatedMipLevelIndex++) {
    969             SkMipMap::Level mipLevel;
    970             mipmaps->getLevel(generatedMipLevelIndex, &mipLevel);
    971 
    972             // Make sure the mipmap data is after the start of the buffer
    973             SkASSERT(mipLevelPtr > bufferAsCharPtr);
    974             // Make sure the mipmap data starts before the end of the buffer
    975             SkASSERT(mipLevelPtr < bufferAsCharPtr + pixelOffset + pixelSize);
    976             // Make sure the mipmap data ends before the end of the buffer
    977             SkASSERT(mipLevelPtr + mipLevel.fPixmap.computeByteSize() <=
    978                      bufferAsCharPtr + pixelOffset + pixelSize);
    979 
    980             memcpy(mipLevelPtr, mipLevel.fPixmap.addr(), mipLevel.fPixmap.computeByteSize());
    981 
    982             memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) +
    983                    sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) +
    984                    offsetof(MipMapLevelData, fPixelData), &mipLevelPtr, sizeof(void*));
    985             size_t rowBytes = mipLevel.fPixmap.rowBytes();
    986             memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) +
    987                    sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) +
    988                    offsetof(MipMapLevelData, fRowBytes), &rowBytes, sizeof(rowBytes));
    989 
    990             mipLevelPtr += SkAlign8(mipLevel.fPixmap.computeByteSize());
    991         }
    992     }
    993     return size;
    994 }
    995 
    996 sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void* data,
    997                                                          SkBudgeted budgeted) {
    998     if (!data) {
    999         return nullptr;
   1000     }
   1001     const DeferredTextureImage* dti = reinterpret_cast<const DeferredTextureImage*>(data);
   1002 
   1003     if (!context || context->uniqueID() != dti->fContextUniqueID || context->abandoned()) {
   1004         return nullptr;
   1005     }
   1006     int mipLevelCount = dti->fMipMapLevelCount;
   1007     SkASSERT(mipLevelCount >= 1);
   1008     sk_sp<SkColorSpace> colorSpace;
   1009     if (dti->fColorSpaceSize) {
   1010         colorSpace = SkColorSpace::Deserialize(dti->fColorSpace, dti->fColorSpaceSize);
   1011     }
   1012     SkImageInfo info = SkImageInfo::Make(dti->fWidth, dti->fHeight,
   1013                                          dti->fColorType, dti->fAlphaType, colorSpace);
   1014     if (mipLevelCount == 1) {
   1015         SkPixmap pixmap;
   1016         pixmap.reset(info, dti->fMipMapLevelData[0].fPixelData, dti->fMipMapLevelData[0].fRowBytes);
   1017 
   1018         // Pass nullptr for the |dstColorSpace|.  This opts in to more lenient color space
   1019         // verification.  This is ok because we've already verified the color space in
   1020         // getDeferredTextureImageData().
   1021         sk_sp<GrTextureProxy> proxy(GrUploadPixmapToTextureProxy(
   1022                 context->contextPriv().proxyProvider(), pixmap, budgeted, nullptr));
   1023         if (!proxy) {
   1024             return nullptr;
   1025         }
   1026         return sk_make_sp<SkImage_Gpu>(context, kNeedNewImageUniqueID, pixmap.alphaType(),
   1027                                        std::move(proxy), std::move(colorSpace), budgeted);
   1028     } else {
   1029         std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
   1030         for (int i = 0; i < mipLevelCount; i++) {
   1031             texels[i].fPixels = dti->fMipMapLevelData[i].fPixelData;
   1032             texels[i].fRowBytes = dti->fMipMapLevelData[i].fRowBytes;
   1033         }
   1034 
   1035         return SkImage::MakeTextureFromMipMap(context, info, texels.get(),
   1036                                               mipLevelCount, SkBudgeted::kYes,
   1037                                               dti->fColorMode);
   1038     }
   1039 }
   1040 
   1041 ///////////////////////////////////////////////////////////////////////////////////////////////////
   1042 
   1043 bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx,
   1044                                             sk_sp<SkImage> image,
   1045                                             GrBackendTexture* backendTexture,
   1046                                             BackendTextureReleaseProc* releaseProc) {
   1047     if (!image || !ctx || !backendTexture || !releaseProc) {
   1048         return false;
   1049     }
   1050 
   1051     // Ensure we have a texture backed image.
   1052     if (!image->isTextureBacked()) {
   1053         image = image->makeTextureImage(ctx, nullptr);
   1054         if (!image) {
   1055             return false;
   1056         }
   1057     }
   1058     GrTexture* texture = image->getTexture();
   1059     if (!texture) {
   1060         // In context-loss cases, we may not have a texture.
   1061         return false;
   1062     }
   1063 
   1064     // If the image's context doesn't match the provided context, fail.
   1065     if (texture->getContext() != ctx) {
   1066         return false;
   1067     }
   1068 
   1069     // Flush any pending IO on the texture.
   1070     ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
   1071     SkASSERT(!texture->surfacePriv().hasPendingIO());
   1072 
   1073     // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
   1074     // image is not unique, or if the texture wraps an external object.
   1075     if (!image->unique() || !texture->surfacePriv().hasUniqueRef() ||
   1076         texture->resourcePriv().refsWrappedObjects()) {
   1077         // onMakeSubset will always copy the image.
   1078         image = as_IB(image)->onMakeSubset(image->bounds());
   1079         if (!image) {
   1080             return false;
   1081         }
   1082 
   1083         texture = image->getTexture();
   1084         if (!texture) {
   1085             return false;
   1086         }
   1087 
   1088         // Flush to ensure that the copy is completed before we return the texture.
   1089         ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
   1090         SkASSERT(!texture->surfacePriv().hasPendingIO());
   1091     }
   1092 
   1093     SkASSERT(!texture->resourcePriv().refsWrappedObjects());
   1094     SkASSERT(texture->surfacePriv().hasUniqueRef());
   1095     SkASSERT(image->unique());
   1096 
   1097     // Take a reference to the GrTexture and release the image.
   1098     sk_sp<GrTexture> textureRef(SkSafeRef(texture));
   1099     image = nullptr;
   1100 
   1101     // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
   1102     return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
   1103 }
   1104 
   1105 ///////////////////////////////////////////////////////////////////////////////////////////////////
   1106 
   1107 sk_sp<SkImage> SkImage::MakeTextureFromMipMap(GrContext* ctx, const SkImageInfo& info,
   1108                                               const GrMipLevel texels[], int mipLevelCount,
   1109                                               SkBudgeted budgeted,
   1110                                               SkDestinationSurfaceColorMode colorMode) {
   1111     SkASSERT(mipLevelCount >= 1);
   1112     if (!ctx) {
   1113         return nullptr;
   1114     }
   1115     GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
   1116 
   1117     // For images where the client is passing the mip data we require that all the mip levels have
   1118     // valid data.
   1119     for (int i = 0; i < mipLevelCount; ++i) {
   1120         if (!texels[i].fPixels) {
   1121             return nullptr;
   1122         }
   1123     }
   1124     sk_sp<GrTextureProxy> proxy(GrUploadMipMapToTextureProxy(proxyProvider, info,
   1125                                                              texels, mipLevelCount, colorMode));
   1126     if (!proxy) {
   1127         return nullptr;
   1128     }
   1129 
   1130     SkASSERT(proxy->priv().isExact());
   1131     return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
   1132                                    info.alphaType(), std::move(proxy),
   1133                                    info.refColorSpace(), budgeted);
   1134 }
   1135 
   1136 sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> target, SkColorType,
   1137                                              SkTransferFunctionBehavior premulBehavior) const {
   1138     if (SkTransferFunctionBehavior::kRespect == premulBehavior) {
   1139         // TODO: Implement this.
   1140         return nullptr;
   1141     }
   1142 
   1143     sk_sp<SkColorSpace> srcSpace = fColorSpace;
   1144     if (!fColorSpace) {
   1145         if (target->isSRGB()) {
   1146             return sk_ref_sp(const_cast<SkImage*>((SkImage*)this));
   1147         }
   1148 
   1149         srcSpace = SkColorSpace::MakeSRGB();
   1150     }
   1151 
   1152     auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), target.get());
   1153     if (!xform) {
   1154         return sk_ref_sp(const_cast<SkImage_Gpu*>(this));
   1155     }
   1156 
   1157     sk_sp<GrRenderTargetContext> renderTargetContext(fContext->makeDeferredRenderTargetContext(
   1158         SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig, nullptr));
   1159     if (!renderTargetContext) {
   1160         return nullptr;
   1161     }
   1162 
   1163     GrPaint paint;
   1164     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
   1165     paint.addColorTextureProcessor(fProxy, SkMatrix::I());
   1166     paint.addColorFragmentProcessor(std::move(xform));
   1167 
   1168     const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
   1169 
   1170     renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
   1171 
   1172     if (!renderTargetContext->asTextureProxy()) {
   1173         return nullptr;
   1174     }
   1175 
   1176     // MDB: this call is okay bc we know 'renderTargetContext' was exact
   1177     return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
   1178                                    fAlphaType, renderTargetContext->asTextureProxyRef(),
   1179                                    std::move(target), fBudgeted);
   1180 
   1181 }
   1182 
   1183 bool SkImage_Gpu::onIsValid(GrContext* context) const {
   1184     // The base class has already checked that context isn't abandoned (if it's not nullptr)
   1185     if (fContext->abandoned()) {
   1186         return false;
   1187     }
   1188 
   1189     if (context && context != fContext) {
   1190         return false;
   1191     }
   1192 
   1193     return true;
   1194 }
   1195