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