• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ScopedGenerator(const sk_sp<SharedGenerator> & gen)40     ScopedGenerator(const sk_sp<SharedGenerator>& gen)
41       : fSharedGenerator(gen)
42       , fAutoAquire(gen->fMutex) {}
43 
operator ->() const44     SkImageGenerator* operator->() const {
45         fSharedGenerator->fMutex.assertHeld();
46         return fSharedGenerator->fGenerator.get();
47     }
48 
operator SkImageGenerator*() const49     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 
Validator(sk_sp<SharedGenerator> gen,const SkIRect * subset)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 
NewFromGenerator(std::unique_ptr<SkImageGenerator> gen,const SkIRect * subset)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 
SkImageCacherator(Validator * validator)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 
~SkImageCacherator()124 SkImageCacherator::~SkImageCacherator() {}
125 
refEncoded(GrContext * ctx)126 SkData* SkImageCacherator::refEncoded(GrContext* ctx) {
127     ScopedGenerator generator(fSharedGenerator);
128     return generator->refEncodedData(ctx);
129 }
130 
check_output_bitmap(const SkBitmap & bitmap,uint32_t expectedID)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 //
generateBitmap(SkBitmap * bitmap,const SkImageInfo & decodeInfo)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 
directGeneratePixels(const SkImageInfo & info,void * pixels,size_t rb,int srcX,int srcY)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 
lockAsBitmapOnlyIfAlreadyCached(SkBitmap * bitmap,CachedFormat format)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 
tryLockAsBitmap(SkBitmap * bitmap,const SkImage * client,SkImage::CachingHint chint,CachedFormat format,const SkImageInfo & info)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 
lockAsBitmap(GrContext * context,SkBitmap * bitmap,const SkImage * client,SkColorSpace * dstColorSpace,SkImage::CachingHint chint)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 {
CacheCapsCacheCaps284     CacheCaps(const GrCaps* caps) : fCaps(caps) {}
285 
286 #if SK_SUPPORT_GPU
supportsHalfFloatCacheCaps287     bool supportsHalfFloat() const {
288         return !fCaps ||
289             (fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) &&
290              fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig, false));
291     }
292 
supportsSRGBCacheCaps293     bool supportsSRGB() const {
294         return !fCaps ||
295             (fCaps->srgbSupport() && fCaps->isConfigTexturable(kSRGBA_8888_GrPixelConfig));
296     }
297 
supportsSBGRCacheCaps298     bool supportsSBGR() const {
299         return !fCaps || fCaps->srgbSupport();
300     }
301 #else
supportsHalfFloatCacheCaps302     bool supportsHalfFloat() const { return true; }
supportsSRGBCacheCaps303     bool supportsSRGB() const { return true; }
supportsSBGRCacheCaps304     bool supportsSBGR() const { return true; }
305 #endif
306 
307     const GrCaps* fCaps;
308 };
309 
chooseCacheFormat(SkColorSpace * dstColorSpace,const GrCaps * grCaps)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 
buildCacheInfo(CachedFormat format)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 
makeCacheKeyFromOrigKey(const GrUniqueKey & origKey,CachedFormat format,GrUniqueKey * cacheKey)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
load_compressed_into_texture(GrContext * ctx,SkData * data,GrSurfaceDesc desc)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:
Generator_GrYUVProvider(SkImageGenerator * gen)480     Generator_GrYUVProvider(SkImageGenerator* gen) : fGen(gen) {}
481 
onGetID()482     uint32_t onGetID() override { return fGen->uniqueID(); }
onQueryYUV8(SkYUVSizeInfo * sizeInfo,SkYUVColorSpace * colorSpace) const483     bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override {
484         return fGen->queryYUV8(sizeInfo, colorSpace);
485     }
onGetYUV8Planes(const SkYUVSizeInfo & sizeInfo,void * planes[3])486     bool onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override {
487         return fGen->getYUV8Planes(sizeInfo, planes);
488     }
489 };
490 
set_key_on_proxy(GrResourceProvider * resourceProvider,GrTextureProxy * proxy,const GrUniqueKey & key)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 
getColorSpace(GrContext * ctx,SkColorSpace * dstColorSpace)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  */
lockTextureProxy(GrContext * ctx,const GrUniqueKey & origKey,const SkImage * client,SkImage::CachingHint chint,bool willBeMipped,SkColorSpace * dstColorSpace)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 
lockAsTextureProxy(GrContext * ctx,const GrSamplerParams & params,SkColorSpace * dstColorSpace,sk_sp<SkColorSpace> * texColorSpace,const SkImage * client,SkScalar scaleAdjust[2],SkImage::CachingHint chint)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