d2bb14f1e35ec04fccc6cdb0a7642c992a911ccf
[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 "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, sk_ref_sp(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                                              SkTransferFunctionBehavior behavior) {
171     ScopedGenerator generator(fSharedGenerator);
172     const SkImageInfo& genInfo = generator->getInfo();
173     // Currently generators do not natively handle subsets, so check that first.
174     if (srcX || srcY || genInfo.width() != info.width() || genInfo.height() != info.height()) {
175         return false;
176     }
177
178     SkImageGenerator::Options opts;
179     opts.fBehavior = behavior;
180     return generator->getPixels(info, pixels, rb, &opts);
181 }
182
183 //////////////////////////////////////////////////////////////////////////////////////////////////
184
185 bool SkImageCacherator::lockAsBitmapOnlyIfAlreadyCached(SkBitmap* bitmap, CachedFormat format) {
186     return kNeedNewImageUniqueID != fUniqueIDs[format] &&
187         SkBitmapCache::Find(SkBitmapCacheDesc::Make(fUniqueIDs[format],
188                                                     fInfo.width(), fInfo.height()), bitmap) &&
189         check_output_bitmap(*bitmap, fUniqueIDs[format]);
190 }
191
192 bool SkImageCacherator::tryLockAsBitmap(SkBitmap* bitmap, const SkImage* client,
193                                         SkImage::CachingHint chint, CachedFormat format,
194                                         const SkImageInfo& info) {
195     if (this->lockAsBitmapOnlyIfAlreadyCached(bitmap, format)) {
196         return true;
197     }
198     if (!this->generateBitmap(bitmap, info)) {
199         return false;
200     }
201
202     if (kNeedNewImageUniqueID == fUniqueIDs[format]) {
203         fUniqueIDs[format] = SkNextID::ImageID();
204     }
205     bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]);
206     if (SkImage::kAllow_CachingHint == chint) {
207         SkBitmapCache::Add(SkBitmapCacheDesc::Make(fUniqueIDs[format],
208                                                    fInfo.width(), fInfo.height()), *bitmap);
209         if (client) {
210             as_IB(client)->notifyAddedToCache();
211         }
212     }
213     return true;
214 }
215
216 bool SkImageCacherator::lockAsBitmap(GrContext* context, 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     if (!context) {
232         bitmap->reset();
233         return false;
234     }
235
236     // Try to get a texture and read it back to raster (and then cache that with our ID)
237     sk_sp<GrTextureProxy> proxy;
238
239     {
240         ScopedGenerator generator(fSharedGenerator);
241         proxy = generator->generateTexture(context, cacheInfo, fOrigin);
242     }
243     if (!proxy) {
244         bitmap->reset();
245         return false;
246     }
247
248     if (!bitmap->tryAllocPixels(cacheInfo)) {
249         bitmap->reset();
250         return false;
251     }
252
253     sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeWrappedSurfaceContext(
254                                                     proxy,
255                                                     fInfo.refColorSpace())); // src colorSpace
256     if (!sContext) {
257         bitmap->reset();
258         return false;
259     }
260
261     if (!sContext->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
262         bitmap->reset();
263         return false;
264     }
265
266     bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]);
267     if (SkImage::kAllow_CachingHint == chint) {
268         SkBitmapCache::Add(SkBitmapCacheDesc::Make(fUniqueIDs[format],
269                                                    fInfo.width(), fInfo.height()), *bitmap);
270         if (client) {
271             as_IB(client)->notifyAddedToCache();
272         }
273     }
274     return check_output_bitmap(*bitmap, fUniqueIDs[format]);
275 #else
276     return false;
277 #endif
278 }
279
280 //////////////////////////////////////////////////////////////////////////////////////////////////
281
282 // Abstraction of GrCaps that handles the cases where we don't have a caps pointer (because
283 // we're in raster mode), or where GPU support is entirely missing. In theory, we only need the
284 // chosen format to be texturable, but that lets us choose F16 on GLES implemenations where we
285 // won't be able to read the texture back. We'd like to ensure that SkImake::makeNonTextureImage
286 // works, so we require that the formats we choose are renderable (as a proxy for being readable).
287 struct CacheCaps {
288     CacheCaps(const GrCaps* caps) : fCaps(caps) {}
289
290 #if SK_SUPPORT_GPU
291     bool supportsHalfFloat() const {
292         return !fCaps ||
293             (fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) &&
294              fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig, false));
295     }
296
297     bool supportsSRGB() const {
298         return !fCaps ||
299             (fCaps->srgbSupport() && fCaps->isConfigTexturable(kSRGBA_8888_GrPixelConfig));
300     }
301
302     bool supportsSBGR() const {
303         return !fCaps || fCaps->srgbSupport();
304     }
305 #else
306     bool supportsHalfFloat() const { return true; }
307     bool supportsSRGB() const { return true; }
308     bool supportsSBGR() const { return true; }
309 #endif
310
311     const GrCaps* fCaps;
312 };
313
314 SkImageCacherator::CachedFormat SkImageCacherator::chooseCacheFormat(SkColorSpace* dstColorSpace,
315                                                                      const GrCaps* grCaps) {
316     SkColorSpace* cs = fInfo.colorSpace();
317     if (!cs || !dstColorSpace) {
318         return kLegacy_CachedFormat;
319     }
320
321     CacheCaps caps(grCaps);
322     switch (fInfo.colorType()) {
323         case kUnknown_SkColorType:
324         case kAlpha_8_SkColorType:
325         case kRGB_565_SkColorType:
326         case kARGB_4444_SkColorType:
327             // We don't support color space on these formats, so always decode in legacy mode:
328             // TODO: Ask the codec to decode these to something else (at least sRGB 8888)?
329             return kLegacy_CachedFormat;
330
331         case kIndex_8_SkColorType:
332             // We can't draw from indexed textures with a color space, so ask the codec to expand
333             if (cs->gammaCloseToSRGB()) {
334                 if (caps.supportsSRGB()) {
335                     return kSRGB8888_CachedFormat;
336                 } else if (caps.supportsHalfFloat()) {
337                     return kLinearF16_CachedFormat;
338                 } else {
339                     return kLegacy_CachedFormat;
340                 }
341             } else {
342                 if (caps.supportsHalfFloat()) {
343                     return kLinearF16_CachedFormat;
344                 } else if (caps.supportsSRGB()) {
345                     return kSRGB8888_CachedFormat;
346                 } else {
347                     return kLegacy_CachedFormat;
348                 }
349             }
350
351         case kGray_8_SkColorType:
352             // TODO: What do we do with grayscale sources that have strange color spaces attached?
353             // The codecs and color space xform don't handle this correctly (yet), so drop it on
354             // the floor. (Also, inflating by a factor of 8 is going to be unfortunate).
355             // As it is, we don't directly support sRGB grayscale, so ask the codec to convert
356             // it for us. This bypasses some really sketchy code GrUploadPixmapToTexture.
357             if (cs->gammaCloseToSRGB() && caps.supportsSRGB()) {
358                 return kSRGB8888_CachedFormat;
359             } else {
360                 return kLegacy_CachedFormat;
361             }
362
363         case kRGBA_8888_SkColorType:
364             if (cs->gammaCloseToSRGB()) {
365                 if (caps.supportsSRGB()) {
366                     return kSRGB8888_CachedFormat;
367                 } else if (caps.supportsHalfFloat()) {
368                     return kLinearF16_CachedFormat;
369                 } else {
370                     return kLegacy_CachedFormat;
371                 }
372             } else {
373                 if (caps.supportsHalfFloat()) {
374                     return kLinearF16_CachedFormat;
375                 } else if (caps.supportsSRGB()) {
376                     return kSRGB8888_CachedFormat;
377                 } else {
378                     return kLegacy_CachedFormat;
379                 }
380             }
381
382         case kBGRA_8888_SkColorType:
383             // Odd case. sBGRA isn't a real thing, so we may not have this texturable.
384             if (caps.supportsSBGR()) {
385                 if (cs->gammaCloseToSRGB()) {
386                     return kSBGR8888_CachedFormat;
387                 } else if (caps.supportsHalfFloat()) {
388                     return kLinearF16_CachedFormat;
389                 } else if (caps.supportsSRGB()) {
390                     return kSRGB8888_CachedFormat;
391                 } else {
392                     // sBGRA support without sRGBA is highly unlikely (impossible?) Nevertheless.
393                     return kLegacy_CachedFormat;
394                 }
395             } else {
396                 if (cs->gammaCloseToSRGB()) {
397                     if (caps.supportsSRGB()) {
398                         return kSRGB8888_CachedFormat;
399                     } else if (caps.supportsHalfFloat()) {
400                         return kLinearF16_CachedFormat;
401                     } else {
402                         return kLegacy_CachedFormat;
403                     }
404                 } else {
405                     if (caps.supportsHalfFloat()) {
406                         return kLinearF16_CachedFormat;
407                     } else if (caps.supportsSRGB()) {
408                         return kSRGB8888_CachedFormat;
409                     } else {
410                         return kLegacy_CachedFormat;
411                     }
412                 }
413             }
414
415         case kRGBA_F16_SkColorType:
416             if (caps.supportsHalfFloat()) {
417                 return kLinearF16_CachedFormat;
418             } else if (caps.supportsSRGB()) {
419                 return kSRGB8888_CachedFormat;
420             } else {
421                 return kLegacy_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 kLinearF16_CachedFormat:
433             return fInfo.makeColorType(kRGBA_F16_SkColorType)
434                         .makeColorSpace(as_CSB(fInfo.colorSpace())->makeLinearGamma());
435         case kSRGB8888_CachedFormat:
436             // If the transfer function is nearly (but not exactly) sRGB, we don't want the codec
437             // to bother trans-coding. It would be slow, and do more harm than good visually,
438             // so we make sure to leave the colorspace as-is.
439             if (fInfo.colorSpace()->gammaCloseToSRGB()) {
440                 return fInfo.makeColorType(kRGBA_8888_SkColorType);
441             } else {
442                 return fInfo.makeColorType(kRGBA_8888_SkColorType)
443                             .makeColorSpace(as_CSB(fInfo.colorSpace())->makeSRGBGamma());
444             }
445         case kSBGR8888_CachedFormat:
446             // See note above about not-quite-sRGB transfer functions.
447             if (fInfo.colorSpace()->gammaCloseToSRGB()) {
448                 return fInfo.makeColorType(kBGRA_8888_SkColorType);
449             } else {
450                 return fInfo.makeColorType(kBGRA_8888_SkColorType)
451                             .makeColorSpace(as_CSB(fInfo.colorSpace())->makeSRGBGamma());
452             }
453         default:
454             SkDEBUGFAIL("Invalid cached format");
455             return fInfo;
456     }
457 }
458
459 //////////////////////////////////////////////////////////////////////////////////////////////////
460
461 #if SK_SUPPORT_GPU
462
463 void SkImageCacherator::makeCacheKeyFromOrigKey(const GrUniqueKey& origKey, CachedFormat format,
464                                                 GrUniqueKey* cacheKey) {
465     SkASSERT(!cacheKey->isValid());
466     if (origKey.isValid()) {
467         static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
468         GrUniqueKey::Builder builder(cacheKey, origKey, kDomain, 1);
469         builder[0] = format;
470     }
471 }
472
473 #ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
474 static GrTexture* load_compressed_into_texture(GrContext* ctx, SkData* data, GrSurfaceDesc desc) {
475     const void* rawStart;
476     GrPixelConfig config = GrIsCompressedTextureDataSupported(ctx, data, desc.fWidth, desc.fHeight,
477                                                               &rawStart);
478     if (kUnknown_GrPixelConfig == config) {
479         return nullptr;
480     }
481
482     desc.fConfig = config;
483     return ctx->resourceProvider()->createTexture(desc, SkBudgeted::kYes, rawStart, 0);
484 }
485 #endif
486
487 class Generator_GrYUVProvider : public GrYUVProvider {
488     SkImageGenerator* fGen;
489
490 public:
491     Generator_GrYUVProvider(SkImageGenerator* gen) : fGen(gen) {}
492
493     uint32_t onGetID() override { return fGen->uniqueID(); }
494     bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override {
495         return fGen->queryYUV8(sizeInfo, colorSpace);
496     }
497     bool onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override {
498         return fGen->getYUV8Planes(sizeInfo, planes);
499     }
500 };
501
502 static void set_key_on_proxy(GrResourceProvider* resourceProvider,
503                              GrTextureProxy* proxy, const GrUniqueKey& key) {
504     if (key.isValid()) {
505         resourceProvider->assignUniqueKeyToProxy(key, proxy);
506     }
507 }
508
509 sk_sp<SkColorSpace> SkImageCacherator::getColorSpace(GrContext* ctx, SkColorSpace* dstColorSpace) {
510     // TODO: This isn't always correct. Picture generator currently produces textures in N32,
511     // and will (soon) emit them in an arbitrary (destination) space. We will need to stash that
512     // information in/on the key so we can return the correct space in case #1 of lockTexture.
513     CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps());
514     SkImageInfo cacheInfo = this->buildCacheInfo(format);
515     return sk_ref_sp(cacheInfo.colorSpace());
516 }
517
518 /*
519  *  We have a 5 ways to try to return a texture (in sorted order)
520  *
521  *  1. Check the cache for a pre-existing one
522  *  2. Ask the generator to natively create one
523  *  3. Ask the generator to return a compressed form that the GPU might support
524  *  4. Ask the generator to return YUV planes, which the GPU can convert
525  *  5. Ask the generator to return RGB(A) data, which the GPU can convert
526  */
527 sk_sp<GrTextureProxy> SkImageCacherator::lockTextureProxy(GrContext* ctx,
528                                                           const GrUniqueKey& origKey,
529                                                           const SkImage* client,
530                                                           SkImage::CachingHint chint,
531                                                           bool willBeMipped,
532                                                           SkColorSpace* dstColorSpace) {
533     // Values representing the various texture lock paths we can take. Used for logging the path
534     // taken to a histogram.
535     enum LockTexturePath {
536         kFailure_LockTexturePath,
537         kPreExisting_LockTexturePath,
538         kNative_LockTexturePath,
539         kCompressed_LockTexturePath,
540         kYUV_LockTexturePath,
541         kRGBA_LockTexturePath,
542     };
543
544     enum { kLockTexturePathCount = kRGBA_LockTexturePath + 1 };
545
546     // Determine which cached format we're going to use (which may involve decoding to a different
547     // info than the generator provides).
548     CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps());
549
550     // Fold the cache format into our texture key
551     GrUniqueKey key;
552     this->makeCacheKeyFromOrigKey(origKey, format, &key);
553
554     // 1. Check the cache for a pre-existing one
555     if (key.isValid()) {
556         if (sk_sp<GrTextureProxy> proxy = ctx->resourceProvider()->findProxyByUniqueKey(key)) {
557             SK_HISTOGRAM_ENUMERATION("LockTexturePath", kPreExisting_LockTexturePath,
558                                      kLockTexturePathCount);
559             return proxy;
560         }
561     }
562
563     // The CachedFormat is both an index for which cache "slot" we'll use to store this particular
564     // decoded variant of the encoded data, and also a recipe for how to transform the original
565     // info to get the one that we're going to decode to.
566     SkImageInfo cacheInfo = this->buildCacheInfo(format);
567
568     // 2. Ask the generator to natively create one
569     {
570         ScopedGenerator generator(fSharedGenerator);
571         if (sk_sp<GrTextureProxy> proxy = generator->generateTexture(ctx, cacheInfo, fOrigin)) {
572             SK_HISTOGRAM_ENUMERATION("LockTexturePath", kNative_LockTexturePath,
573                                      kLockTexturePathCount);
574             set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key);
575             return proxy;
576         }
577     }
578
579     const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(cacheInfo, *ctx->caps());
580
581 #ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
582     // 3. Ask the generator to return a compressed form that the GPU might support
583     sk_sp<SkData> data(this->refEncoded(ctx));
584     if (data) {
585         GrTexture* tex = load_compressed_into_texture(ctx, data, desc);
586         if (tex) {
587             SK_HISTOGRAM_ENUMERATION("LockTexturePath", kCompressed_LockTexturePath,
588                                      kLockTexturePathCount);
589             return set_key_and_return(tex, key);
590         }
591     }
592 #endif
593
594     // 4. Ask the generator to return YUV planes, which the GPU can convert
595     if (!ctx->contextPriv().disableGpuYUVConversion()) {
596         ScopedGenerator generator(fSharedGenerator);
597         Generator_GrYUVProvider provider(generator);
598         if (sk_sp<GrTextureProxy> proxy = provider.refAsTextureProxy(ctx, desc, true)) {
599             SK_HISTOGRAM_ENUMERATION("LockTexturePath", kYUV_LockTexturePath,
600                                      kLockTexturePathCount);
601             set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key);
602             return proxy;
603         }
604     }
605
606     // 5. Ask the generator to return RGB(A) data, which the GPU can convert
607     SkBitmap bitmap;
608     if (this->tryLockAsBitmap(&bitmap, client, chint, format, cacheInfo)) {
609         sk_sp<GrTextureProxy> proxy;
610         if (willBeMipped) {
611             proxy = GrGenerateMipMapsAndUploadToTextureProxy(ctx, bitmap, dstColorSpace);
612         }
613         if (!proxy) {
614             proxy = GrUploadBitmapToTextureProxy(ctx->resourceProvider(), bitmap);
615         }
616         if (proxy) {
617             SK_HISTOGRAM_ENUMERATION("LockTexturePath", kRGBA_LockTexturePath,
618                                      kLockTexturePathCount);
619             set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key);
620             return proxy;
621         }
622     }
623     SK_HISTOGRAM_ENUMERATION("LockTexturePath", kFailure_LockTexturePath,
624                              kLockTexturePathCount);
625     return nullptr;
626 }
627
628 ///////////////////////////////////////////////////////////////////////////////////////////////////
629
630 sk_sp<GrTextureProxy> SkImageCacherator::lockAsTextureProxy(GrContext* ctx,
631                                                             const GrSamplerParams& params,
632                                                             SkColorSpace* dstColorSpace,
633                                                             sk_sp<SkColorSpace>* texColorSpace,
634                                                             const SkImage* client,
635                                                             SkScalar scaleAdjust[2],
636                                                             SkImage::CachingHint chint) {
637     if (!ctx) {
638         return nullptr;
639     }
640
641     return GrImageTextureMaker(ctx, this, client, chint).refTextureProxyForParams(params,
642                                                                                   dstColorSpace,
643                                                                                   texColorSpace,
644                                                                                   scaleAdjust);
645 }
646
647 #endif