Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2015 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 "SkBitmap.h"
      9 #include "SkBitmapCache.h"
     10 #include "SkColorSpace_Base.h"
     11 #include "SkImage_Base.h"
     12 #include "SkImageCacherator.h"
     13 #include "SkMallocPixelRef.h"
     14 #include "SkNextID.h"
     15 #include "SkPixelRef.h"
     16 #include "SkResourceCache.h"
     17 
     18 #if SK_SUPPORT_GPU
     19 #include "GrContext.h"
     20 #include "GrContextPriv.h"
     21 #include "GrGpuResourcePriv.h"
     22 #include "GrImageTextureMaker.h"
     23 #include "GrResourceKey.h"
     24 #include "GrResourceProvider.h"
     25 #include "GrSamplerParams.h"
     26 #include "GrYUVProvider.h"
     27 #include "SkGr.h"
     28 #endif
     29 
     30 // Until we actually have codecs/etc. that can contain/support a GPU texture format
     31 // skip this step, since for some generators, returning their encoded data as a SkData
     32 // can be somewhat expensive, and this call doesn't indicate to the generator that we're
     33 // only interested in GPU datas...
     34 // see skbug.com/ 4971, 5128, ...
     35 //#define SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
     36 
     37 // Helper for exclusive access to a shared generator.
     38 class SkImageCacherator::ScopedGenerator {
     39 public:
     40     ScopedGenerator(const sk_sp<SharedGenerator>& gen)
     41       : fSharedGenerator(gen)
     42       , fAutoAquire(gen->fMutex) {}
     43 
     44     SkImageGenerator* operator->() const {
     45         fSharedGenerator->fMutex.assertHeld();
     46         return fSharedGenerator->fGenerator.get();
     47     }
     48 
     49     operator SkImageGenerator*() const {
     50         fSharedGenerator->fMutex.assertHeld();
     51         return fSharedGenerator->fGenerator.get();
     52     }
     53 
     54 private:
     55     const sk_sp<SharedGenerator>& fSharedGenerator;
     56     SkAutoExclusive               fAutoAquire;
     57 };
     58 
     59 SkImageCacherator::Validator::Validator(sk_sp<SharedGenerator> gen, const SkIRect* subset)
     60     : fSharedGenerator(std::move(gen)) {
     61 
     62     if (!fSharedGenerator) {
     63         return;
     64     }
     65 
     66     // The following generator accessors are safe without acquiring the mutex (const getters).
     67     // TODO: refactor to use a ScopedGenerator instead, for clarity.
     68     const SkImageInfo& info = fSharedGenerator->fGenerator->getInfo();
     69     if (info.isEmpty()) {
     70         fSharedGenerator.reset();
     71         return;
     72     }
     73 
     74     fUniqueID = fSharedGenerator->fGenerator->uniqueID();
     75     const SkIRect bounds = SkIRect::MakeWH(info.width(), info.height());
     76     if (subset) {
     77         if (!bounds.contains(*subset)) {
     78             fSharedGenerator.reset();
     79             return;
     80         }
     81         if (*subset != bounds) {
     82             // we need a different uniqueID since we really are a subset of the raw generator
     83             fUniqueID = SkNextID::ImageID();
     84         }
     85     } else {
     86         subset = &bounds;
     87     }
     88 
     89     fInfo   = info.makeWH(subset->width(), subset->height());
     90     fOrigin = SkIPoint::Make(subset->x(), subset->y());
     91 
     92     // If the encoded data is in a strange color space (it's not an XYZ matrix space), we won't be
     93     // able to preserve the gamut of the encoded data when we decode it. Instead, we'll have to
     94     // decode to a known color space (linear sRGB is a good choice). But we need to adjust the
     95     // stored color space, because drawing code will ask the SkImage for its color space, which
     96     // will in turn ask the cacherator. If we return the A2B color space, then we will be unable to
     97     // construct a source-to-dest gamut transformation matrix.
     98     if (fInfo.colorSpace() &&
     99         SkColorSpace_Base::Type::kXYZ != as_CSB(fInfo.colorSpace())->type()) {
    100         fInfo = fInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear());
    101     }
    102 }
    103 
    104 SkImageCacherator* SkImageCacherator::NewFromGenerator(std::unique_ptr<SkImageGenerator> gen,
    105                                                        const SkIRect* subset) {
    106     Validator validator(SharedGenerator::Make(std::move(gen)), subset);
    107 
    108     return validator ? new SkImageCacherator(&validator) : nullptr;
    109 }
    110 
    111 SkImageCacherator::SkImageCacherator(Validator* validator)
    112     : fSharedGenerator(std::move(validator->fSharedGenerator)) // we take ownership
    113     , fInfo(validator->fInfo)
    114     , fOrigin(validator->fOrigin)
    115 {
    116     fUniqueIDs[kLegacy_CachedFormat] = validator->fUniqueID;
    117     for (int i = 1; i < kNumCachedFormats; ++i) {
    118         // We lazily allocate IDs for non-default caching cases
    119         fUniqueIDs[i] = kNeedNewImageUniqueID;
    120     }
    121     SkASSERT(fSharedGenerator);
    122 }
    123 
    124 SkImageCacherator::~SkImageCacherator() {}
    125 
    126 SkData* SkImageCacherator::refEncoded(GrContext* ctx) {
    127     ScopedGenerator generator(fSharedGenerator);
    128     return generator->refEncodedData(ctx);
    129 }
    130 
    131 static bool check_output_bitmap(const SkBitmap& bitmap, uint32_t expectedID) {
    132     SkASSERT(bitmap.getGenerationID() == expectedID);
    133     SkASSERT(bitmap.isImmutable());
    134     SkASSERT(bitmap.getPixels());
    135     return true;
    136 }
    137 
    138 // Note, this returns a new, mutable, bitmap, with a new genID.
    139 // If you want the immutable bitmap with the same ID as our cacherator, call tryLockAsBitmap()
    140 //
    141 bool SkImageCacherator::generateBitmap(SkBitmap* bitmap, const SkImageInfo& decodeInfo) {
    142     SkBitmap::Allocator* allocator = SkResourceCache::GetAllocator();
    143 
    144     ScopedGenerator generator(fSharedGenerator);
    145     const SkImageInfo& genInfo = generator->getInfo();
    146     if (decodeInfo.dimensions() == genInfo.dimensions()) {
    147         SkASSERT(fOrigin.x() == 0 && fOrigin.y() == 0);
    148         // fast-case, no copy needed
    149         return generator->tryGenerateBitmap(bitmap, decodeInfo, allocator);
    150     } else {
    151         // need to handle subsetting, so we first generate the full size version, and then
    152         // "read" from it to get our subset. See https://bug.skia.org/4213
    153 
    154         SkBitmap full;
    155         if (!generator->tryGenerateBitmap(&full,
    156                                           decodeInfo.makeWH(genInfo.width(), genInfo.height()),
    157                                           allocator)) {
    158             return false;
    159         }
    160         if (!bitmap->tryAllocPixels(decodeInfo, nullptr, full.getColorTable())) {
    161             return false;
    162         }
    163         return full.readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(),
    164                                fOrigin.x(), fOrigin.y());
    165     }
    166 }
    167 
    168 bool SkImageCacherator::directGeneratePixels(const SkImageInfo& info, void* pixels, size_t rb,
    169                                              int srcX, int srcY) {
    170     ScopedGenerator generator(fSharedGenerator);
    171     const SkImageInfo& genInfo = generator->getInfo();
    172     // Currently generators do not natively handle subsets, so check that first.
    173     if (srcX || srcY || genInfo.width() != info.width() || genInfo.height() != info.height()) {
    174         return false;
    175     }
    176     return generator->getPixels(info, pixels, rb);
    177 }
    178 
    179 //////////////////////////////////////////////////////////////////////////////////////////////////
    180 
    181 bool SkImageCacherator::lockAsBitmapOnlyIfAlreadyCached(SkBitmap* bitmap, CachedFormat format) {
    182     return kNeedNewImageUniqueID != fUniqueIDs[format] &&
    183         SkBitmapCache::Find(SkBitmapCacheDesc::Make(fUniqueIDs[format],
    184                                                     fInfo.width(), fInfo.height()), bitmap) &&
    185         check_output_bitmap(*bitmap, fUniqueIDs[format]);
    186 }
    187 
    188 bool SkImageCacherator::tryLockAsBitmap(SkBitmap* bitmap, const SkImage* client,
    189                                         SkImage::CachingHint chint, CachedFormat format,
    190                                         const SkImageInfo& info) {
    191     if (this->lockAsBitmapOnlyIfAlreadyCached(bitmap, format)) {
    192         return true;
    193     }
    194     if (!this->generateBitmap(bitmap, info)) {
    195         return false;
    196     }
    197 
    198     if (kNeedNewImageUniqueID == fUniqueIDs[format]) {
    199         fUniqueIDs[format] = SkNextID::ImageID();
    200     }
    201     bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]);
    202     if (SkImage::kAllow_CachingHint == chint) {
    203         SkBitmapCache::Add(SkBitmapCacheDesc::Make(fUniqueIDs[format],
    204                                                    fInfo.width(), fInfo.height()), *bitmap);
    205         if (client) {
    206             as_IB(client)->notifyAddedToCache();
    207         }
    208     }
    209     return true;
    210 }
    211 
    212 bool SkImageCacherator::lockAsBitmap(GrContext* context, SkBitmap* bitmap, const SkImage* client,
    213                                      SkColorSpace* dstColorSpace,
    214                                      SkImage::CachingHint chint) {
    215     CachedFormat format = this->chooseCacheFormat(dstColorSpace);
    216     SkImageInfo cacheInfo = this->buildCacheInfo(format);
    217 
    218     if (kNeedNewImageUniqueID == fUniqueIDs[format]) {
    219         fUniqueIDs[format] = SkNextID::ImageID();
    220     }
    221 
    222     if (this->tryLockAsBitmap(bitmap, client, chint, format, cacheInfo)) {
    223         return check_output_bitmap(*bitmap, fUniqueIDs[format]);
    224     }
    225 
    226 #if SK_SUPPORT_GPU
    227     if (!context) {
    228         bitmap->reset();
    229         return false;
    230     }
    231 
    232     // Try to get a texture and read it back to raster (and then cache that with our ID)
    233     sk_sp<GrTextureProxy> proxy;
    234 
    235     {
    236         ScopedGenerator generator(fSharedGenerator);
    237         proxy = generator->generateTexture(context, cacheInfo, fOrigin);
    238     }
    239     if (!proxy) {
    240         bitmap->reset();
    241         return false;
    242     }
    243 
    244     if (!bitmap->tryAllocPixels(cacheInfo)) {
    245         bitmap->reset();
    246         return false;
    247     }
    248 
    249     sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeWrappedSurfaceContext(
    250                                                     proxy,
    251                                                     fInfo.refColorSpace())); // src colorSpace
    252     if (!sContext) {
    253         bitmap->reset();
    254         return false;
    255     }
    256 
    257     if (!sContext->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
    258         bitmap->reset();
    259         return false;
    260     }
    261 
    262     bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]);
    263     if (SkImage::kAllow_CachingHint == chint) {
    264         SkBitmapCache::Add(SkBitmapCacheDesc::Make(fUniqueIDs[format],
    265                                                    fInfo.width(), fInfo.height()), *bitmap);
    266         if (client) {
    267             as_IB(client)->notifyAddedToCache();
    268         }
    269     }
    270     return check_output_bitmap(*bitmap, fUniqueIDs[format]);
    271 #else
    272     return false;
    273 #endif
    274 }
    275 
    276 //////////////////////////////////////////////////////////////////////////////////////////////////
    277 
    278 // Abstraction of GrCaps that handles the cases where we don't have a caps pointer (because
    279 // we're in raster mode), or where GPU support is entirely missing. In theory, we only need the
    280 // chosen format to be texturable, but that lets us choose F16 on GLES implemenations where we
    281 // won't be able to read the texture back. We'd like to ensure that SkImake::makeNonTextureImage
    282 // works, so we require that the formats we choose are renderable (as a proxy for being readable).
    283 struct CacheCaps {
    284     CacheCaps(const GrCaps* caps) : fCaps(caps) {}
    285 
    286 #if SK_SUPPORT_GPU
    287     bool supportsHalfFloat() const {
    288         return !fCaps ||
    289             (fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) &&
    290              fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig, false));
    291     }
    292 
    293     bool supportsSRGB() const {
    294         return !fCaps ||
    295             (fCaps->srgbSupport() && fCaps->isConfigTexturable(kSRGBA_8888_GrPixelConfig));
    296     }
    297 
    298     bool supportsSBGR() const {
    299         return !fCaps || fCaps->srgbSupport();
    300     }
    301 #else
    302     bool supportsHalfFloat() const { return true; }
    303     bool supportsSRGB() const { return true; }
    304     bool supportsSBGR() const { return true; }
    305 #endif
    306 
    307     const GrCaps* fCaps;
    308 };
    309 
    310 SkImageCacherator::CachedFormat SkImageCacherator::chooseCacheFormat(SkColorSpace* dstColorSpace,
    311                                                                      const GrCaps* grCaps) {
    312     SkColorSpace* cs = fInfo.colorSpace();
    313     if (!cs || !dstColorSpace) {
    314         return kLegacy_CachedFormat;
    315     }
    316 
    317     CacheCaps caps(grCaps);
    318     switch (fInfo.colorType()) {
    319         case kUnknown_SkColorType:
    320         case kAlpha_8_SkColorType:
    321         case kRGB_565_SkColorType:
    322         case kARGB_4444_SkColorType:
    323             // We don't support color space on these formats, so always decode in legacy mode:
    324             // TODO: Ask the codec to decode these to something else (at least sRGB 8888)?
    325             return kLegacy_CachedFormat;
    326 
    327         case kIndex_8_SkColorType:
    328             // We can't draw from indexed textures with a color space, so ask the codec to expand
    329             if (cs->gammaCloseToSRGB()) {
    330                 if (caps.supportsSRGB()) {
    331                     return kSRGB8888_CachedFormat;
    332                 } else if (caps.supportsHalfFloat()) {
    333                     return kLinearF16_CachedFormat;
    334                 } else {
    335                     return kLegacy_CachedFormat;
    336                 }
    337             } else {
    338                 if (caps.supportsHalfFloat()) {
    339                     return kLinearF16_CachedFormat;
    340                 } else if (caps.supportsSRGB()) {
    341                     return kSRGB8888_CachedFormat;
    342                 } else {
    343                     return kLegacy_CachedFormat;
    344                 }
    345             }
    346 
    347         case kGray_8_SkColorType:
    348             // TODO: What do we do with grayscale sources that have strange color spaces attached?
    349             // The codecs and color space xform don't handle this correctly (yet), so drop it on
    350             // the floor. (Also, inflating by a factor of 8 is going to be unfortunate).
    351             // As it is, we don't directly support sRGB grayscale, so ask the codec to convert
    352             // it for us. This bypasses some really sketchy code GrUploadPixmapToTexture.
    353             if (cs->gammaCloseToSRGB() && caps.supportsSRGB()) {
    354                 return kSRGB8888_CachedFormat;
    355             } else {
    356                 return kLegacy_CachedFormat;
    357             }
    358 
    359         case kRGBA_8888_SkColorType:
    360             if (cs->gammaCloseToSRGB()) {
    361                 if (caps.supportsSRGB()) {
    362                     return kAsIs_CachedFormat;
    363                 } else if (caps.supportsHalfFloat()) {
    364                     return kLinearF16_CachedFormat;
    365                 } else {
    366                     return kLegacy_CachedFormat;
    367                 }
    368             } else {
    369                 if (caps.supportsHalfFloat()) {
    370                     return kLinearF16_CachedFormat;
    371                 } else if (caps.supportsSRGB()) {
    372                     return kSRGB8888_CachedFormat;
    373                 } else {
    374                     return kLegacy_CachedFormat;
    375                 }
    376             }
    377 
    378         case kBGRA_8888_SkColorType:
    379             // Odd case. sBGRA isn't a real thing, so we may not have this texturable.
    380             if (caps.supportsSBGR()) {
    381                 if (cs->gammaCloseToSRGB()) {
    382                     return kAsIs_CachedFormat;
    383                 } else if (caps.supportsHalfFloat()) {
    384                     return kLinearF16_CachedFormat;
    385                 } else if (caps.supportsSRGB()) {
    386                     return kSRGB8888_CachedFormat;
    387                 } else {
    388                     // sBGRA support without sRGBA is highly unlikely (impossible?) Nevertheless.
    389                     return kLegacy_CachedFormat;
    390                 }
    391             } else {
    392                 if (cs->gammaCloseToSRGB()) {
    393                     if (caps.supportsSRGB()) {
    394                         return kSRGB8888_CachedFormat;
    395                     } else if (caps.supportsHalfFloat()) {
    396                         return kLinearF16_CachedFormat;
    397                     } else {
    398                         return kLegacy_CachedFormat;
    399                     }
    400                 } else {
    401                     if (caps.supportsHalfFloat()) {
    402                         return kLinearF16_CachedFormat;
    403                     } else if (caps.supportsSRGB()) {
    404                         return kSRGB8888_CachedFormat;
    405                     } else {
    406                         return kLegacy_CachedFormat;
    407                     }
    408                 }
    409             }
    410 
    411         case kRGBA_F16_SkColorType:
    412             if (!caps.supportsHalfFloat()) {
    413                 if (caps.supportsSRGB()) {
    414                     return kSRGB8888_CachedFormat;
    415                 } else {
    416                     return kLegacy_CachedFormat;
    417                 }
    418             } else if (cs->gammaIsLinear()) {
    419                 return kAsIs_CachedFormat;
    420             } else {
    421                 return kLinearF16_CachedFormat;
    422             }
    423     }
    424     SkDEBUGFAIL("Unreachable");
    425     return kLegacy_CachedFormat;
    426 }
    427 
    428 SkImageInfo SkImageCacherator::buildCacheInfo(CachedFormat format) {
    429     switch (format) {
    430         case kLegacy_CachedFormat:
    431             return fInfo.makeColorSpace(nullptr);
    432         case kAsIs_CachedFormat:
    433             return fInfo;
    434         case kLinearF16_CachedFormat:
    435             return fInfo
    436                 .makeColorType(kRGBA_F16_SkColorType)
    437                 .makeColorSpace(as_CSB(fInfo.colorSpace())->makeLinearGamma());
    438         case kSRGB8888_CachedFormat:
    439             return fInfo
    440                 .makeColorType(kRGBA_8888_SkColorType)
    441                 .makeColorSpace(as_CSB(fInfo.colorSpace())->makeSRGBGamma());
    442         default:
    443             SkDEBUGFAIL("Invalid cached format");
    444             return fInfo;
    445     }
    446 }
    447 
    448 //////////////////////////////////////////////////////////////////////////////////////////////////
    449 
    450 #if SK_SUPPORT_GPU
    451 
    452 void SkImageCacherator::makeCacheKeyFromOrigKey(const GrUniqueKey& origKey, CachedFormat format,
    453                                                 GrUniqueKey* cacheKey) {
    454     SkASSERT(!cacheKey->isValid());
    455     if (origKey.isValid()) {
    456         static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
    457         GrUniqueKey::Builder builder(cacheKey, origKey, kDomain, 1);
    458         builder[0] = format;
    459     }
    460 }
    461 
    462 #ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
    463 static GrTexture* load_compressed_into_texture(GrContext* ctx, SkData* data, GrSurfaceDesc desc) {
    464     const void* rawStart;
    465     GrPixelConfig config = GrIsCompressedTextureDataSupported(ctx, data, desc.fWidth, desc.fHeight,
    466                                                               &rawStart);
    467     if (kUnknown_GrPixelConfig == config) {
    468         return nullptr;
    469     }
    470 
    471     desc.fConfig = config;
    472     return ctx->resourceProvider()->createTexture(desc, SkBudgeted::kYes, rawStart, 0);
    473 }
    474 #endif
    475 
    476 class Generator_GrYUVProvider : public GrYUVProvider {
    477     SkImageGenerator* fGen;
    478 
    479 public:
    480     Generator_GrYUVProvider(SkImageGenerator* gen) : fGen(gen) {}
    481 
    482     uint32_t onGetID() override { return fGen->uniqueID(); }
    483     bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override {
    484         return fGen->queryYUV8(sizeInfo, colorSpace);
    485     }
    486     bool onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override {
    487         return fGen->getYUV8Planes(sizeInfo, planes);
    488     }
    489 };
    490 
    491 static void set_key_on_proxy(GrResourceProvider* resourceProvider,
    492                              GrTextureProxy* proxy, const GrUniqueKey& key) {
    493     if (key.isValid()) {
    494         resourceProvider->assignUniqueKeyToProxy(key, proxy);
    495     }
    496 }
    497 
    498 sk_sp<SkColorSpace> SkImageCacherator::getColorSpace(GrContext* ctx, SkColorSpace* dstColorSpace) {
    499     // TODO: This isn't always correct. Picture generator currently produces textures in N32,
    500     // and will (soon) emit them in an arbitrary (destination) space. We will need to stash that
    501     // information in/on the key so we can return the correct space in case #1 of lockTexture.
    502     CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps());
    503     SkImageInfo cacheInfo = this->buildCacheInfo(format);
    504     return sk_ref_sp(cacheInfo.colorSpace());
    505 }
    506 
    507 /*
    508  *  We have a 5 ways to try to return a texture (in sorted order)
    509  *
    510  *  1. Check the cache for a pre-existing one
    511  *  2. Ask the generator to natively create one
    512  *  3. Ask the generator to return a compressed form that the GPU might support
    513  *  4. Ask the generator to return YUV planes, which the GPU can convert
    514  *  5. Ask the generator to return RGB(A) data, which the GPU can convert
    515  */
    516 sk_sp<GrTextureProxy> SkImageCacherator::lockTextureProxy(GrContext* ctx,
    517                                                           const GrUniqueKey& origKey,
    518                                                           const SkImage* client,
    519                                                           SkImage::CachingHint chint,
    520                                                           bool willBeMipped,
    521                                                           SkColorSpace* dstColorSpace) {
    522     // Values representing the various texture lock paths we can take. Used for logging the path
    523     // taken to a histogram.
    524     enum LockTexturePath {
    525         kFailure_LockTexturePath,
    526         kPreExisting_LockTexturePath,
    527         kNative_LockTexturePath,
    528         kCompressed_LockTexturePath,
    529         kYUV_LockTexturePath,
    530         kRGBA_LockTexturePath,
    531     };
    532 
    533     enum { kLockTexturePathCount = kRGBA_LockTexturePath + 1 };
    534 
    535     // Determine which cached format we're going to use (which may involve decoding to a different
    536     // info than the generator provides).
    537     CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps());
    538 
    539     // Fold the cache format into our texture key
    540     GrUniqueKey key;
    541     this->makeCacheKeyFromOrigKey(origKey, format, &key);
    542 
    543     // 1. Check the cache for a pre-existing one
    544     if (key.isValid()) {
    545         if (sk_sp<GrTextureProxy> proxy = ctx->resourceProvider()->findProxyByUniqueKey(key)) {
    546             SK_HISTOGRAM_ENUMERATION("LockTexturePath", kPreExisting_LockTexturePath,
    547                                      kLockTexturePathCount);
    548             return proxy;
    549         }
    550     }
    551 
    552     // The CachedFormat is both an index for which cache "slot" we'll use to store this particular
    553     // decoded variant of the encoded data, and also a recipe for how to transform the original
    554     // info to get the one that we're going to decode to.
    555     SkImageInfo cacheInfo = this->buildCacheInfo(format);
    556 
    557     // 2. Ask the generator to natively create one
    558     {
    559         ScopedGenerator generator(fSharedGenerator);
    560         if (sk_sp<GrTextureProxy> proxy = generator->generateTexture(ctx, cacheInfo, fOrigin)) {
    561             SK_HISTOGRAM_ENUMERATION("LockTexturePath", kNative_LockTexturePath,
    562                                      kLockTexturePathCount);
    563             set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key);
    564             return proxy;
    565         }
    566     }
    567 
    568     const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(cacheInfo, *ctx->caps());
    569 
    570 #ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
    571     // 3. Ask the generator to return a compressed form that the GPU might support
    572     sk_sp<SkData> data(this->refEncoded(ctx));
    573     if (data) {
    574         GrTexture* tex = load_compressed_into_texture(ctx, data, desc);
    575         if (tex) {
    576             SK_HISTOGRAM_ENUMERATION("LockTexturePath", kCompressed_LockTexturePath,
    577                                      kLockTexturePathCount);
    578             return set_key_and_return(tex, key);
    579         }
    580     }
    581 #endif
    582 
    583     // 4. Ask the generator to return YUV planes, which the GPU can convert
    584     if (!ctx->contextPriv().disableGpuYUVConversion()) {
    585         ScopedGenerator generator(fSharedGenerator);
    586         Generator_GrYUVProvider provider(generator);
    587         if (sk_sp<GrTextureProxy> proxy = provider.refAsTextureProxy(ctx, desc, true)) {
    588             SK_HISTOGRAM_ENUMERATION("LockTexturePath", kYUV_LockTexturePath,
    589                                      kLockTexturePathCount);
    590             set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key);
    591             return proxy;
    592         }
    593     }
    594 
    595     // 5. Ask the generator to return RGB(A) data, which the GPU can convert
    596     SkBitmap bitmap;
    597     if (this->tryLockAsBitmap(&bitmap, client, chint, format, cacheInfo)) {
    598         sk_sp<GrTextureProxy> proxy;
    599         if (willBeMipped) {
    600             proxy = GrGenerateMipMapsAndUploadToTextureProxy(ctx, bitmap, dstColorSpace);
    601         }
    602         if (!proxy) {
    603             proxy = GrUploadBitmapToTextureProxy(ctx->resourceProvider(), bitmap);
    604         }
    605         if (proxy) {
    606             SK_HISTOGRAM_ENUMERATION("LockTexturePath", kRGBA_LockTexturePath,
    607                                      kLockTexturePathCount);
    608             set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key);
    609             return proxy;
    610         }
    611     }
    612     SK_HISTOGRAM_ENUMERATION("LockTexturePath", kFailure_LockTexturePath,
    613                              kLockTexturePathCount);
    614     return nullptr;
    615 }
    616 
    617 ///////////////////////////////////////////////////////////////////////////////////////////////////
    618 
    619 sk_sp<GrTextureProxy> SkImageCacherator::lockAsTextureProxy(GrContext* ctx,
    620                                                             const GrSamplerParams& params,
    621                                                             SkColorSpace* dstColorSpace,
    622                                                             sk_sp<SkColorSpace>* texColorSpace,
    623                                                             const SkImage* client,
    624                                                             SkScalar scaleAdjust[2],
    625                                                             SkImage::CachingHint chint) {
    626     if (!ctx) {
    627         return nullptr;
    628     }
    629 
    630     return GrImageTextureMaker(ctx, this, client, chint).refTextureProxyForParams(params,
    631                                                                                   dstColorSpace,
    632                                                                                   texColorSpace,
    633                                                                                   scaleAdjust);
    634 }
    635 
    636 #endif
    637