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 #include "SkTraceEvent.h"
     43 
     44 SkImage_Gpu::SkImage_Gpu(GrContext* context, uint32_t uniqueID, SkAlphaType at,
     45                          sk_sp<GrTextureProxy> proxy,
     46                          sk_sp<SkColorSpace> colorSpace, SkBudgeted budgeted)
     47     : INHERITED(proxy->worstCaseWidth(), proxy->worstCaseHeight(), uniqueID)
     48     , fContext(context)
     49     , fProxy(std::move(proxy))
     50     , fAlphaType(at)
     51     , fBudgeted(budgeted)
     52     , fColorSpace(std::move(colorSpace))
     53     , fAddedRasterVersionToCache(false) {
     54 }
     55 
     56 SkImage_Gpu::~SkImage_Gpu() {
     57     if (fAddedRasterVersionToCache.load()) {
     58         SkNotifyBitmapGenIDIsStale(this->uniqueID());
     59     }
     60 }
     61 
     62 SkImageInfo SkImage_Gpu::onImageInfo() const {
     63     SkColorType ct;
     64     if (!GrPixelConfigToColorType(fProxy->config(), &ct)) {
     65         ct = kUnknown_SkColorType;
     66     }
     67     return SkImageInfo::Make(fProxy->width(), fProxy->height(), ct, fAlphaType, fColorSpace);
     68 }
     69 
     70 bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkColorSpace*, CachingHint chint) const {
     71     // The SkColorSpace parameter "dstColorSpace" is really just a hint about how/where the bitmap
     72     // will be used. The client doesn't expect that we convert to that color space, it's intended
     73     // for codec-backed images, to drive our decoding heuristic. In theory we *could* read directly
     74     // into that color space (to save the client some effort in whatever they're about to do), but
     75     // that would make our use of the bitmap cache incorrect (or much less efficient, assuming we
     76     // rolled the dstColorSpace into the key).
     77     const auto desc = SkBitmapCacheDesc::Make(this);
     78     if (SkBitmapCache::Find(desc, dst)) {
     79         SkASSERT(dst->getGenerationID() == this->uniqueID());
     80         SkASSERT(dst->isImmutable());
     81         SkASSERT(dst->getPixels());
     82         return true;
     83     }
     84 
     85     SkBitmapCache::RecPtr rec = nullptr;
     86     SkPixmap pmap;
     87     if (kAllow_CachingHint == chint) {
     88         rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap);
     89         if (!rec) {
     90             return false;
     91         }
     92     } else {
     93         if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) {
     94             return false;
     95         }
     96     }
     97 
     98     sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
     99                                                                                     fProxy,
    100                                                                                     fColorSpace);
    101     if (!sContext) {
    102         return false;
    103     }
    104 
    105     if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
    106         return false;
    107     }
    108 
    109     if (rec) {
    110         SkBitmapCache::Add(std::move(rec), dst);
    111         fAddedRasterVersionToCache.store(true);
    112     }
    113     return true;
    114 }
    115 
    116 sk_sp<GrTextureProxy> SkImage_Gpu::asTextureProxyRef(GrContext* context,
    117                                                      const GrSamplerState& params,
    118                                                      SkColorSpace* dstColorSpace,
    119                                                      sk_sp<SkColorSpace>* texColorSpace,
    120                                                      SkScalar scaleAdjust[2]) const {
    121     if (context != fContext) {
    122         SkASSERT(0);
    123         return nullptr;
    124     }
    125 
    126     GrTextureAdjuster adjuster(fContext, fProxy, this->alphaType(), this->uniqueID(),
    127                                this->fColorSpace.get());
    128     return adjuster.refTextureProxyForParams(params, dstColorSpace, texColorSpace, scaleAdjust);
    129 }
    130 
    131 static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
    132     switch (info.colorType()) {
    133         case kRGBA_8888_SkColorType:
    134         case kBGRA_8888_SkColorType:
    135             break;
    136         default:
    137             return; // nothing to do
    138     }
    139 
    140     // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian,
    141     // and in either case, the alpha-byte is always in the same place, so we can safely call
    142     // SkPreMultiplyColor()
    143     //
    144     SkColor* row = (SkColor*)pixels;
    145     for (int y = 0; y < info.height(); ++y) {
    146         for (int x = 0; x < info.width(); ++x) {
    147             row[x] = SkPreMultiplyColor(row[x]);
    148         }
    149         row = (SkColor*)((char*)(row) + rowBytes);
    150     }
    151 }
    152 
    153 GrBackendObject SkImage_Gpu::onGetTextureHandle(bool flushPendingGrContextIO,
    154                                                 GrSurfaceOrigin* origin) const {
    155     SkASSERT(fProxy);
    156 
    157     if (!fContext->contextPriv().resourceProvider() && !fProxy->priv().isInstantiated()) {
    158         // This image was created with a DDL context and cannot be instantiated. Thus we return 0
    159         // here which is considered invalid for all backends.
    160         return 0;
    161     }
    162 
    163     if (GrSurfaceProxy::LazyState::kNot != fProxy->lazyInstantiationState()) {
    164         SkASSERT(fContext->contextPriv().resourceProvider());
    165         fProxy->priv().doLazyInstantiation(fContext->contextPriv().resourceProvider());
    166         if (!fProxy->priv().isInstantiated()) {
    167             // We failed to instantiate the lazy proxy. Thus we return 0 here which is considered
    168             // invalid for all backends.
    169             return 0;
    170         }
    171     }
    172 
    173     if (!fProxy->instantiate(fContext->contextPriv().resourceProvider())) {
    174         return 0;
    175     }
    176 
    177     GrTexture* texture = fProxy->priv().peekTexture();
    178 
    179     if (texture) {
    180         if (flushPendingGrContextIO) {
    181             fContext->contextPriv().prepareSurfaceForExternalIO(fProxy.get());
    182         }
    183         if (origin) {
    184             *origin = fProxy->origin();
    185         }
    186         return texture->getTextureHandle();
    187     }
    188     return 0;
    189 }
    190 
    191 GrTexture* SkImage_Gpu::onGetTexture() const {
    192     GrTextureProxy* proxy = this->peekProxy();
    193     if (!proxy) {
    194         return nullptr;
    195     }
    196 
    197     if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) {
    198         return nullptr;
    199     }
    200 
    201     return proxy->priv().peekTexture();
    202 }
    203 
    204 bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
    205                                int srcX, int srcY, CachingHint) const {
    206     if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) {
    207         return false;
    208     }
    209 
    210     SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, srcX, srcY);
    211     if (!rec.trim(this->width(), this->height())) {
    212         return false;
    213     }
    214 
    215     // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and
    216     // GrRenderTargetContext::onReadPixels
    217     uint32_t flags = 0;
    218     if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) {
    219         // let the GPU perform this transformation for us
    220         flags = GrContextPriv::kUnpremul_PixelOpsFlag;
    221     }
    222 
    223     // This hack allows us to call makeNonTextureImage on images with arbitrary color spaces.
    224     // Otherwise, we'll be unable to create a render target context.
    225     // TODO: This shouldn't be necessary - we need more robust support for images (and surfaces)
    226     // with arbitrary color spaces. Unfortunately, this is one spot where we go from image to
    227     // surface (rather than the opposite), and our lenient image rules break our (currently) more
    228     // strict surface rules.
    229     // GrSurfaceContext::readPixels does not make use of the context's color space. However, we
    230     // don't allow creating a surface context for a sRGB GrPixelConfig unless the color space has
    231     // sRGB gamma. So we choose null for non-SRGB GrPixelConfigs and sRGB for sRGB GrPixelConfigs.
    232     sk_sp<SkColorSpace> surfaceColorSpace = fColorSpace;
    233     if (!flags) {
    234         if (!dstInfo.colorSpace() ||
    235             SkColorSpace::Equals(fColorSpace.get(), dstInfo.colorSpace())) {
    236             if (GrPixelConfigIsSRGB(fProxy->config())) {
    237                 surfaceColorSpace = SkColorSpace::MakeSRGB();
    238             } else {
    239                 surfaceColorSpace = nullptr;
    240             }
    241         }
    242     }
    243 
    244     sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
    245             fProxy, surfaceColorSpace);
    246     if (!sContext) {
    247         return false;
    248     }
    249 
    250     if (!sContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, flags)) {
    251         return false;
    252     }
    253 
    254     // do we have to manually fix-up the alpha channel?
    255     //      src         dst
    256     //      unpremul    premul      fix manually
    257     //      premul      unpremul    done by kUnpremul_PixelOpsFlag
    258     // all other combos need to change.
    259     //
    260     // Should this be handled by Ganesh? todo:?
    261     //
    262     if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
    263         apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes);
    264     }
    265     return true;
    266 }
    267 
    268 sk_sp<SkImage> SkImage_Gpu::onMakeSubset(const SkIRect& subset) const {
    269     GrSurfaceDesc desc;
    270     desc.fOrigin = fProxy->origin();
    271     desc.fWidth = subset.width();
    272     desc.fHeight = subset.height();
    273     desc.fConfig = fProxy->config();
    274 
    275     sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext(
    276                                                                         desc,
    277                                                                         GrMipMapped::kNo,
    278                                                                         SkBackingFit::kExact,
    279                                                                         fBudgeted));
    280     if (!sContext) {
    281         return nullptr;
    282     }
    283 
    284     if (!sContext->copy(fProxy.get(), subset, SkIPoint::Make(0, 0))) {
    285         return nullptr;
    286     }
    287 
    288     // MDB: this call is okay bc we know 'sContext' was kExact
    289     return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
    290                                    fAlphaType, sContext->asTextureProxyRef(),
    291                                    fColorSpace, fBudgeted);
    292 }
    293 
    294 ///////////////////////////////////////////////////////////////////////////////////////////////////
    295 
    296 static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx,
    297                                                  const GrBackendTexture& backendTex,
    298                                                  GrSurfaceOrigin origin,
    299                                                  SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
    300                                                  GrWrapOwnership ownership,
    301                                                  SkImage::TextureReleaseProc releaseProc,
    302                                                  SkImage::ReleaseContext releaseCtx) {
    303     if (backendTex.width() <= 0 || backendTex.height() <= 0) {
    304         return nullptr;
    305     }
    306 
    307     GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
    308     sk_sp<GrTextureProxy> proxy = proxyProvider->createWrappedTextureProxy(
    309                                         backendTex, origin, ownership, releaseProc, releaseCtx);
    310     if (!proxy) {
    311         return nullptr;
    312     }
    313 
    314     return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
    315                                    at, std::move(proxy), std::move(colorSpace), SkBudgeted::kNo);
    316 }
    317 
    318 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
    319                                         const GrBackendTexture& tex, GrSurfaceOrigin origin,
    320                                         SkAlphaType at, sk_sp<SkColorSpace> cs,
    321                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
    322     if (!ctx) {
    323         return nullptr;
    324     }
    325     return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kBorrow_GrWrapOwnership,
    326                                       releaseP, releaseC);
    327 }
    328 
    329 bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex, GrPixelConfig* config,
    330                               SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs) {
    331     // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
    332     // create a fake image info here.
    333     SkImageInfo info = SkImageInfo::Make(1, 1, ct, at, cs);
    334     if (!SkImageInfoIsValidAllowNumericalCS(info)) {
    335         return false;
    336     }
    337 
    338     return ctx->caps()->validateBackendTexture(tex, ct, config);
    339 }
    340 
    341 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
    342                                         const GrBackendTexture& tex, GrSurfaceOrigin origin,
    343                                         SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
    344                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
    345     if (!ctx) {
    346         return nullptr;
    347     }
    348     GrBackendTexture texCopy = tex;
    349     if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
    350         return nullptr;
    351     }
    352     return MakeFromTexture(ctx, texCopy, origin, at, cs, releaseP, releaseC);
    353 }
    354 
    355 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
    356                                                const GrBackendTexture& tex, GrSurfaceOrigin origin,
    357                                                SkAlphaType at, sk_sp<SkColorSpace> cs) {
    358     if (!ctx->contextPriv().resourceProvider()) {
    359         // We have a DDL context and we don't support adopted textures for them.
    360         return nullptr;
    361     }
    362     return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kAdopt_GrWrapOwnership,
    363                                       nullptr, nullptr);
    364 }
    365 
    366 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
    367                                                const GrBackendTexture& tex, GrSurfaceOrigin origin,
    368                                                SkColorType ct, SkAlphaType at,
    369                                                sk_sp<SkColorSpace> cs) {
    370     GrBackendTexture texCopy = tex;
    371     if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
    372         return nullptr;
    373     }
    374     return MakeFromAdoptedTexture(ctx, texCopy, origin, at, cs);
    375 }
    376 
    377 static GrBackendTexture make_backend_texture_from_handle(GrBackend backend,
    378                                                          int width, int height,
    379                                                          GrPixelConfig config,
    380                                                          GrBackendObject handle) {
    381     switch (backend) {
    382         case kOpenGL_GrBackend: {
    383             const GrGLTextureInfo* glInfo = (const GrGLTextureInfo*)(handle);
    384             return GrBackendTexture(width, height, config, *glInfo);
    385         }
    386 #ifdef SK_VULKAN
    387         case kVulkan_GrBackend: {
    388             const GrVkImageInfo* vkInfo = (const GrVkImageInfo*)(handle);
    389             return GrBackendTexture(width, height, *vkInfo);
    390         }
    391 #endif
    392         case kMock_GrBackend: {
    393             const GrMockTextureInfo* mockInfo = (const GrMockTextureInfo*)(handle);
    394             return GrBackendTexture(width, height, config, *mockInfo);
    395         }
    396         default:
    397             return GrBackendTexture();
    398     }
    399 }
    400 
    401 static bool are_yuv_sizes_valid(const SkISize yuvSizes[], bool nv12) {
    402     if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 ||
    403         yuvSizes[1].fWidth <= 0 || yuvSizes[1].fHeight <= 0) {
    404         return false;
    405     }
    406     if (!nv12 && (yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0)) {
    407         return false;
    408     }
    409 
    410     return true;
    411 }
    412 
    413 static sk_sp<SkImage> make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpace colorSpace,
    414                                                   bool nv12,
    415                                                   const GrBackendTexture yuvBackendTextures[],
    416                                                   const SkISize yuvSizes[],
    417                                                   GrSurfaceOrigin origin,
    418                                                   sk_sp<SkColorSpace> imageColorSpace) {
    419     GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
    420 
    421     if (!are_yuv_sizes_valid(yuvSizes, nv12)) {
    422         return nullptr;
    423     }
    424 
    425     sk_sp<GrTextureProxy> yProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[0],
    426                                                                             origin);
    427     sk_sp<GrTextureProxy> uProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[1],
    428                                                                             origin);
    429     sk_sp<GrTextureProxy> vProxy;
    430 
    431     if (nv12) {
    432         vProxy = uProxy;
    433     } else {
    434         vProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[2], origin);
    435     }
    436     if (!yProxy || !uProxy || !vProxy) {
    437         return nullptr;
    438     }
    439 
    440     const int width = yuvSizes[0].fWidth;
    441     const int height = yuvSizes[0].fHeight;
    442 
    443     // Needs to be a render target in order to draw to it for the yuv->rgb conversion.
    444     sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeDeferredRenderTargetContext(
    445             SkBackingFit::kExact, width, height, kRGBA_8888_GrPixelConfig,
    446             std::move(imageColorSpace), 1, GrMipMapped::kNo, origin));
    447     if (!renderTargetContext) {
    448         return nullptr;
    449     }
    450 
    451     GrPaint paint;
    452     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
    453     paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Make(yProxy, uProxy, vProxy,
    454                                                            yuvSizes, colorSpace, nv12));
    455 
    456     const SkRect rect = SkRect::MakeIWH(width, height);
    457 
    458     renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
    459 
    460     if (!renderTargetContext->asSurfaceProxy()) {
    461         return nullptr;
    462     }
    463     ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());
    464 
    465     // MDB: this call is okay bc we know 'renderTargetContext' was exact
    466     return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID, kOpaque_SkAlphaType,
    467                                    renderTargetContext->asTextureProxyRef(),
    468                                    renderTargetContext->colorSpaceInfo().refColorSpace(),
    469                                    SkBudgeted::kYes);
    470 }
    471 
    472 static sk_sp<SkImage> make_from_yuv_objects_copy(GrContext* ctx, SkYUVColorSpace colorSpace,
    473                                                  bool nv12,
    474                                                  const GrBackendObject yuvTextureHandles[],
    475                                                  const SkISize yuvSizes[],
    476                                                  GrSurfaceOrigin origin,
    477                                                  sk_sp<SkColorSpace> imageColorSpace) {
    478     if (!are_yuv_sizes_valid(yuvSizes, nv12)) {
    479         return nullptr;
    480     }
    481 
    482     GrBackendTexture backendTextures[3];
    483 
    484     const GrPixelConfig kConfig = nv12 ? kRGBA_8888_GrPixelConfig : kAlpha_8_GrPixelConfig;
    485 
    486     GrBackend backend = ctx->contextPriv().getBackend();
    487     backendTextures[0] = make_backend_texture_from_handle(backend,
    488                                                           yuvSizes[0].fWidth,
    489                                                           yuvSizes[0].fHeight,
    490                                                           kConfig,
    491                                                           yuvTextureHandles[0]);
    492     backendTextures[1] = make_backend_texture_from_handle(backend,
    493                                                           yuvSizes[1].fWidth,
    494                                                           yuvSizes[1].fHeight,
    495                                                           kConfig,
    496                                                           yuvTextureHandles[1]);
    497 
    498     if (!nv12) {
    499         backendTextures[2] = make_backend_texture_from_handle(backend,
    500                                                               yuvSizes[2].fWidth,
    501                                                               yuvSizes[2].fHeight,
    502                                                               kConfig,
    503                                                               yuvTextureHandles[2]);
    504     }
    505 
    506     return make_from_yuv_textures_copy(ctx, colorSpace, nv12,
    507                                        backendTextures, yuvSizes, origin,
    508                                        std::move(imageColorSpace));
    509 }
    510 
    511 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
    512                                                 const GrBackendObject yuvTextureHandles[3],
    513                                                 const SkISize yuvSizes[3], GrSurfaceOrigin origin,
    514                                                 sk_sp<SkColorSpace> imageColorSpace) {
    515     return make_from_yuv_objects_copy(ctx, colorSpace, false, yuvTextureHandles, yuvSizes, origin,
    516                                       std::move(imageColorSpace));
    517 }
    518 
    519 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
    520                                                  const GrBackendObject yuvTextureHandles[2],
    521                                                  const SkISize yuvSizes[2],
    522                                                  GrSurfaceOrigin origin,
    523                                                  sk_sp<SkColorSpace> imageColorSpace) {
    524     return make_from_yuv_objects_copy(ctx, colorSpace, true, yuvTextureHandles, yuvSizes, origin,
    525                                       std::move(imageColorSpace));
    526 }
    527 
    528 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
    529                                                 const GrBackendTexture yuvBackendTextures[3],
    530                                                 const SkISize yuvSizes[3], GrSurfaceOrigin origin,
    531                                                 sk_sp<SkColorSpace> imageColorSpace) {
    532     return make_from_yuv_textures_copy(ctx, colorSpace, false, yuvBackendTextures, yuvSizes, origin,
    533                                        std::move(imageColorSpace));
    534 }
    535 
    536 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
    537                                                  const GrBackendTexture yuvBackendTextures[2],
    538                                                  const SkISize yuvSizes[2],
    539                                                  GrSurfaceOrigin origin,
    540                                                  sk_sp<SkColorSpace> imageColorSpace) {
    541     return make_from_yuv_textures_copy(ctx, colorSpace, true, yuvBackendTextures, yuvSizes, origin,
    542                                        std::move(imageColorSpace));
    543 }
    544 
    545 static sk_sp<SkImage> create_image_from_maker(GrContext* context, GrTextureMaker* maker,
    546                                               SkAlphaType at, uint32_t id,
    547                                               SkColorSpace* dstColorSpace) {
    548     sk_sp<SkColorSpace> texColorSpace;
    549     sk_sp<GrTextureProxy> proxy(maker->refTextureProxyForParams(
    550             GrSamplerState::ClampNearest(), dstColorSpace, &texColorSpace, nullptr));
    551     if (!proxy) {
    552         return nullptr;
    553     }
    554     return sk_make_sp<SkImage_Gpu>(context, id, at,
    555                                    std::move(proxy), std::move(texColorSpace), SkBudgeted::kNo);
    556 }
    557 
    558 sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const {
    559     if (!context) {
    560         return nullptr;
    561     }
    562     if (GrContext* incumbent = as_IB(this)->context()) {
    563         return incumbent == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr;
    564     }
    565 
    566     if (this->isLazyGenerated()) {
    567         GrImageTextureMaker maker(context, this, kDisallow_CachingHint);
    568         return create_image_from_maker(context, &maker, this->alphaType(),
    569                                        this->uniqueID(), dstColorSpace);
    570     }
    571 
    572     if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
    573         GrBitmapTextureMaker maker(context, *bmp);
    574         return create_image_from_maker(context, &maker, this->alphaType(),
    575                                        this->uniqueID(), dstColorSpace);
    576     }
    577     return nullptr;
    578 }
    579 
    580 sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> encoded,
    581                                                     bool buildMips, SkColorSpace* dstColorSpace) {
    582     sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded));
    583     if (!codecImage) {
    584         return nullptr;
    585     }
    586 
    587     // Some backends or drivers don't support (safely) moving resources between contexts
    588     if (!context || !context->caps()->crossContextTextureSupport()) {
    589         return codecImage;
    590     }
    591 
    592     // Turn the codec image into a GrTextureProxy
    593     GrImageTextureMaker maker(context, codecImage.get(), kDisallow_CachingHint);
    594     sk_sp<SkColorSpace> texColorSpace;
    595     GrSamplerState samplerState(
    596             GrSamplerState::WrapMode::kClamp,
    597             buildMips ? GrSamplerState::Filter::kMipMap : GrSamplerState::Filter::kBilerp);
    598     sk_sp<GrTextureProxy> proxy(
    599             maker.refTextureProxyForParams(samplerState, dstColorSpace, &texColorSpace, nullptr));
    600     if (!proxy) {
    601         return codecImage;
    602     }
    603 
    604     if (!proxy->instantiate(context->contextPriv().resourceProvider())) {
    605         return codecImage;
    606     }
    607     sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
    608 
    609     // Flush any writes or uploads
    610     context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
    611 
    612     GrGpu* gpu = context->contextPriv().getGpu();
    613     sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
    614 
    615     auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
    616                                                     std::move(sema), codecImage->alphaType(),
    617                                                     std::move(texColorSpace));
    618     return SkImage::MakeFromGenerator(std::move(gen));
    619 }
    620 
    621 sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrContext* context, const SkPixmap& pixmap,
    622                                                    bool buildMips, SkColorSpace* dstColorSpace) {
    623     // Some backends or drivers don't support (safely) moving resources between contexts
    624     if (!context || !context->caps()->crossContextTextureSupport()) {
    625         return SkImage::MakeRasterCopy(pixmap);
    626     }
    627 
    628     // If we don't have access to the resource provider and gpu (i.e. in a DDL context) we will not
    629     // be able to make everything needed for a GPU CrossContext image. Thus return a raster copy
    630     // instead.
    631     if (!context->contextPriv().resourceProvider()) {
    632         return SkImage::MakeRasterCopy(pixmap);
    633     }
    634 
    635     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
    636     // Turn the pixmap into a GrTextureProxy
    637     sk_sp<GrTextureProxy> proxy;
    638     if (buildMips) {
    639         SkBitmap bmp;
    640         bmp.installPixels(pixmap);
    641         proxy = proxyProvider->createMipMapProxyFromBitmap(bmp, dstColorSpace);
    642     } else {
    643         SkDestinationSurfaceColorMode colorMode = dstColorSpace
    644                 ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware
    645                 : SkDestinationSurfaceColorMode::kLegacy;
    646 
    647         if (SkImageInfoIsValid(pixmap.info(), colorMode)) {
    648             ATRACE_ANDROID_FRAMEWORK("Upload Texture [%ux%u]", pixmap.width(), pixmap.height());
    649             GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(pixmap.info(), *proxyProvider->caps());
    650             proxy = proxyProvider->createTextureProxy(desc, SkBudgeted::kYes, pixmap.addr(),
    651                                                       pixmap.rowBytes());
    652         }
    653     }
    654 
    655     if (!proxy) {
    656         return SkImage::MakeRasterCopy(pixmap);
    657     }
    658 
    659     sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
    660 
    661     // Flush any writes or uploads
    662     context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
    663     GrGpu* gpu = context->contextPriv().getGpu();
    664 
    665     sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
    666 
    667     auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
    668                                                     std::move(sema), pixmap.alphaType(),
    669                                                     pixmap.info().refColorSpace());
    670     return SkImage::MakeFromGenerator(std::move(gen));
    671 }
    672 
    673 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
    674 sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at,
    675                                                sk_sp<SkColorSpace> cs) {
    676     auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs);
    677     return SkImage::MakeFromGenerator(std::move(gen));
    678 }
    679 #endif
    680 
    681 ///////////////////////////////////////////////////////////////////////////////////////////////////
    682 
    683 bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx,
    684                                             sk_sp<SkImage> image,
    685                                             GrBackendTexture* backendTexture,
    686                                             BackendTextureReleaseProc* releaseProc) {
    687     if (!image || !ctx || !backendTexture || !releaseProc) {
    688         return false;
    689     }
    690 
    691     // Ensure we have a texture backed image.
    692     if (!image->isTextureBacked()) {
    693         image = image->makeTextureImage(ctx, nullptr);
    694         if (!image) {
    695             return false;
    696         }
    697     }
    698     GrTexture* texture = image->getTexture();
    699     if (!texture) {
    700         // In context-loss cases, we may not have a texture.
    701         return false;
    702     }
    703 
    704     // If the image's context doesn't match the provided context, fail.
    705     if (texture->getContext() != ctx) {
    706         return false;
    707     }
    708 
    709     // Flush any pending IO on the texture.
    710     ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
    711     SkASSERT(!texture->surfacePriv().hasPendingIO());
    712 
    713     // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
    714     // image is not unique, or if the texture wraps an external object.
    715     if (!image->unique() || !texture->surfacePriv().hasUniqueRef() ||
    716         texture->resourcePriv().refsWrappedObjects()) {
    717         // onMakeSubset will always copy the image.
    718         image = as_IB(image)->onMakeSubset(image->bounds());
    719         if (!image) {
    720             return false;
    721         }
    722 
    723         texture = image->getTexture();
    724         if (!texture) {
    725             return false;
    726         }
    727 
    728         // Flush to ensure that the copy is completed before we return the texture.
    729         ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
    730         SkASSERT(!texture->surfacePriv().hasPendingIO());
    731     }
    732 
    733     SkASSERT(!texture->resourcePriv().refsWrappedObjects());
    734     SkASSERT(texture->surfacePriv().hasUniqueRef());
    735     SkASSERT(image->unique());
    736 
    737     // Take a reference to the GrTexture and release the image.
    738     sk_sp<GrTexture> textureRef(SkSafeRef(texture));
    739     image = nullptr;
    740 
    741     // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
    742     return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
    743 }
    744 
    745 ///////////////////////////////////////////////////////////////////////////////////////////////////
    746 
    747 sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> target, SkColorType,
    748                                              SkTransferFunctionBehavior premulBehavior) const {
    749     if (SkTransferFunctionBehavior::kRespect == premulBehavior) {
    750         // TODO: Implement this.
    751         return nullptr;
    752     }
    753 
    754     sk_sp<SkColorSpace> srcSpace = fColorSpace;
    755     if (!fColorSpace) {
    756         if (target->isSRGB()) {
    757             return sk_ref_sp(const_cast<SkImage*>((SkImage*)this));
    758         }
    759 
    760         srcSpace = SkColorSpace::MakeSRGB();
    761     }
    762 
    763     auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), target.get());
    764     if (!xform) {
    765         return sk_ref_sp(const_cast<SkImage_Gpu*>(this));
    766     }
    767 
    768     sk_sp<GrRenderTargetContext> renderTargetContext(fContext->makeDeferredRenderTargetContext(
    769         SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig, nullptr));
    770     if (!renderTargetContext) {
    771         return nullptr;
    772     }
    773 
    774     GrPaint paint;
    775     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
    776     paint.addColorTextureProcessor(fProxy, SkMatrix::I());
    777     paint.addColorFragmentProcessor(std::move(xform));
    778 
    779     const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
    780 
    781     renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
    782 
    783     if (!renderTargetContext->asTextureProxy()) {
    784         return nullptr;
    785     }
    786 
    787     // MDB: this call is okay bc we know 'renderTargetContext' was exact
    788     return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
    789                                    fAlphaType, renderTargetContext->asTextureProxyRef(),
    790                                    std::move(target), fBudgeted);
    791 
    792 }
    793 
    794 bool SkImage_Gpu::onIsValid(GrContext* context) const {
    795     // The base class has already checked that context isn't abandoned (if it's not nullptr)
    796     if (fContext->abandoned()) {
    797         return false;
    798     }
    799 
    800     if (context && context != fContext) {
    801         return false;
    802     }
    803 
    804     return true;
    805 }
    806