• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/image/SkImage_Lazy.h"
9 
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkData.h"
13 #include "include/core/SkImageGenerator.h"
14 #include "include/core/SkPixmap.h"
15 #include "include/core/SkSize.h"
16 #include "include/core/SkYUVAInfo.h"
17 #include "src/core/SkBitmapCache.h"
18 #include "src/core/SkCachedData.h"
19 #include "src/core/SkNextID.h"
20 #include "src/core/SkResourceCache.h"
21 #include "src/core/SkYUVPlanesCache.h"
22 
23 #include <utility>
24 
25 enum SkColorType : int;
26 
Make(std::unique_ptr<SkImageGenerator> gen)27 sk_sp<SharedGenerator> SharedGenerator::Make(std::unique_ptr<SkImageGenerator> gen) {
28     return gen ? sk_sp<SharedGenerator>(new SharedGenerator(std::move(gen))) : nullptr;
29 }
30 
SharedGenerator(std::unique_ptr<SkImageGenerator> gen)31 SharedGenerator::SharedGenerator(std::unique_ptr<SkImageGenerator> gen)
32         : fGenerator(std::move(gen)) {
33     SkASSERT(fGenerator);
34 }
35 
getInfo() const36 const SkImageInfo& SharedGenerator::getInfo() const { return fGenerator->getInfo(); }
37 
isTextureGenerator()38 bool SharedGenerator::isTextureGenerator() { return fGenerator->isTextureGenerator(); }
39 
40 ///////////////////////////////////////////////////////////////////////////////
41 
Validator(sk_sp<SharedGenerator> gen,const SkColorType * colorType,sk_sp<SkColorSpace> colorSpace)42 SkImage_Lazy::Validator::Validator(sk_sp<SharedGenerator> gen, const SkColorType* colorType,
43                                    sk_sp<SkColorSpace> colorSpace)
44         : fSharedGenerator(std::move(gen)) {
45     if (!fSharedGenerator) {
46         return;
47     }
48 
49     // The following generator accessors are safe without acquiring the mutex (const getters).
50     // TODO: refactor to use a ScopedGenerator instead, for clarity.
51     fInfo = fSharedGenerator->fGenerator->getInfo();
52     if (fInfo.isEmpty()) {
53         fSharedGenerator.reset();
54         return;
55     }
56 
57     fUniqueID = fSharedGenerator->fGenerator->uniqueID();
58 
59     if (colorType && (*colorType == fInfo.colorType())) {
60         colorType = nullptr;
61     }
62 
63     if (colorType || colorSpace) {
64         if (colorType) {
65             fInfo = fInfo.makeColorType(*colorType);
66         }
67         if (colorSpace) {
68             fInfo = fInfo.makeColorSpace(colorSpace);
69         }
70         fUniqueID = SkNextID::ImageID();
71     }
72 }
73 
74 ///////////////////////////////////////////////////////////////////////////////
75 
76 // Helper for exclusive access to a shared generator.
77 class SkImage_Lazy::ScopedGenerator {
78 public:
ScopedGenerator(const sk_sp<SharedGenerator> & gen)79     ScopedGenerator(const sk_sp<SharedGenerator>& gen)
80       : fSharedGenerator(gen)
81       , fAutoAcquire(gen->fMutex) {}
82 
operator ->() const83     SkImageGenerator* operator->() const {
84         fSharedGenerator->fMutex.assertHeld();
85         return fSharedGenerator->fGenerator.get();
86     }
87 
operator SkImageGenerator*() const88     operator SkImageGenerator*() const {
89         fSharedGenerator->fMutex.assertHeld();
90         return fSharedGenerator->fGenerator.get();
91     }
92 
93 private:
94     const sk_sp<SharedGenerator>& fSharedGenerator;
95     SkAutoMutexExclusive          fAutoAcquire;
96 };
97 
98 ///////////////////////////////////////////////////////////////////////////////
99 
SkImage_Lazy(Validator * validator)100 SkImage_Lazy::SkImage_Lazy(Validator* validator)
101     : SkImage_Base(validator->fInfo, validator->fUniqueID)
102     , fSharedGenerator(std::move(validator->fSharedGenerator))
103 {
104     SkASSERT(fSharedGenerator);
105 }
106 
getROPixels(GrDirectContext * ctx,SkBitmap * bitmap,SkImage::CachingHint chint) const107 bool SkImage_Lazy::getROPixels(GrDirectContext* ctx, SkBitmap* bitmap,
108                                SkImage::CachingHint chint) const {
109     auto check_output_bitmap = [bitmap]() {
110         SkASSERT(bitmap->isImmutable());
111         SkASSERT(bitmap->getPixels());
112         (void)bitmap;
113     };
114 
115     auto desc = SkBitmapCacheDesc::Make(this);
116     if (SkBitmapCache::Find(desc, bitmap)) {
117         check_output_bitmap();
118         return true;
119     }
120 
121     if (SkImage::kAllow_CachingHint == chint) {
122         SkPixmap pmap;
123         SkBitmapCache::RecPtr cacheRec = SkBitmapCache::Alloc(desc, this->imageInfo(), &pmap);
124         if (!cacheRec) {
125             return false;
126         }
127         bool success = false;
128         {   // make sure ScopedGenerator goes out of scope before we try readPixelsProxy
129             success = ScopedGenerator(fSharedGenerator)->getPixels(pmap);
130         }
131         if (!success && !this->readPixelsProxy(ctx, pmap)) {
132             return false;
133         }
134         SkBitmapCache::Add(std::move(cacheRec), bitmap);
135         this->notifyAddedToRasterCache();
136     } else {
137         if (!bitmap->tryAllocPixels(this->imageInfo())) {
138             return false;
139         }
140         bool success = false;
141         {   // make sure ScopedGenerator goes out of scope before we try readPixelsProxy
142             success = ScopedGenerator(fSharedGenerator)->getPixels(bitmap->pixmap());
143         }
144         if (!success && !this->readPixelsProxy(ctx, bitmap->pixmap())) {
145             return false;
146         }
147         bitmap->setImmutable();
148     }
149     check_output_bitmap();
150     return true;
151 }
152 
generator() const153 sk_sp<SharedGenerator> SkImage_Lazy::generator() const {
154     return fSharedGenerator;
155 }
156 
onIsProtected() const157 bool SkImage_Lazy::onIsProtected() const {
158     ScopedGenerator generator(fSharedGenerator);
159     return generator->isProtected();
160 }
161 
onReadPixels(GrDirectContext * dContext,const SkImageInfo & dstInfo,void * dstPixels,size_t dstRB,int srcX,int srcY,CachingHint chint) const162 bool SkImage_Lazy::onReadPixels(GrDirectContext* dContext,
163                                 const SkImageInfo& dstInfo,
164                                 void* dstPixels,
165                                 size_t dstRB,
166                                 int srcX,
167                                 int srcY,
168                                 CachingHint chint) const {
169     SkBitmap bm;
170     if (this->getROPixels(dContext, &bm, chint)) {
171         return bm.readPixels(dstInfo, dstPixels, dstRB, srcX, srcY);
172     }
173     return false;
174 }
175 
onRefEncoded() const176 sk_sp<SkData> SkImage_Lazy::onRefEncoded() const {
177     // check that we aren't a subset or colortype/etc modification of the original
178     if (fSharedGenerator->fGenerator->uniqueID() == this->uniqueID()) {
179         ScopedGenerator generator(fSharedGenerator);
180         return generator->refEncodedData();
181     }
182     return nullptr;
183 }
184 
isValid(GrRecordingContext * context) const185 bool SkImage_Lazy::isValid(GrRecordingContext* context) const {
186     ScopedGenerator generator(fSharedGenerator);
187     return generator->isValid(context);
188 }
189 
190 
onMakeSubset(GrDirectContext *,const SkIRect & subset) const191 sk_sp<SkImage> SkImage_Lazy::onMakeSubset(GrDirectContext*, const SkIRect& subset) const {
192     // neither picture-backed nor codec-backed lazy images need the context to do readbacks.
193     // The subclass for cross-context images *does* use the direct context.
194     auto pixels = this->makeRasterImage(nullptr);
195     return pixels ? pixels->makeSubset(nullptr, subset) : nullptr;
196 }
197 
onMakeSubset(skgpu::graphite::Recorder *,const SkIRect & subset,RequiredProperties props) const198 sk_sp<SkImage> SkImage_Lazy::onMakeSubset(skgpu::graphite::Recorder*,
199                                           const SkIRect& subset,
200                                           RequiredProperties props) const {
201     // TODO: can we do this more efficiently, by telling the generator we want to
202     //       "realize" a subset?
203     sk_sp<SkImage> nonLazyImg = this->makeRasterImage(nullptr);
204     if (!nonLazyImg) {
205         return nullptr;
206     }
207     return nonLazyImg->makeSubset(nullptr, subset, props);
208 }
209 
onMakeColorTypeAndColorSpace(SkColorType targetCT,sk_sp<SkColorSpace> targetCS,GrDirectContext *) const210 sk_sp<SkImage> SkImage_Lazy::onMakeColorTypeAndColorSpace(SkColorType targetCT,
211                                                           sk_sp<SkColorSpace> targetCS,
212                                                           GrDirectContext*) const {
213     SkAutoMutexExclusive autoAquire(fOnMakeColorTypeAndSpaceMutex);
214     if (fOnMakeColorTypeAndSpaceResult &&
215         targetCT == fOnMakeColorTypeAndSpaceResult->colorType() &&
216         SkColorSpace::Equals(targetCS.get(), fOnMakeColorTypeAndSpaceResult->colorSpace())) {
217         return fOnMakeColorTypeAndSpaceResult;
218     }
219     Validator validator(fSharedGenerator, &targetCT, targetCS);
220     sk_sp<SkImage> result = validator ? sk_sp<SkImage>(new SkImage_Lazy(&validator)) : nullptr;
221     if (result) {
222         fOnMakeColorTypeAndSpaceResult = result;
223     }
224     return result;
225 }
226 
onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const227 sk_sp<SkImage> SkImage_Lazy::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
228     // TODO: The correct thing is to clone the generator, and modify its color space. That's hard,
229     // because we don't have a clone method, and generator is public (and derived-from by clients).
230     // So do the simple/inefficient thing here, and fallback to raster when this is called.
231 
232     // We allocate the bitmap with the new color space, then generate the image using the original.
233     SkBitmap bitmap;
234     if (bitmap.tryAllocPixels(this->imageInfo().makeColorSpace(std::move(newCS)))) {
235         SkPixmap pixmap = bitmap.pixmap();
236         pixmap.setColorSpace(this->refColorSpace());
237         if (ScopedGenerator(fSharedGenerator)->getPixels(pixmap)) {
238             bitmap.setImmutable();
239             return bitmap.asImage();
240         }
241     }
242     return nullptr;
243 }
244 
getPlanes(const SkYUVAPixmapInfo::SupportedDataTypes & supportedDataTypes,SkYUVAPixmaps * yuvaPixmaps) const245 sk_sp<SkCachedData> SkImage_Lazy::getPlanes(
246         const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes,
247         SkYUVAPixmaps* yuvaPixmaps) const {
248     ScopedGenerator generator(fSharedGenerator);
249 
250     sk_sp<SkCachedData> data(SkYUVPlanesCache::FindAndRef(generator->uniqueID(), yuvaPixmaps));
251 
252     if (data) {
253         SkASSERT(yuvaPixmaps->isValid());
254         SkASSERT(yuvaPixmaps->yuvaInfo().dimensions() == this->dimensions());
255         return data;
256     }
257     SkYUVAPixmapInfo yuvaPixmapInfo;
258     if (!generator->queryYUVAInfo(supportedDataTypes, &yuvaPixmapInfo) ||
259         yuvaPixmapInfo.yuvaInfo().dimensions() != this->dimensions()) {
260         return nullptr;
261     }
262     data.reset(SkResourceCache::NewCachedData(yuvaPixmapInfo.computeTotalBytes()));
263     SkYUVAPixmaps tempPixmaps = SkYUVAPixmaps::FromExternalMemory(yuvaPixmapInfo,
264                                                                   data->writable_data());
265     SkASSERT(tempPixmaps.isValid());
266     if (!generator->getYUVAPlanes(tempPixmaps)) {
267         return nullptr;
268     }
269     // Decoding is done, cache the resulting YUV planes
270     *yuvaPixmaps = tempPixmaps;
271     SkYUVPlanesCache::Add(this->uniqueID(), data.get(), *yuvaPixmaps);
272     return data;
273 }
274 
addUniqueIDListener(sk_sp<SkIDChangeListener> listener) const275 void SkImage_Lazy::addUniqueIDListener(sk_sp<SkIDChangeListener> listener) const {
276     fUniqueIDListeners.add(std::move(listener));
277 }
278 
279 // TODO(kjlubick) move SharedGenerate to SkImage_Lazy.h and this to SkImage_LazyFactories
280 namespace SkImages {
281 
DeferredFromGenerator(std::unique_ptr<SkImageGenerator> generator)282 sk_sp<SkImage> DeferredFromGenerator(std::unique_ptr<SkImageGenerator> generator) {
283     SkImage_Lazy::Validator validator(
284             SharedGenerator::Make(std::move(generator)), nullptr, nullptr);
285 
286     return validator ? sk_make_sp<SkImage_Lazy>(&validator) : nullptr;
287 }
288 
289 }  // namespace SkImages
290