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 #ifndef SkImageCacherator_DEFINED
9 #define SkImageCacherator_DEFINED
10 
11 #include "SkImageGenerator.h"
12 #include "SkMutex.h"
13 #include "SkTemplates.h"
14 
15 class GrCaps;
16 class GrContext;
17 class GrSamplerParams;
18 class GrTextureProxy;
19 class GrUniqueKey;
20 class SkBitmap;
21 class SkImage;
22 
23 /*
24  *  Internal class to manage caching the output of an ImageGenerator.
25  */
26 class SkImageCacherator {
27 public:
28     static SkImageCacherator* NewFromGenerator(std::unique_ptr<SkImageGenerator>,
29                                                const SkIRect* subset = nullptr);
30 
31     ~SkImageCacherator();
32 
info()33     const SkImageInfo& info() const { return fInfo; }
uniqueID()34     uint32_t uniqueID() const { return fUniqueIDs[kLegacy_CachedFormat]; }
35 
36     enum CachedFormat {
37         kLegacy_CachedFormat,    // The format from the generator, with any color space stripped out
38         kAsIs_CachedFormat,      // The format from the generator, with no modification
39         kLinearF16_CachedFormat, // Half float RGBA with linear gamma
40         kSRGB8888_CachedFormat,  // sRGB bytes
41 
42         kNumCachedFormats,
43     };
44 
45     /**
46      *  On success (true), bitmap will point to the pixels for this generator. If this returns
47      *  false, the bitmap will be reset to empty.
48      *
49      *  If not NULL, the client will be notified (->notifyAddedToCache()) when resources are
50      *  added to the cache on its behalf.
51      */
52     bool lockAsBitmap(GrContext*, SkBitmap*, const SkImage* client, SkColorSpace* dstColorSpace,
53                       SkImage::CachingHint = SkImage::kAllow_CachingHint);
54 
55 #if SK_SUPPORT_GPU
56     /**
57      *  Returns a ref() on the texture produced by this generator. The caller must call unref()
58      *  when it is done. Will return nullptr on failure.
59      *
60      *  If not NULL, the client will be notified (->notifyAddedToCache()) when resources are
61      *  added to the cache on its behalf.
62      *
63      *  The caller is responsible for calling proxy->unref() when they are done.
64      *
65      *  The scaleAdjust in/out parameter will return any scale adjustment that needs
66      *  to be applied to the absolute texture coordinates in the case where the image
67      *  was resized to meet the sampling requirements (e.g., resized out to the next power of 2).
68      *  It can be null if the caller knows resizing will not be required.
69      */
70     sk_sp<GrTextureProxy> lockAsTextureProxy(GrContext*, const GrSamplerParams&,
71                                              SkColorSpace* dstColorSpace,
72                                              sk_sp<SkColorSpace>* texColorSpace,
73                                              const SkImage* client,
74                                              SkScalar scaleAdjust[2],
75                                              SkImage::CachingHint = SkImage::kAllow_CachingHint);
76 #endif
77 
78     /**
79      *  If the underlying src naturally is represented by an encoded blob (in SkData), this returns
80      *  a ref to that data. If not, it returns null.
81      *
82      *  If a GrContext is specified, then the caller is only interested in gpu-specific encoded
83      *  formats, so others (e.g. PNG) can just return nullptr.
84      */
85     SkData* refEncoded(GrContext*);
86 
87     // Only return true if the generate has already been cached.
88     bool lockAsBitmapOnlyIfAlreadyCached(SkBitmap*, CachedFormat);
89     // Call the underlying generator directly
90     bool directGeneratePixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
91                               int srcX, int srcY);
92 
93 private:
94     // Ref-counted tuple(SkImageGenerator, SkMutex) which allows sharing of one generator
95     // among several cacherators.
96     class SharedGenerator final : public SkNVRefCnt<SharedGenerator> {
97     public:
Make(std::unique_ptr<SkImageGenerator> gen)98         static sk_sp<SharedGenerator> Make(std::unique_ptr<SkImageGenerator> gen) {
99             return gen ? sk_sp<SharedGenerator>(new SharedGenerator(std::move(gen))) : nullptr;
100         }
101 
102     private:
SharedGenerator(std::unique_ptr<SkImageGenerator> gen)103         explicit SharedGenerator(std::unique_ptr<SkImageGenerator> gen)
104             : fGenerator(std::move(gen))
105         {
106             SkASSERT(fGenerator);
107         }
108 
109         friend class ScopedGenerator;
110         friend class SkImageCacherator;
111 
112         std::unique_ptr<SkImageGenerator> fGenerator;
113         SkMutex                           fMutex;
114     };
115     class ScopedGenerator;
116 
117     struct Validator {
118         Validator(sk_sp<SharedGenerator>, const SkIRect* subset);
119 
120         operator bool() const { return fSharedGenerator.get(); }
121 
122         sk_sp<SharedGenerator> fSharedGenerator;
123         SkImageInfo            fInfo;
124         SkIPoint               fOrigin;
125         uint32_t               fUniqueID;
126     };
127 
128     SkImageCacherator(Validator*);
129 
130     CachedFormat chooseCacheFormat(SkColorSpace* dstColorSpace, const GrCaps* = nullptr);
131     SkImageInfo buildCacheInfo(CachedFormat);
132 
133     bool generateBitmap(SkBitmap*, const SkImageInfo&);
134     bool tryLockAsBitmap(SkBitmap*, const SkImage*, SkImage::CachingHint, CachedFormat,
135                          const SkImageInfo&);
136 #if SK_SUPPORT_GPU
137     // Returns the texture proxy. If the cacherator is generating the texture and wants to cache it,
138     // it should use the passed in key (if the key is valid).
139     sk_sp<GrTextureProxy> lockTextureProxy(GrContext*,
140                                            const GrUniqueKey& key,
141                                            const SkImage* client,
142                                            SkImage::CachingHint,
143                                            bool willBeMipped,
144                                            SkColorSpace* dstColorSpace);
145     // Returns the color space of the texture that would be returned if you called lockTexture.
146     // Separate code path to allow querying of the color space for textures that cached (even
147     // externally).
148     sk_sp<SkColorSpace> getColorSpace(GrContext*, SkColorSpace* dstColorSpace);
149     void makeCacheKeyFromOrigKey(const GrUniqueKey& origKey, CachedFormat, GrUniqueKey* cacheKey);
150 #endif
151 
152     sk_sp<SharedGenerator> fSharedGenerator;
153     const SkImageInfo      fInfo;
154     const SkIPoint         fOrigin;
155     uint32_t               fUniqueIDs[kNumCachedFormats];
156 
157     friend class GrImageTextureMaker;
158     friend class SkImage;
159     friend class SkImage_Generator;
160 };
161 
162 #endif
163