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 "SkImage_Base.h"
9#include "SkImageCacherator.h"
10
11#include "SkBitmap.h"
12#include "SkBitmapCache.h"
13#include "SkData.h"
14#include "SkImageGenerator.h"
15#include "SkImagePriv.h"
16#include "SkNextID.h"
17#include "SkPixelRef.h"
18
19#if SK_SUPPORT_GPU
20#include "GrContext.h"
21#include "GrContextPriv.h"
22#include "GrGpuResourcePriv.h"
23#include "GrImageTextureMaker.h"
24#include "GrResourceKey.h"
25#include "GrProxyProvider.h"
26#include "GrSamplerState.h"
27#include "GrYUVProvider.h"
28#include "SkGr.h"
29#endif
30
31// Ref-counted tuple(SkImageGenerator, SkMutex) which allows sharing one generator among N images
32class SharedGenerator final : public SkNVRefCnt<SharedGenerator> {
33public:
34    static sk_sp<SharedGenerator> Make(std::unique_ptr<SkImageGenerator> gen) {
35        return gen ? sk_sp<SharedGenerator>(new SharedGenerator(std::move(gen))) : nullptr;
36    }
37
38    // This is thread safe.  It is a const field set in the constructor.
39    const SkImageInfo& getInfo() { return fGenerator->getInfo(); }
40
41private:
42    explicit SharedGenerator(std::unique_ptr<SkImageGenerator> gen)
43            : fGenerator(std::move(gen)) {
44        SkASSERT(fGenerator);
45    }
46
47    friend class ScopedGenerator;
48    friend class SkImage_Lazy;
49
50    std::unique_ptr<SkImageGenerator> fGenerator;
51    SkMutex                           fMutex;
52};
53
54class SkImage_Lazy : public SkImage_Base, public SkImageCacherator {
55public:
56    struct Validator {
57        Validator(sk_sp<SharedGenerator>, const SkIRect* subset, sk_sp<SkColorSpace> colorSpace);
58
59        operator bool() const { return fSharedGenerator.get(); }
60
61        sk_sp<SharedGenerator> fSharedGenerator;
62        SkImageInfo            fInfo;
63        SkIPoint               fOrigin;
64        sk_sp<SkColorSpace>    fColorSpace;
65        uint32_t               fUniqueID;
66    };
67
68    SkImage_Lazy(Validator* validator);
69
70    SkImageInfo onImageInfo() const override {
71        return fInfo;
72    }
73    SkAlphaType onAlphaType() const override {
74        return fInfo.alphaType();
75    }
76
77    bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY,
78                      CachingHint) const override;
79#if SK_SUPPORT_GPU
80    sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*,
81                                            const GrSamplerState&, SkColorSpace*,
82                                            sk_sp<SkColorSpace>*,
83                                            SkScalar scaleAdjust[2]) const override;
84#endif
85    SkData* onRefEncoded() const override;
86    sk_sp<SkImage> onMakeSubset(const SkIRect&) const override;
87    bool getROPixels(SkBitmap*, SkColorSpace* dstColorSpace, CachingHint) const override;
88    bool onIsLazyGenerated() const override { return true; }
89    bool onCanLazyGenerateOnGPU() const override;
90    sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>, SkColorType,
91                                    SkTransferFunctionBehavior) const override;
92
93    bool onIsValid(GrContext*) const override;
94
95    SkImageCacherator* peekCacherator() const override {
96        return const_cast<SkImage_Lazy*>(this);
97    }
98
99    // Only return true if the generate has already been cached.
100    bool lockAsBitmapOnlyIfAlreadyCached(SkBitmap*, CachedFormat) const;
101    // Call the underlying generator directly
102    bool directGeneratePixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
103                              int srcX, int srcY, SkTransferFunctionBehavior behavior) const;
104
105    // SkImageCacherator interface
106#if SK_SUPPORT_GPU
107    // Returns the texture proxy. If the cacherator is generating the texture and wants to cache it,
108    // it should use the passed in key (if the key is valid).
109    sk_sp<GrTextureProxy> lockTextureProxy(GrContext*,
110                                           const GrUniqueKey& key,
111                                           SkImage::CachingHint,
112                                           bool willBeMipped,
113                                           SkColorSpace* dstColorSpace,
114                                           GrTextureMaker::AllowedTexGenType genType) override;
115
116    // Returns the color space of the texture that would be returned if you called lockTexture.
117    // Separate code path to allow querying of the color space for textures that cached (even
118    // externally).
119    sk_sp<SkColorSpace> getColorSpace(GrContext*, SkColorSpace* dstColorSpace) override;
120    void makeCacheKeyFromOrigKey(const GrUniqueKey& origKey, CachedFormat,
121                                 GrUniqueKey* cacheKey) override;
122#endif
123
124    CachedFormat chooseCacheFormat(SkColorSpace* dstColorSpace,
125                                   const GrCaps* = nullptr) const override;
126    SkImageInfo buildCacheInfo(CachedFormat) const override;
127
128private:
129    class ScopedGenerator;
130
131    /**
132     *  On success (true), bitmap will point to the pixels for this generator. If this returns
133     *  false, the bitmap will be reset to empty.
134     */
135    bool lockAsBitmap(SkBitmap*, SkImage::CachingHint, CachedFormat, const SkImageInfo&,
136                      SkTransferFunctionBehavior) const;
137
138    /**
139     * Populates parameters to pass to the generator for reading pixels or generating a texture.
140     * For image generators, legacy versus true color blending is indicated using a
141     * SkTransferFunctionBehavior, and the target color space is specified on the SkImageInfo.
142     * If generatorImageInfo has no color space set, set its color space to this SkImage's color
143     * space, and return "ignore" behavior, indicating legacy mode. If generatorImageInfo has a
144     * color space set, return "respect" behavior, indicating linear blending mode.
145     */
146    SkTransferFunctionBehavior getGeneratorBehaviorAndInfo(SkImageInfo* generatorImageInfo) const;
147
148    sk_sp<SharedGenerator> fSharedGenerator;
149    // Note that fInfo is not necessarily the info from the generator. It may be cropped by
150    // onMakeSubset and its color space may be changed by onMakeColorSpace.
151    const SkImageInfo      fInfo;
152    const SkIPoint         fOrigin;
153
154    struct IDRec {
155        SkOnce      fOnce;
156        uint32_t    fUniqueID;
157    };
158    mutable IDRec fIDRecs[kNumCachedFormats];
159
160    uint32_t getUniqueID(CachedFormat) const;
161
162    // Repeated calls to onMakeColorSpace will result in a proliferation of unique IDs and
163    // SkImage_Lazy instances. Cache the result of the last successful onMakeColorSpace call.
164    mutable SkMutex             fOnMakeColorSpaceMutex;
165    mutable sk_sp<SkColorSpace> fOnMakeColorSpaceTarget;
166    mutable sk_sp<SkImage>      fOnMakeColorSpaceResult;
167
168    typedef SkImage_Base INHERITED;
169};
170
171///////////////////////////////////////////////////////////////////////////////
172
173SkImage_Lazy::Validator::Validator(sk_sp<SharedGenerator> gen, const SkIRect* subset,
174                                   sk_sp<SkColorSpace> colorSpace)
175        : fSharedGenerator(std::move(gen)) {
176    if (!fSharedGenerator) {
177        return;
178    }
179
180    // The following generator accessors are safe without acquiring the mutex (const getters).
181    // TODO: refactor to use a ScopedGenerator instead, for clarity.
182    const SkImageInfo& info = fSharedGenerator->fGenerator->getInfo();
183    if (info.isEmpty()) {
184        fSharedGenerator.reset();
185        return;
186    }
187
188    fUniqueID = fSharedGenerator->fGenerator->uniqueID();
189    const SkIRect bounds = SkIRect::MakeWH(info.width(), info.height());
190    if (subset) {
191        if (!bounds.contains(*subset)) {
192            fSharedGenerator.reset();
193            return;
194        }
195        if (*subset != bounds) {
196            // we need a different uniqueID since we really are a subset of the raw generator
197            fUniqueID = SkNextID::ImageID();
198        }
199    } else {
200        subset = &bounds;
201    }
202
203    fInfo   = info.makeWH(subset->width(), subset->height());
204    fOrigin = SkIPoint::Make(subset->x(), subset->y());
205    if (colorSpace) {
206        fInfo = fInfo.makeColorSpace(colorSpace);
207        fUniqueID = SkNextID::ImageID();
208    }
209}
210
211///////////////////////////////////////////////////////////////////////////////
212
213// Helper for exclusive access to a shared generator.
214class SkImage_Lazy::ScopedGenerator {
215public:
216    ScopedGenerator(const sk_sp<SharedGenerator>& gen)
217      : fSharedGenerator(gen)
218      , fAutoAquire(gen->fMutex) {}
219
220    SkImageGenerator* operator->() const {
221        fSharedGenerator->fMutex.assertHeld();
222        return fSharedGenerator->fGenerator.get();
223    }
224
225    operator SkImageGenerator*() const {
226        fSharedGenerator->fMutex.assertHeld();
227        return fSharedGenerator->fGenerator.get();
228    }
229
230private:
231    const sk_sp<SharedGenerator>& fSharedGenerator;
232    SkAutoExclusive               fAutoAquire;
233};
234
235///////////////////////////////////////////////////////////////////////////////
236
237SkImage_Lazy::SkImage_Lazy(Validator* validator)
238        : INHERITED(validator->fInfo.width(), validator->fInfo.height(), validator->fUniqueID)
239        , fSharedGenerator(std::move(validator->fSharedGenerator))
240        , fInfo(validator->fInfo)
241        , fOrigin(validator->fOrigin) {
242    SkASSERT(fSharedGenerator);
243    // We explicit set the legacy format slot, but leave the others uninitialized (via SkOnce)
244    // and only resolove them to IDs as needed (by calling getUniqueID()).
245    fIDRecs[kLegacy_CachedFormat].fOnce([this, validator] {
246        fIDRecs[kLegacy_CachedFormat].fUniqueID = validator->fUniqueID;
247    });
248}
249
250uint32_t SkImage_Lazy::getUniqueID(CachedFormat format) const {
251    IDRec* rec = &fIDRecs[format];
252    rec->fOnce([rec] {
253        rec->fUniqueID = SkNextID::ImageID();
254    });
255    return rec->fUniqueID;
256}
257
258//////////////////////////////////////////////////////////////////////////////////////////////////
259
260// Abstraction of GrCaps that handles the cases where we don't have a caps pointer (because
261// we're in raster mode), or where GPU support is entirely missing. In theory, we only need the
262// chosen format to be texturable, but that lets us choose F16 on GLES implemenations where we
263// won't be able to read the texture back. We'd like to ensure that SkImake::makeNonTextureImage
264// works, so we require that the formats we choose are renderable (as a proxy for being readable).
265struct CacheCaps {
266    CacheCaps(const GrCaps* caps) : fCaps(caps) {}
267
268#if SK_SUPPORT_GPU
269    bool supportsHalfFloat() const {
270        return !fCaps || (fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) &&
271                          fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig));
272    }
273
274    bool supportsSRGB() const {
275        return !fCaps ||
276            (fCaps->srgbSupport() && fCaps->isConfigTexturable(kSRGBA_8888_GrPixelConfig));
277    }
278
279    bool supportsSBGR() const {
280        return !fCaps || fCaps->srgbSupport();
281    }
282#else
283    bool supportsHalfFloat() const { return true; }
284    bool supportsSRGB() const { return true; }
285    bool supportsSBGR() const { return true; }
286#endif
287
288    const GrCaps* fCaps;
289};
290
291SkImageCacherator::CachedFormat SkImage_Lazy::chooseCacheFormat(SkColorSpace* dstColorSpace,
292                                                                const GrCaps* grCaps) const {
293    SkColorSpace* cs = fInfo.colorSpace();
294    if (!cs || !dstColorSpace) {
295        return kLegacy_CachedFormat;
296    }
297
298    CacheCaps caps(grCaps);
299    switch (fInfo.colorType()) {
300        case kUnknown_SkColorType:
301        case kAlpha_8_SkColorType:
302        case kRGB_565_SkColorType:
303        case kARGB_4444_SkColorType:
304        case kRGB_888x_SkColorType:
305        case kRGBA_1010102_SkColorType:
306        case kRGB_101010x_SkColorType:
307            // We don't support color space on these formats, so always decode in legacy mode:
308            // TODO: Ask the codec to decode these to something else (at least sRGB 8888)?
309            return kLegacy_CachedFormat;
310
311        case kGray_8_SkColorType:
312            // TODO: What do we do with grayscale sources that have strange color spaces attached?
313            // The codecs and color space xform don't handle this correctly (yet), so drop it on
314            // the floor. (Also, inflating by a factor of 8 is going to be unfortunate).
315            // As it is, we don't directly support sRGB grayscale, so ask the codec to convert
316            // it for us. This bypasses some really sketchy code GrUploadPixmapToTexture.
317            if (cs->gammaCloseToSRGB() && caps.supportsSRGB()) {
318                return kSRGB8888_CachedFormat;
319            } else {
320                return kLegacy_CachedFormat;
321            }
322
323        case kRGBA_8888_SkColorType:
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 kBGRA_8888_SkColorType:
343            // Odd case. sBGRA isn't a real thing, so we may not have this texturable.
344            if (caps.supportsSBGR()) {
345                if (cs->gammaCloseToSRGB()) {
346                    return kSBGR8888_CachedFormat;
347                } else if (caps.supportsHalfFloat()) {
348                    return kLinearF16_CachedFormat;
349                } else if (caps.supportsSRGB()) {
350                    return kSRGB8888_CachedFormat;
351                } else {
352                    // sBGRA support without sRGBA is highly unlikely (impossible?) Nevertheless.
353                    return kLegacy_CachedFormat;
354                }
355            } else {
356                if (cs->gammaCloseToSRGB()) {
357                    if (caps.supportsSRGB()) {
358                        return kSRGB8888_CachedFormat;
359                    } else if (caps.supportsHalfFloat()) {
360                        return kLinearF16_CachedFormat;
361                    } else {
362                        return kLegacy_CachedFormat;
363                    }
364                } else {
365                    if (caps.supportsHalfFloat()) {
366                        return kLinearF16_CachedFormat;
367                    } else if (caps.supportsSRGB()) {
368                        return kSRGB8888_CachedFormat;
369                    } else {
370                        return kLegacy_CachedFormat;
371                    }
372                }
373            }
374
375        case kRGBA_F16_SkColorType:
376            if (caps.supportsHalfFloat()) {
377                return kLinearF16_CachedFormat;
378            } else if (caps.supportsSRGB()) {
379                return kSRGB8888_CachedFormat;
380            } else {
381                return kLegacy_CachedFormat;
382            }
383    }
384    SkDEBUGFAIL("Unreachable");
385    return kLegacy_CachedFormat;
386}
387
388SkImageInfo SkImage_Lazy::buildCacheInfo(CachedFormat format) const {
389    switch (format) {
390        case kLegacy_CachedFormat:
391            return fInfo.makeColorSpace(nullptr);
392        case kLinearF16_CachedFormat:
393            return fInfo.makeColorType(kRGBA_F16_SkColorType)
394                        .makeColorSpace(fInfo.colorSpace()->makeLinearGamma());
395        case kSRGB8888_CachedFormat:
396            // If the transfer function is nearly (but not exactly) sRGB, we don't want the codec
397            // to bother trans-coding. It would be slow, and do more harm than good visually,
398            // so we make sure to leave the colorspace as-is.
399            if (fInfo.colorSpace()->gammaCloseToSRGB()) {
400                return fInfo.makeColorType(kRGBA_8888_SkColorType);
401            } else {
402                return fInfo.makeColorType(kRGBA_8888_SkColorType)
403                            .makeColorSpace(fInfo.colorSpace()->makeSRGBGamma());
404            }
405        case kSBGR8888_CachedFormat:
406            // See note above about not-quite-sRGB transfer functions.
407            if (fInfo.colorSpace()->gammaCloseToSRGB()) {
408                return fInfo.makeColorType(kBGRA_8888_SkColorType);
409            } else {
410                return fInfo.makeColorType(kBGRA_8888_SkColorType)
411                            .makeColorSpace(fInfo.colorSpace()->makeSRGBGamma());
412            }
413        default:
414            SkDEBUGFAIL("Invalid cached format");
415            return fInfo;
416    }
417}
418
419//////////////////////////////////////////////////////////////////////////////////////////////////
420
421static bool check_output_bitmap(const SkBitmap& bitmap, uint32_t expectedID) {
422    SkASSERT(bitmap.getGenerationID() == expectedID);
423    SkASSERT(bitmap.isImmutable());
424    SkASSERT(bitmap.getPixels());
425    return true;
426}
427
428bool SkImage_Lazy::directGeneratePixels(const SkImageInfo& info, void* pixels, size_t rb,
429                                        int srcX, int srcY,
430                                        SkTransferFunctionBehavior behavior) const {
431    ScopedGenerator generator(fSharedGenerator);
432    const SkImageInfo& genInfo = generator->getInfo();
433    // Currently generators do not natively handle subsets, so check that first.
434    if (srcX || srcY || genInfo.width() != info.width() || genInfo.height() != info.height()) {
435        return false;
436    }
437
438    SkImageGenerator::Options opts;
439    // TODO: This should respect the behavior argument.
440    opts.fBehavior = SkTransferFunctionBehavior::kIgnore;
441    return generator->getPixels(info, pixels, rb, &opts);
442}
443
444//////////////////////////////////////////////////////////////////////////////////////////////////
445
446bool SkImage_Lazy::lockAsBitmapOnlyIfAlreadyCached(SkBitmap* bitmap, CachedFormat format) const {
447    uint32_t uniqueID = this->getUniqueID(format);
448    return SkBitmapCache::Find(SkBitmapCacheDesc::Make(uniqueID,
449                                                       fInfo.width(), fInfo.height()), bitmap) &&
450           check_output_bitmap(*bitmap, uniqueID);
451}
452
453static bool generate_pixels(SkImageGenerator* gen, const SkPixmap& pmap, int originX, int originY,
454                            SkTransferFunctionBehavior behavior) {
455    const int genW = gen->getInfo().width();
456    const int genH = gen->getInfo().height();
457    const SkIRect srcR = SkIRect::MakeWH(genW, genH);
458    const SkIRect dstR = SkIRect::MakeXYWH(originX, originY, pmap.width(), pmap.height());
459    if (!srcR.contains(dstR)) {
460        return false;
461    }
462
463    // If they are requesting a subset, we have to have a temp allocation for full image, and
464    // then copy the subset into their allocation
465    SkBitmap full;
466    SkPixmap fullPM;
467    const SkPixmap* dstPM = &pmap;
468    if (srcR != dstR) {
469        if (!full.tryAllocPixels(pmap.info().makeWH(genW, genH))) {
470            return false;
471        }
472        if (!full.peekPixels(&fullPM)) {
473            return false;
474        }
475        dstPM = &fullPM;
476    }
477
478    SkImageGenerator::Options opts;
479    opts.fBehavior = behavior;
480    if (!gen->getPixels(dstPM->info(), dstPM->writable_addr(), dstPM->rowBytes(), &opts)) {
481        return false;
482    }
483
484    if (srcR != dstR) {
485        if (!full.readPixels(pmap, originX, originY)) {
486            return false;
487        }
488    }
489    return true;
490}
491
492bool SkImage_Lazy::lockAsBitmap(SkBitmap* bitmap, SkImage::CachingHint chint, CachedFormat format,
493                                const SkImageInfo& info,
494                                SkTransferFunctionBehavior behavior) const {
495    if (this->lockAsBitmapOnlyIfAlreadyCached(bitmap, format)) {
496        return true;
497    }
498
499    uint32_t uniqueID = this->getUniqueID(format);
500
501    SkBitmap tmpBitmap;
502    SkBitmapCache::RecPtr cacheRec;
503    SkPixmap pmap;
504    if (SkImage::kAllow_CachingHint == chint) {
505        auto desc = SkBitmapCacheDesc::Make(uniqueID, info.width(), info.height());
506        cacheRec = SkBitmapCache::Alloc(desc, info, &pmap);
507        if (!cacheRec) {
508            return false;
509        }
510    } else {
511        if (!tmpBitmap.tryAllocPixels(info)) {
512            return false;
513        }
514        if (!tmpBitmap.peekPixels(&pmap)) {
515            return false;
516        }
517    }
518
519    ScopedGenerator generator(fSharedGenerator);
520    if (!generate_pixels(generator, pmap, fOrigin.x(), fOrigin.y(), behavior)) {
521        return false;
522    }
523
524    if (cacheRec) {
525        SkBitmapCache::Add(std::move(cacheRec), bitmap);
526        SkASSERT(bitmap->getPixels());  // we're locked
527        SkASSERT(bitmap->isImmutable());
528        SkASSERT(bitmap->getGenerationID() == uniqueID);
529        this->notifyAddedToCache();
530    } else {
531        *bitmap = tmpBitmap;
532        bitmap->pixelRef()->setImmutableWithID(uniqueID);
533    }
534
535    check_output_bitmap(*bitmap, uniqueID);
536    return true;
537}
538
539//////////////////////////////////////////////////////////////////////////////////////////////////
540
541bool SkImage_Lazy::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
542                                int srcX, int srcY, CachingHint chint) const {
543    SkColorSpace* dstColorSpace = dstInfo.colorSpace();
544    SkBitmap bm;
545    if (kDisallow_CachingHint == chint) {
546        CachedFormat cacheFormat = this->chooseCacheFormat(dstColorSpace);
547        SkImageInfo genPixelsInfo = dstInfo;
548        SkTransferFunctionBehavior behavior = getGeneratorBehaviorAndInfo(&genPixelsInfo);
549        if (this->lockAsBitmapOnlyIfAlreadyCached(&bm, cacheFormat)) {
550            return bm.readPixels(dstInfo, dstPixels, dstRB, srcX, srcY);
551        } else {
552            // Try passing the caller's buffer directly down to the generator. If this fails we
553            // may still succeed in the general case, as the generator may prefer some other
554            // config, which we could then convert via SkBitmap::readPixels.
555            if (this->directGeneratePixels(genPixelsInfo, dstPixels, dstRB, srcX, srcY, behavior)) {
556                return true;
557            }
558            // else fall through
559        }
560    }
561
562    if (this->getROPixels(&bm, dstColorSpace, chint)) {
563        return bm.readPixels(dstInfo, dstPixels, dstRB, srcX, srcY);
564    }
565    return false;
566}
567
568SkData* SkImage_Lazy::onRefEncoded() const {
569    ScopedGenerator generator(fSharedGenerator);
570    return generator->refEncodedData();
571}
572
573bool SkImage_Lazy::getROPixels(SkBitmap* bitmap, SkColorSpace* dstColorSpace,
574                               CachingHint chint) const {
575    CachedFormat cacheFormat = this->chooseCacheFormat(dstColorSpace);
576    const SkImageInfo cacheInfo = this->buildCacheInfo(cacheFormat);
577    SkImageInfo genPixelsInfo = cacheInfo;
578    SkTransferFunctionBehavior behavior = getGeneratorBehaviorAndInfo(&genPixelsInfo);
579    return this->lockAsBitmap(bitmap, chint, cacheFormat, genPixelsInfo, behavior);
580}
581
582bool SkImage_Lazy::onIsValid(GrContext* context) const {
583    ScopedGenerator generator(fSharedGenerator);
584    return generator->isValid(context);
585}
586
587bool SkImage_Lazy::onCanLazyGenerateOnGPU() const {
588#if SK_SUPPORT_GPU
589    ScopedGenerator generator(fSharedGenerator);
590    return SkImageGenerator::TexGenType::kNone != generator->onCanGenerateTexture();
591#else
592    return false;
593#endif
594}
595
596SkTransferFunctionBehavior SkImage_Lazy::getGeneratorBehaviorAndInfo(SkImageInfo* generatorImageInfo) const {
597    if (generatorImageInfo->colorSpace()) {
598        return SkTransferFunctionBehavior::kRespect;
599    }
600    // Only specify an output color space if color conversion can be done on the color type.
601    switch (generatorImageInfo->colorType()) {
602        case kRGBA_8888_SkColorType:
603        case kBGRA_8888_SkColorType:
604        case kRGBA_F16_SkColorType:
605        case kRGB_565_SkColorType:
606            *generatorImageInfo = generatorImageInfo->makeColorSpace(fInfo.refColorSpace());
607            break;
608        default:
609            break;
610    }
611    return SkTransferFunctionBehavior::kIgnore;
612}
613
614///////////////////////////////////////////////////////////////////////////////////////////////////
615
616#if SK_SUPPORT_GPU
617sk_sp<GrTextureProxy> SkImage_Lazy::asTextureProxyRef(GrContext* context,
618                                                      const GrSamplerState& params,
619                                                      SkColorSpace* dstColorSpace,
620                                                      sk_sp<SkColorSpace>* texColorSpace,
621                                                      SkScalar scaleAdjust[2]) const {
622    if (!context) {
623        return nullptr;
624    }
625
626    GrImageTextureMaker textureMaker(context, this, kAllow_CachingHint);
627    return textureMaker.refTextureProxyForParams(params, dstColorSpace, texColorSpace, scaleAdjust);
628}
629#endif
630
631sk_sp<SkImage> SkImage_Lazy::onMakeSubset(const SkIRect& subset) const {
632    SkASSERT(fInfo.bounds().contains(subset));
633    SkASSERT(fInfo.bounds() != subset);
634
635    const SkIRect generatorSubset = subset.makeOffset(fOrigin.x(), fOrigin.y());
636    Validator validator(fSharedGenerator, &generatorSubset, fInfo.refColorSpace());
637    return validator ? sk_sp<SkImage>(new SkImage_Lazy(&validator)) : nullptr;
638}
639
640sk_sp<SkImage> SkImage_Lazy::onMakeColorSpace(sk_sp<SkColorSpace> target,
641                                              SkColorType targetColorType,
642                                              SkTransferFunctionBehavior premulBehavior) const {
643    SkAutoExclusive autoAquire(fOnMakeColorSpaceMutex);
644    if (target && fOnMakeColorSpaceTarget &&
645        SkColorSpace::Equals(target.get(), fOnMakeColorSpaceTarget.get())) {
646        return fOnMakeColorSpaceResult;
647    }
648    const SkIRect generatorSubset =
649            SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), fInfo.width(), fInfo.height());
650    Validator validator(fSharedGenerator, &generatorSubset, target);
651    sk_sp<SkImage> result = validator ? sk_sp<SkImage>(new SkImage_Lazy(&validator)) : nullptr;
652    if (result) {
653        fOnMakeColorSpaceTarget = target;
654        fOnMakeColorSpaceResult = result;
655    }
656    return result;
657}
658
659sk_sp<SkImage> SkImage::MakeFromGenerator(std::unique_ptr<SkImageGenerator> generator,
660                                          const SkIRect* subset) {
661    SkImage_Lazy::Validator validator(SharedGenerator::Make(std::move(generator)), subset, nullptr);
662
663    return validator ? sk_make_sp<SkImage_Lazy>(&validator) : nullptr;
664}
665
666//////////////////////////////////////////////////////////////////////////////////////////////////
667
668/**
669 *  Implementation of SkImageCacherator interface, as needed by GrImageTextureMaker
670 */
671
672#if SK_SUPPORT_GPU
673
674void SkImage_Lazy::makeCacheKeyFromOrigKey(const GrUniqueKey& origKey, CachedFormat format,
675                                           GrUniqueKey* cacheKey) {
676    SkASSERT(!cacheKey->isValid());
677    if (origKey.isValid()) {
678        static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
679        GrUniqueKey::Builder builder(cacheKey, origKey, kDomain, 1, "Image");
680        builder[0] = format;
681    }
682}
683
684class Generator_GrYUVProvider : public GrYUVProvider {
685    SkImageGenerator* fGen;
686
687public:
688    Generator_GrYUVProvider(SkImageGenerator* gen) : fGen(gen) {}
689
690    uint32_t onGetID() override { return fGen->uniqueID(); }
691    bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override {
692        return fGen->queryYUV8(sizeInfo, colorSpace);
693    }
694    bool onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override {
695        return fGen->getYUV8Planes(sizeInfo, planes);
696    }
697};
698
699static void set_key_on_proxy(GrProxyProvider* proxyProvider,
700                             GrTextureProxy* proxy, GrTextureProxy* originalProxy,
701                             const GrUniqueKey& key) {
702    if (key.isValid()) {
703        SkASSERT(proxy->origin() == kTopLeft_GrSurfaceOrigin);
704        if (originalProxy && originalProxy->getUniqueKey().isValid()) {
705            SkASSERT(originalProxy->getUniqueKey() == key);
706            SkASSERT(GrMipMapped::kYes == proxy->mipMapped() &&
707                     GrMipMapped::kNo == originalProxy->mipMapped());
708            // If we had an originalProxy with a valid key, that means there already is a proxy in
709            // the cache which matches the key, but it does not have mip levels and we require them.
710            // Thus we must remove the unique key from that proxy.
711            proxyProvider->removeUniqueKeyFromProxy(key, originalProxy);
712        }
713        proxyProvider->assignUniqueKeyToProxy(key, proxy);
714    }
715}
716
717sk_sp<SkColorSpace> SkImage_Lazy::getColorSpace(GrContext* ctx, SkColorSpace* dstColorSpace) {
718    if (!dstColorSpace) {
719        // In legacy mode, we do no modification to the image's color space or encoding.
720        // Subsequent legacy drawing is likely to ignore the color space, but some clients
721        // may want to know what space the image data is in, so return it.
722        return fInfo.refColorSpace();
723    } else {
724        CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps());
725        SkImageInfo cacheInfo = this->buildCacheInfo(format);
726        return cacheInfo.refColorSpace();
727    }
728}
729
730/*
731 *  We have 4 ways to try to return a texture (in sorted order)
732 *
733 *  1. Check the cache for a pre-existing one
734 *  2. Ask the generator to natively create one
735 *  3. Ask the generator to return YUV planes, which the GPU can convert
736 *  4. Ask the generator to return RGB(A) data, which the GPU can convert
737 */
738sk_sp<GrTextureProxy> SkImage_Lazy::lockTextureProxy(GrContext* ctx,
739                                                     const GrUniqueKey& origKey,
740                                                     SkImage::CachingHint chint,
741                                                     bool willBeMipped,
742                                                     SkColorSpace* dstColorSpace,
743                                                     GrTextureMaker::AllowedTexGenType genType) {
744    // Values representing the various texture lock paths we can take. Used for logging the path
745    // taken to a histogram.
746    enum LockTexturePath {
747        kFailure_LockTexturePath,
748        kPreExisting_LockTexturePath,
749        kNative_LockTexturePath,
750        kCompressed_LockTexturePath, // Deprecated
751        kYUV_LockTexturePath,
752        kRGBA_LockTexturePath,
753    };
754
755    enum { kLockTexturePathCount = kRGBA_LockTexturePath + 1 };
756
757    // Determine which cached format we're going to use (which may involve decoding to a different
758    // info than the generator provides).
759    CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps());
760
761    // Fold the cache format into our texture key
762    GrUniqueKey key;
763    this->makeCacheKeyFromOrigKey(origKey, format, &key);
764
765    GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
766    sk_sp<GrTextureProxy> proxy;
767
768    // 1. Check the cache for a pre-existing one
769    if (key.isValid()) {
770        proxy = proxyProvider->findOrCreateProxyByUniqueKey(key, kTopLeft_GrSurfaceOrigin);
771        if (proxy) {
772            SK_HISTOGRAM_ENUMERATION("LockTexturePath", kPreExisting_LockTexturePath,
773                                     kLockTexturePathCount);
774            if (!willBeMipped || GrMipMapped::kYes == proxy->mipMapped()) {
775                return proxy;
776            }
777        }
778    }
779
780    // The CachedFormat is both an index for which cache "slot" we'll use to store this particular
781    // decoded variant of the encoded data, and also a recipe for how to transform the original
782    // info to get the one that we're going to decode to.
783    const SkImageInfo cacheInfo = this->buildCacheInfo(format);
784    SkImageInfo genPixelsInfo = cacheInfo;
785    SkTransferFunctionBehavior behavior = getGeneratorBehaviorAndInfo(&genPixelsInfo);
786
787    // 2. Ask the generator to natively create one
788    if (!proxy) {
789        ScopedGenerator generator(fSharedGenerator);
790        if (GrTextureMaker::AllowedTexGenType::kCheap == genType &&
791                SkImageGenerator::TexGenType::kCheap != generator->onCanGenerateTexture()) {
792            return nullptr;
793        }
794        if ((proxy = generator->generateTexture(ctx, genPixelsInfo, fOrigin, behavior,
795                                                willBeMipped))) {
796            SK_HISTOGRAM_ENUMERATION("LockTexturePath", kNative_LockTexturePath,
797                                     kLockTexturePathCount);
798            set_key_on_proxy(proxyProvider, proxy.get(), nullptr, key);
799            if (!willBeMipped || GrMipMapped::kYes == proxy->mipMapped()) {
800                return proxy;
801            }
802        }
803    }
804
805    // 3. Ask the generator to return YUV planes, which the GPU can convert. If we will be mipping
806    //    the texture we fall through here and have the CPU generate the mip maps for us.
807    if (!proxy && !willBeMipped && !ctx->contextPriv().disableGpuYUVConversion()) {
808        const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(cacheInfo, *ctx->caps());
809        ScopedGenerator generator(fSharedGenerator);
810        Generator_GrYUVProvider provider(generator);
811
812        // The pixels in the texture will be in the generator's color space. If onMakeColorSpace
813        // has been called then this will not match this image's color space. To correct this, apply
814        // a color space conversion from the generator's color space to this image's color space.
815        const SkColorSpace* generatorColorSpace =
816                fSharedGenerator->fGenerator->getInfo().colorSpace();
817        const SkColorSpace* thisColorSpace = fInfo.colorSpace();
818
819        // TODO: Update to create the mipped surface in the YUV generator and draw the base layer
820        // directly into the mipped surface.
821        proxy = provider.refAsTextureProxy(ctx, desc, generatorColorSpace, thisColorSpace);
822        if (proxy) {
823            SK_HISTOGRAM_ENUMERATION("LockTexturePath", kYUV_LockTexturePath,
824                                     kLockTexturePathCount);
825            set_key_on_proxy(proxyProvider, proxy.get(), nullptr, key);
826            return proxy;
827        }
828    }
829
830    // 4. Ask the generator to return RGB(A) data, which the GPU can convert
831    SkBitmap bitmap;
832    if (!proxy && this->lockAsBitmap(&bitmap, chint, format, genPixelsInfo, behavior)) {
833        if (willBeMipped) {
834            proxy = proxyProvider->createMipMapProxyFromBitmap(bitmap, dstColorSpace);
835        }
836        if (!proxy) {
837            proxy = GrUploadBitmapToTextureProxy(proxyProvider, bitmap, dstColorSpace);
838        }
839        if (proxy && (!willBeMipped || GrMipMapped::kYes == proxy->mipMapped())) {
840            SK_HISTOGRAM_ENUMERATION("LockTexturePath", kRGBA_LockTexturePath,
841                                     kLockTexturePathCount);
842            set_key_on_proxy(proxyProvider, proxy.get(), nullptr, key);
843            return proxy;
844        }
845    }
846
847    if (proxy) {
848        // We need a mipped proxy, but we either found a proxy earlier that wasn't mipped, generated
849        // a native non mipped proxy, or generated a non-mipped yuv proxy. Thus we generate a new
850        // mipped surface and copy the original proxy into the base layer. We will then let the gpu
851        // generate the rest of the mips.
852        SkASSERT(willBeMipped);
853        SkASSERT(GrMipMapped::kNo == proxy->mipMapped());
854        if (auto mippedProxy = GrCopyBaseMipMapToTextureProxy(ctx, proxy.get())) {
855            set_key_on_proxy(proxyProvider, mippedProxy.get(), proxy.get(), key);
856            return mippedProxy;
857        }
858        // We failed to make a mipped proxy with the base copied into it. This could have
859        // been from failure to make the proxy or failure to do the copy. Thus we will fall
860        // back to just using the non mipped proxy; See skbug.com/7094.
861        return proxy;
862    }
863
864    SK_HISTOGRAM_ENUMERATION("LockTexturePath", kFailure_LockTexturePath,
865                             kLockTexturePathCount);
866    return nullptr;
867}
868
869///////////////////////////////////////////////////////////////////////////////////////////////////
870
871#endif
872