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