• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 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 "include/core/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkData.h"
11 #include "include/core/SkPixelRef.h"
12 #include "include/core/SkSurface.h"
13 #include "include/private/SkImageInfoPriv.h"
14 #include "src/codec/SkColorTable.h"
15 #include "src/core/SkCompressedDataUtils.h"
16 #include "src/core/SkConvertPixels.h"
17 #include "src/core/SkImagePriv.h"
18 #include "src/core/SkTLazy.h"
19 #include "src/image/SkImage_Base.h"
20 #include "src/shaders/SkBitmapProcShader.h"
21 
22 #if SK_SUPPORT_GPU
23 #include "include/gpu/GrDirectContext.h"
24 #include "src/gpu/GrRecordingContextPriv.h"
25 #include "src/gpu/SkGr.h"
26 #include "src/gpu/effects/GrBicubicEffect.h"
27 #include "src/gpu/effects/GrTextureEffect.h"
28 #endif
29 
30 // fixes https://bug.skia.org/5096
is_not_subset(const SkBitmap & bm)31 static bool is_not_subset(const SkBitmap& bm) {
32     SkASSERT(bm.pixelRef());
33     SkISize dim = SkISize::Make(bm.pixelRef()->width(), bm.pixelRef()->height());
34     SkASSERT(dim != bm.dimensions() || bm.pixelRefOrigin().isZero());
35     return dim == bm.dimensions();
36 }
37 
38 class SkImage_Raster : public SkImage_Base {
39 public:
ValidArgs(const SkImageInfo & info,size_t rowBytes,size_t * minSize)40     static bool ValidArgs(const SkImageInfo& info, size_t rowBytes, size_t* minSize) {
41         const int maxDimension = SK_MaxS32 >> 2;
42 
43         // TODO(mtklein): eliminate anything here that setInfo() has already checked.
44         SkBitmap b;
45         if (!b.setInfo(info, rowBytes)) {
46             return false;
47         }
48 
49         if (info.width() <= 0 || info.height() <= 0) {
50             return false;
51         }
52         if (info.width() > maxDimension || info.height() > maxDimension) {
53             return false;
54         }
55         if ((unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType) {
56             return false;
57         }
58         if ((unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType) {
59             return false;
60         }
61 
62         if (kUnknown_SkColorType == info.colorType()) {
63             return false;
64         }
65         if (!info.validRowBytes(rowBytes)) {
66             return false;
67         }
68 
69         size_t size = info.computeByteSize(rowBytes);
70         if (SkImageInfo::ByteSizeOverflowed(size)) {
71             return false;
72         }
73 
74         if (minSize) {
75             *minSize = size;
76         }
77         return true;
78     }
79 
80     SkImage_Raster(const SkImageInfo&, sk_sp<SkData>, size_t rb,
81                    uint32_t id = kNeedNewImageUniqueID);
82     ~SkImage_Raster() override;
83 
84     bool onReadPixels(GrDirectContext*, const SkImageInfo&, void*, size_t, int srcX, int srcY,
85                       CachingHint) const override;
86     bool onPeekPixels(SkPixmap*) const override;
onPeekBitmap() const87     const SkBitmap* onPeekBitmap() const override { return &fBitmap; }
88 
89     bool getROPixels(GrDirectContext*, SkBitmap*, CachingHint) const override;
90     sk_sp<SkImage> onMakeSubset(const SkIRect&, GrDirectContext*) const override;
91 
getPixelRef() const92     SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
93 
94     bool onAsLegacyBitmap(GrDirectContext*, SkBitmap*) const override;
95 
SkImage_Raster(const SkBitmap & bm,bool bitmapMayBeMutable=false)96     SkImage_Raster(const SkBitmap& bm, bool bitmapMayBeMutable = false)
97             : INHERITED(bm.info(),
98                         is_not_subset(bm) ? bm.getGenerationID() : (uint32_t)kNeedNewImageUniqueID)
99             , fBitmap(bm) {
100         SkASSERT(bitmapMayBeMutable || fBitmap.isImmutable());
101     }
102 
103     sk_sp<SkImage> onMakeColorTypeAndColorSpace(SkColorType, sk_sp<SkColorSpace>,
104                                                 GrDirectContext*) const override;
105 
106     sk_sp<SkImage> onReinterpretColorSpace(sk_sp<SkColorSpace>) const override;
107 
onIsValid(GrRecordingContext * context) const108     bool onIsValid(GrRecordingContext* context) const override { return true; }
notifyAddedToRasterCache() const109     void notifyAddedToRasterCache() const override {
110         // We explicitly DON'T want to call INHERITED::notifyAddedToRasterCache. That ties the
111         // lifetime of derived/cached resources to the image. In this case, we only want cached
112         // data (eg mips) tied to the lifetime of the underlying pixelRef.
113         SkASSERT(fBitmap.pixelRef());
114         fBitmap.pixelRef()->notifyAddedToCache();
115     }
116 
117 #if SK_SUPPORT_GPU
118     bool onPinAsTexture(GrRecordingContext*) const override;
119     void onUnpinAsTexture(GrRecordingContext*) const override;
120     bool isPinnedOnContext(GrRecordingContext*) const override;
121 #endif
122 
onHasMipmaps() const123     bool onHasMipmaps() const override { return SkToBool(fBitmap.fMips); }
124 
onPeekMips() const125     SkMipmap* onPeekMips() const override { return fBitmap.fMips.get(); }
126 
onMakeWithMipmaps(sk_sp<SkMipmap> mips) const127     sk_sp<SkImage> onMakeWithMipmaps(sk_sp<SkMipmap> mips) const override {
128         auto img = new SkImage_Raster(fBitmap);
129         if (mips) {
130             img->fBitmap.fMips = std::move(mips);
131         } else {
132             img->fBitmap.fMips.reset(SkMipmap::Build(fBitmap.pixmap(), nullptr));
133         }
134         return sk_sp<SkImage>(img);
135     }
136 
137 private:
138 #if SK_SUPPORT_GPU
139     std::tuple<GrSurfaceProxyView, GrColorType> onAsView(GrRecordingContext*,
140                                                          GrMipmapped,
141                                                          GrImageTexGenPolicy) const override;
142 
143     std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(GrRecordingContext*,
144                                                                SkSamplingOptions,
145                                                                const SkTileMode[2],
146                                                                const SkMatrix&,
147                                                                const SkRect*,
148                                                                const SkRect*) const override;
149 #endif
150 
151     SkBitmap fBitmap;
152 
153 #if SK_SUPPORT_GPU
154     mutable GrSurfaceProxyView fPinnedView;
155     mutable int32_t fPinnedCount = 0;
156     mutable uint32_t fPinnedUniqueID = SK_InvalidUniqueID;
157     mutable uint32_t fPinnedContextID = SK_InvalidUniqueID;
158     mutable GrColorType fPinnedColorType = GrColorType::kUnknown;
159 #endif
160 
161     using INHERITED = SkImage_Base;
162 };
163 
164 ///////////////////////////////////////////////////////////////////////////////
165 
release_data(void * addr,void * context)166 static void release_data(void* addr, void* context) {
167     SkData* data = static_cast<SkData*>(context);
168     data->unref();
169 }
170 
SkImage_Raster(const SkImageInfo & info,sk_sp<SkData> data,size_t rowBytes,uint32_t id)171 SkImage_Raster::SkImage_Raster(const SkImageInfo& info, sk_sp<SkData> data, size_t rowBytes,
172                                uint32_t id)
173         : INHERITED(info, id) {
174     void* addr = const_cast<void*>(data->data());
175 
176     fBitmap.installPixels(info, addr, rowBytes, release_data, data.release());
177     fBitmap.setImmutable();
178 }
179 
~SkImage_Raster()180 SkImage_Raster::~SkImage_Raster() {
181 #if SK_SUPPORT_GPU
182     if (fPinnedView) {
183         GrDirectContext* context = nullptr;
184         auto proxy = fPinnedView.refProxy();
185         do {
186             if (!proxy) {
187                 break;
188             }
189             if (!proxy->peekSurface()) {
190                 break;
191             }
192             context = proxy->peekSurface()->getContext();
193             if (context) {
194                 context->collectResource(proxy);
195                 return;
196             }
197         } while (false);
198     }
199     SkASSERT(!fPinnedView);  // want the caller to have manually unpinned
200 #endif
201 }
202 
onReadPixels(GrDirectContext *,const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint) const203 bool SkImage_Raster::onReadPixels(GrDirectContext*,
204                                   const SkImageInfo& dstInfo,
205                                   void* dstPixels,
206                                   size_t dstRowBytes,
207                                   int srcX,
208                                   int srcY,
209                                   CachingHint) const {
210     SkBitmap shallowCopy(fBitmap);
211     return shallowCopy.readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
212 }
213 
onPeekPixels(SkPixmap * pm) const214 bool SkImage_Raster::onPeekPixels(SkPixmap* pm) const {
215     return fBitmap.peekPixels(pm);
216 }
217 
getROPixels(GrDirectContext *,SkBitmap * dst,CachingHint) const218 bool SkImage_Raster::getROPixels(GrDirectContext*, SkBitmap* dst, CachingHint) const {
219     *dst = fBitmap;
220     return true;
221 }
222 
223 #if SK_SUPPORT_GPU
onPinAsTexture(GrRecordingContext * rContext) const224 bool SkImage_Raster::onPinAsTexture(GrRecordingContext* rContext) const {
225     if (fPinnedView) {
226         SkASSERT(fPinnedCount > 0);
227         SkASSERT(fPinnedUniqueID != 0);
228         if (rContext->priv().contextID() != fPinnedContextID) {
229             return false;
230         }
231     } else {
232         SkASSERT(fPinnedCount == 0);
233         SkASSERT(fPinnedUniqueID == 0);
234         std::tie(fPinnedView, fPinnedColorType) = GrMakeCachedBitmapProxyView(rContext,
235                                                                               fBitmap,
236                                                                               GrMipmapped::kNo);
237         if (!fPinnedView) {
238             fPinnedColorType = GrColorType::kUnknown;
239             return false;
240         }
241         fPinnedUniqueID = fBitmap.getGenerationID();
242         fPinnedContextID = rContext->priv().contextID();
243     }
244     // Note: we only increment if the texture was successfully pinned
245     ++fPinnedCount;
246     return true;
247 }
248 
onUnpinAsTexture(GrRecordingContext * rContext) const249 void SkImage_Raster::onUnpinAsTexture(GrRecordingContext* rContext) const {
250     // Note: we always decrement, even if fPinnedTexture is null
251     SkASSERT(fPinnedCount > 0);
252     SkASSERT(fPinnedUniqueID != 0);
253 #if 0 // This would be better but Android currently calls with an already freed context ptr.
254     if (rContext->priv().contextID() != fPinnedContextID) {
255         return;
256     }
257 #endif
258 
259     if (0 == --fPinnedCount) {
260         fPinnedView = GrSurfaceProxyView();
261         fPinnedUniqueID = SK_InvalidUniqueID;
262         fPinnedContextID = SK_InvalidUniqueID;
263         fPinnedColorType = GrColorType::kUnknown;
264     }
265 }
266 
isPinnedOnContext(GrRecordingContext * rContext) const267 bool SkImage_Raster::isPinnedOnContext(GrRecordingContext* rContext) const {
268     return fPinnedContextID == rContext->priv().contextID();
269 }
270 #endif
271 
onMakeSubset(const SkIRect & subset,GrDirectContext *) const272 sk_sp<SkImage> SkImage_Raster::onMakeSubset(const SkIRect& subset, GrDirectContext*) const {
273     SkImageInfo info = fBitmap.info().makeDimensions(subset.size());
274     SkBitmap bitmap;
275     if (!bitmap.tryAllocPixels(info)) {
276         return nullptr;
277     }
278 
279     void* dst = bitmap.getPixels();
280     void* src = fBitmap.getAddr(subset.x(), subset.y());
281     if (!dst || !src) {
282         SkDEBUGFAIL("SkImage_Raster::onMakeSubset with nullptr src or dst");
283         return nullptr;
284     }
285 
286     SkRectMemcpy(dst, bitmap.rowBytes(), src, fBitmap.rowBytes(), bitmap.rowBytes(),
287                  subset.height());
288 
289     bitmap.setImmutable();
290     return bitmap.asImage();
291 }
292 
293 ///////////////////////////////////////////////////////////////////////////////
294 
MakeRasterCopyPriv(const SkPixmap & pmap,uint32_t id)295 sk_sp<SkImage> MakeRasterCopyPriv(const SkPixmap& pmap, uint32_t id) {
296     size_t size;
297     if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
298         return nullptr;
299     }
300 
301     // Here we actually make a copy of the caller's pixel data
302     sk_sp<SkData> data(SkData::MakeWithCopy(pmap.addr(), size));
303     return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes(), id);
304 }
305 
MakeRasterCopy(const SkPixmap & pmap)306 sk_sp<SkImage> SkImage::MakeRasterCopy(const SkPixmap& pmap) {
307     return MakeRasterCopyPriv(pmap, kNeedNewImageUniqueID);
308 }
309 
MakeRasterData(const SkImageInfo & info,sk_sp<SkData> data,size_t rowBytes)310 sk_sp<SkImage> SkImage::MakeRasterData(const SkImageInfo& info, sk_sp<SkData> data,
311                                        size_t rowBytes) {
312     size_t size;
313     if (!SkImage_Raster::ValidArgs(info, rowBytes, &size) || !data) {
314         return nullptr;
315     }
316 
317     // did they give us enough data?
318     if (data->size() < size) {
319         return nullptr;
320     }
321 
322     return sk_make_sp<SkImage_Raster>(info, std::move(data), rowBytes);
323 }
324 
325 // TODO: this could be improved to decode and make use of the mipmap
326 // levels potentially present in the compressed data. For now, any
327 // mipmap levels are discarded.
MakeRasterFromCompressed(sk_sp<SkData> data,int width,int height,CompressionType type)328 sk_sp<SkImage> SkImage::MakeRasterFromCompressed(sk_sp<SkData> data,
329                                                  int width, int height,
330                                                  CompressionType type) {
331     size_t expectedSize = SkCompressedFormatDataSize(type, { width, height }, false);
332     if (!data || data->size() < expectedSize) {
333         return nullptr;
334     }
335 
336     SkAlphaType at = SkCompressionTypeIsOpaque(type) ? kOpaque_SkAlphaType
337                                                      : kPremul_SkAlphaType;
338 
339     SkImageInfo ii = SkImageInfo::MakeN32(width, height, at);
340 
341     if (!SkImage_Raster::ValidArgs(ii, ii.minRowBytes(), nullptr)) {
342         return nullptr;
343     }
344 
345     SkBitmap bitmap;
346     if (!bitmap.tryAllocPixels(ii)) {
347         return nullptr;
348     }
349 
350     if (!SkDecompress(std::move(data), { width, height }, type, &bitmap)) {
351         return nullptr;
352     }
353 
354     bitmap.setImmutable();
355     return MakeFromBitmap(bitmap);
356 }
357 
MakeFromRaster(const SkPixmap & pmap,RasterReleaseProc proc,ReleaseContext ctx)358 sk_sp<SkImage> SkImage::MakeFromRaster(const SkPixmap& pmap, RasterReleaseProc proc,
359                                        ReleaseContext ctx) {
360     size_t size;
361     if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
362         return nullptr;
363     }
364 
365     sk_sp<SkData> data(SkData::MakeWithProc(pmap.addr(), size, proc, ctx));
366     return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes());
367 }
368 
SkMakeImageFromRasterBitmapPriv(const SkBitmap & bm,SkCopyPixelsMode cpm,uint32_t idForCopy)369 sk_sp<SkImage> SkMakeImageFromRasterBitmapPriv(const SkBitmap& bm, SkCopyPixelsMode cpm,
370                                                uint32_t idForCopy) {
371     if (kAlways_SkCopyPixelsMode == cpm || (!bm.isImmutable() && kNever_SkCopyPixelsMode != cpm)) {
372         SkPixmap pmap;
373         if (bm.peekPixels(&pmap)) {
374             return MakeRasterCopyPriv(pmap, idForCopy);
375         } else {
376             return sk_sp<SkImage>();
377         }
378     }
379 
380     return sk_make_sp<SkImage_Raster>(bm, kNever_SkCopyPixelsMode == cpm);
381 }
382 
SkMakeImageFromRasterBitmap(const SkBitmap & bm,SkCopyPixelsMode cpm)383 sk_sp<SkImage> SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode cpm) {
384     if (!SkImageInfoIsValid(bm.info()) || bm.rowBytes() < bm.info().minRowBytes()) {
385         return nullptr;
386     }
387 
388     return SkMakeImageFromRasterBitmapPriv(bm, cpm, kNeedNewImageUniqueID);
389 }
390 
SkBitmapImageGetPixelRef(const SkImage * image)391 const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
392     return ((const SkImage_Raster*)image)->getPixelRef();
393 }
394 
onAsLegacyBitmap(GrDirectContext *,SkBitmap * bitmap) const395 bool SkImage_Raster::onAsLegacyBitmap(GrDirectContext*, SkBitmap* bitmap) const {
396     // When we're a snapshot from a surface, our bitmap may not be marked immutable
397     // even though logically always we are, but in that case we can't physically share our
398     // pixelref since the caller might call setImmutable() themselves
399     // (thus changing our state).
400     if (fBitmap.isImmutable()) {
401         SkIPoint origin = fBitmap.pixelRefOrigin();
402         bitmap->setInfo(fBitmap.info(), fBitmap.rowBytes());
403         bitmap->setPixelRef(sk_ref_sp(fBitmap.pixelRef()), origin.x(), origin.y());
404         return true;
405     }
406     return this->INHERITED::onAsLegacyBitmap(nullptr, bitmap);
407 }
408 
409 ///////////////////////////////////////////////////////////////////////////////
410 
onMakeColorTypeAndColorSpace(SkColorType targetCT,sk_sp<SkColorSpace> targetCS,GrDirectContext *) const411 sk_sp<SkImage> SkImage_Raster::onMakeColorTypeAndColorSpace(SkColorType targetCT,
412                                                             sk_sp<SkColorSpace> targetCS,
413                                                             GrDirectContext*) const {
414     SkPixmap src;
415     SkAssertResult(fBitmap.peekPixels(&src));
416 
417     SkBitmap dst;
418     dst.allocPixels(fBitmap.info().makeColorType(targetCT).makeColorSpace(targetCS));
419 
420     SkAssertResult(dst.writePixels(src));
421     dst.setImmutable();
422     return dst.asImage();
423 }
424 
onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const425 sk_sp<SkImage> SkImage_Raster::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
426     // TODO: If our bitmap is immutable, then we could theoretically create another image sharing
427     // our pixelRef. That doesn't work (without more invasive logic), because the image gets its
428     // gen ID from the bitmap, which gets it from the pixelRef.
429     SkPixmap pixmap = fBitmap.pixmap();
430     pixmap.setColorSpace(std::move(newCS));
431     return SkImage::MakeRasterCopy(pixmap);
432 }
433 
434 #if SK_SUPPORT_GPU
onAsView(GrRecordingContext * rContext,GrMipmapped mipmapped,GrImageTexGenPolicy policy) const435 std::tuple<GrSurfaceProxyView, GrColorType> SkImage_Raster::onAsView(
436         GrRecordingContext* rContext,
437         GrMipmapped mipmapped,
438         GrImageTexGenPolicy policy) const {
439     if (fPinnedView) {
440         // We ignore the mipmap request here. If the pinned view isn't mipmapped then we will
441         // fallback to bilinear. The pin API is used by Android Framework which does not expose
442         // mipmapping.Moreover, we're moving towards requiring that images be made with mip levels
443         // if mipmapping is desired (skbug.com/10411)
444         mipmapped = GrMipmapped::kNo;
445         if (policy != GrImageTexGenPolicy::kDraw) {
446             return {CopyView(rContext, fPinnedView, mipmapped, policy), fPinnedColorType};
447         }
448         return {fPinnedView, fPinnedColorType};
449     }
450     if (policy == GrImageTexGenPolicy::kDraw) {
451         return GrMakeCachedBitmapProxyView(rContext, fBitmap, mipmapped);
452     }
453     auto budgeted = (policy == GrImageTexGenPolicy::kNew_Uncached_Unbudgeted)
454             ? SkBudgeted::kNo
455             : SkBudgeted::kYes;
456     return GrMakeUncachedBitmapProxyView(rContext,
457                                          fBitmap,
458                                          mipmapped,
459                                          SkBackingFit::kExact,
460                                          budgeted);
461 }
462 
onAsFragmentProcessor(GrRecordingContext * rContext,SkSamplingOptions sampling,const SkTileMode tileModes[2],const SkMatrix & m,const SkRect * subset,const SkRect * domain) const463 std::unique_ptr<GrFragmentProcessor> SkImage_Raster::onAsFragmentProcessor(
464         GrRecordingContext* rContext,
465         SkSamplingOptions sampling,
466         const SkTileMode tileModes[2],
467         const SkMatrix& m,
468         const SkRect* subset,
469         const SkRect* domain) const {
470     auto mm = sampling.mipmap == SkMipmapMode::kNone ? GrMipmapped::kNo : GrMipmapped::kYes;
471     return MakeFragmentProcessorFromView(rContext,
472                                          std::get<0>(this->asView(rContext, mm)),
473                                          this->alphaType(),
474                                          sampling,
475                                          tileModes,
476                                          m,
477                                          subset,
478                                          domain);
479 }
480 #endif
481