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