2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "include/core/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColorSpace.h"
11 #include "include/core/SkData.h"
12 #include "include/core/SkPixelRef.h"
13 #include "include/core/SkSurface.h"
14 #include "include/private/SkImageInfoPriv.h"
15 #include "src/codec/SkColorTable.h"
16 #include "src/core/SkCompressedDataUtils.h"
17 #include "src/core/SkConvertPixels.h"
18 #include "src/core/SkImagePriv.h"
19 #include "src/core/SkTLazy.h"
20 #include "src/image/SkImage_Base.h"
21 #include "src/shaders/SkBitmapProcShader.h"
24 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
25 #include "src/gpu/ganesh/SkGr.h"
26 #include "src/gpu/ganesh/effects/GrBicubicEffect.h"
27 #include "src/gpu/ganesh/effects/GrTextureEffect.h"
30 #ifdef SK_GRAPHITE_ENABLED
31 #include "include/gpu/graphite/GraphiteTypes.h"
32 #include "include/gpu/graphite/Recorder.h"
33 #include "src/gpu/graphite/Buffer.h"
34 #include "src/gpu/graphite/Caps.h"
35 #include "src/gpu/graphite/CommandBuffer.h"
36 #include "src/gpu/graphite/RecorderPriv.h"
37 #include "src/gpu/graphite/TextureUtils.h"
38 #include "src/gpu/graphite/UploadTask.h"
41 // fixes https://bug.skia.org/5096
42 static bool is_not_subset(const SkBitmap& bm) {
43 SkASSERT(bm.pixelRef());
44 SkISize dim = SkISize::Make(bm.pixelRef()->width(), bm.pixelRef()->height());
45 SkASSERT(dim != bm.dimensions() || bm.pixelRefOrigin().isZero());
46 return dim == bm.dimensions();
49 class SkImage_Raster : public SkImage_Base {
51 static bool ValidArgs(const SkImageInfo& info, size_t rowBytes, size_t* minSize) {
52 const int maxDimension = SK_MaxS32 >> 2;
54 // TODO(mtklein): eliminate anything here that setInfo() has already checked.
56 if (!b.setInfo(info, rowBytes)) {
60 if (info.width() <= 0 || info.height() <= 0) {
63 if (info.width() > maxDimension || info.height() > maxDimension) {
66 if ((unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType) {
69 if ((unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType) {
73 if (kUnknown_SkColorType == info.colorType()) {
76 if (!info.validRowBytes(rowBytes)) {
80 size_t size = info.computeByteSize(rowBytes);
81 if (SkImageInfo::ByteSizeOverflowed(size)) {
91 SkImage_Raster(const SkImageInfo&, sk_sp<SkData>, size_t rb,
92 uint32_t id = kNeedNewImageUniqueID);
93 ~SkImage_Raster() override;
95 bool onReadPixels(GrDirectContext*, const SkImageInfo&, void*, size_t, int srcX, int srcY,
96 CachingHint) const override;
97 bool onPeekPixels(SkPixmap*) const override;
98 const SkBitmap* onPeekBitmap() const override { return &fBitmap; }
100 bool getROPixels(GrDirectContext*, SkBitmap*, CachingHint) const override;
101 sk_sp<SkImage> onMakeSubset(const SkIRect&, GrDirectContext*) const override;
103 SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
105 bool onAsLegacyBitmap(GrDirectContext*, SkBitmap*) const override;
107 SkImage_Raster(const SkBitmap& bm, bool bitmapMayBeMutable = false)
108 : INHERITED(bm.info(),
109 is_not_subset(bm) ? bm.getGenerationID() : (uint32_t)kNeedNewImageUniqueID)
111 SkASSERT(bitmapMayBeMutable || fBitmap.isImmutable());
114 sk_sp<SkImage> onMakeColorTypeAndColorSpace(SkColorType, sk_sp<SkColorSpace>,
115 GrDirectContext*) const override;
117 sk_sp<SkImage> onReinterpretColorSpace(sk_sp<SkColorSpace>) const override;
119 bool onIsValid(GrRecordingContext* context) const override { return true; }
120 void notifyAddedToRasterCache() const override {
121 // We explicitly DON'T want to call INHERITED::notifyAddedToRasterCache. That ties the
122 // lifetime of derived/cached resources to the image. In this case, we only want cached
123 // data (eg mips) tied to the lifetime of the underlying pixelRef.
124 SkASSERT(fBitmap.pixelRef());
125 fBitmap.pixelRef()->notifyAddedToCache();
129 bool onPinAsTexture(GrRecordingContext*) const override;
130 void onUnpinAsTexture(GrRecordingContext*) const override;
131 bool isPinnedOnContext(GrRecordingContext*) const override;
134 bool onHasMipmaps() const override { return SkToBool(fBitmap.fMips); }
136 SkMipmap* onPeekMips() const override { return fBitmap.fMips.get(); }
138 sk_sp<SkImage> onMakeWithMipmaps(sk_sp<SkMipmap> mips) const override {
139 // It's dangerous to have two SkBitmaps that share a SkPixelRef but have different SkMipmaps
140 // since various caches key on SkPixelRef's generation ID. Also, SkPixelRefs that back
141 // SkSurfaces are marked "temporarily immutable" and making an image that uses the same
142 // SkPixelRef can interact badly with SkSurface/SkImage copy-on-write. So we just always
143 // make a copy with a new ID.
144 static auto constexpr kCopyMode = SkCopyPixelsMode::kAlways_SkCopyPixelsMode;
145 sk_sp<SkImage> img = SkMakeImageFromRasterBitmap(fBitmap, kCopyMode);
146 auto imgRaster = static_cast<SkImage_Raster*>(img.get());
148 imgRaster->fBitmap.fMips = std::move(mips);
150 imgRaster->fBitmap.fMips.reset(SkMipmap::Build(fBitmap.pixmap(), nullptr));
157 std::tuple<GrSurfaceProxyView, GrColorType> onAsView(GrRecordingContext*,
159 GrImageTexGenPolicy) const override;
161 std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(GrRecordingContext*,
166 const SkRect*) const override;
168 #ifdef SK_GRAPHITE_ENABLED
169 std::tuple<skgpu::graphite::TextureProxyView, SkColorType> onAsView(
170 skgpu::graphite::Recorder*, skgpu::graphite::Mipmapped) const override;
176 mutable GrSurfaceProxyView fPinnedView;
177 mutable int32_t fPinnedCount = 0;
178 mutable uint32_t fPinnedUniqueID = SK_InvalidUniqueID;
179 mutable uint32_t fPinnedContextID = SK_InvalidUniqueID;
180 mutable GrColorType fPinnedColorType = GrColorType::kUnknown;
183 using INHERITED = SkImage_Base;
186 ///////////////////////////////////////////////////////////////////////////////
188 static void release_data(void* addr, void* context) {
189 SkData* data = static_cast<SkData*>(context);
193 SkImage_Raster::SkImage_Raster(const SkImageInfo& info, sk_sp<SkData> data, size_t rowBytes,
195 : INHERITED(info, id) {
196 void* addr = const_cast<void*>(data->data());
198 fBitmap.installPixels(info, addr, rowBytes, release_data, data.release());
199 fBitmap.setImmutable();
202 SkImage_Raster::~SkImage_Raster() {
204 SkASSERT(!fPinnedView); // want the caller to have manually unpinned
208 bool SkImage_Raster::onReadPixels(GrDirectContext*,
209 const SkImageInfo& dstInfo,
215 SkBitmap shallowCopy(fBitmap);
216 return shallowCopy.readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
219 bool SkImage_Raster::onPeekPixels(SkPixmap* pm) const {
220 return fBitmap.peekPixels(pm);
223 bool SkImage_Raster::getROPixels(GrDirectContext*, SkBitmap* dst, CachingHint) const {
229 bool SkImage_Raster::onPinAsTexture(GrRecordingContext* rContext) const {
231 SkASSERT(fPinnedCount > 0);
232 SkASSERT(fPinnedUniqueID != 0);
233 if (rContext->priv().contextID() != fPinnedContextID) {
237 SkASSERT(fPinnedCount == 0);
238 SkASSERT(fPinnedUniqueID == 0);
239 std::tie(fPinnedView, fPinnedColorType) = GrMakeCachedBitmapProxyView(rContext,
243 fPinnedColorType = GrColorType::kUnknown;
246 fPinnedUniqueID = fBitmap.getGenerationID();
247 fPinnedContextID = rContext->priv().contextID();
249 // Note: we only increment if the texture was successfully pinned
254 void SkImage_Raster::onUnpinAsTexture(GrRecordingContext* rContext) const {
255 // Note: we always decrement, even if fPinnedTexture is null
256 SkASSERT(fPinnedCount > 0);
257 SkASSERT(fPinnedUniqueID != 0);
258 #if 0 // This would be better but Android currently calls with an already freed context ptr.
259 if (rContext->priv().contextID() != fPinnedContextID) {
264 if (0 == --fPinnedCount) {
265 fPinnedView = GrSurfaceProxyView();
266 fPinnedUniqueID = SK_InvalidUniqueID;
267 fPinnedContextID = SK_InvalidUniqueID;
268 fPinnedColorType = GrColorType::kUnknown;
272 bool SkImage_Raster::isPinnedOnContext(GrRecordingContext* rContext) const {
273 return fPinnedContextID == rContext->priv().contextID();
277 sk_sp<SkImage> SkImage_Raster::onMakeSubset(const SkIRect& subset, GrDirectContext*) const {
278 SkImageInfo info = fBitmap.info().makeDimensions(subset.size());
280 if (!bitmap.tryAllocPixels(info)) {
284 void* dst = bitmap.getPixels();
285 void* src = fBitmap.getAddr(subset.x(), subset.y());
287 SkDEBUGFAIL("SkImage_Raster::onMakeSubset with nullptr src or dst");
291 SkRectMemcpy(dst, bitmap.rowBytes(), src, fBitmap.rowBytes(), bitmap.rowBytes(),
294 bitmap.setImmutable();
295 return bitmap.asImage();
298 ///////////////////////////////////////////////////////////////////////////////
300 sk_sp<SkImage> MakeRasterCopyPriv(const SkPixmap& pmap, uint32_t id) {
302 if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
306 // Here we actually make a copy of the caller's pixel data
307 sk_sp<SkData> data(SkData::MakeWithCopy(pmap.addr(), size));
308 return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes(), id);
311 sk_sp<SkImage> SkImage::MakeRasterCopy(const SkPixmap& pmap) {
312 return MakeRasterCopyPriv(pmap, kNeedNewImageUniqueID);
315 sk_sp<SkImage> SkImage::MakeRasterData(const SkImageInfo& info, sk_sp<SkData> data,
318 if (!SkImage_Raster::ValidArgs(info, rowBytes, &size) || !data) {
322 // did they give us enough data?
323 if (data->size() < size) {
327 return sk_make_sp<SkImage_Raster>(info, std::move(data), rowBytes);
330 // TODO: this could be improved to decode and make use of the mipmap
331 // levels potentially present in the compressed data. For now, any
332 // mipmap levels are discarded.
333 sk_sp<SkImage> SkImage::MakeRasterFromCompressed(sk_sp<SkData> data,
334 int width, int height,
335 CompressionType type) {
336 size_t expectedSize = SkCompressedFormatDataSize(type, { width, height }, false);
337 if (!data || data->size() < expectedSize) {
341 SkAlphaType at = SkCompressionTypeIsOpaque(type) ? kOpaque_SkAlphaType
342 : kPremul_SkAlphaType;
344 SkImageInfo ii = SkImageInfo::MakeN32(width, height, at);
346 if (!SkImage_Raster::ValidArgs(ii, ii.minRowBytes(), nullptr)) {
351 if (!bitmap.tryAllocPixels(ii)) {
355 if (!SkDecompress(std::move(data), { width, height }, type, &bitmap)) {
359 bitmap.setImmutable();
360 return MakeFromBitmap(bitmap);
363 sk_sp<SkImage> SkImage::MakeFromRaster(const SkPixmap& pmap, RasterReleaseProc proc,
364 ReleaseContext ctx) {
366 if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
370 sk_sp<SkData> data(SkData::MakeWithProc(pmap.addr(), size, proc, ctx));
371 return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes());
374 sk_sp<SkImage> SkMakeImageFromRasterBitmapPriv(const SkBitmap& bm, SkCopyPixelsMode cpm,
375 uint32_t idForCopy) {
376 if (kAlways_SkCopyPixelsMode == cpm || (!bm.isImmutable() && kNever_SkCopyPixelsMode != cpm)) {
378 if (bm.peekPixels(&pmap)) {
379 return MakeRasterCopyPriv(pmap, idForCopy);
381 return sk_sp<SkImage>();
385 return sk_make_sp<SkImage_Raster>(bm, kNever_SkCopyPixelsMode == cpm);
388 sk_sp<SkImage> SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode cpm) {
389 if (!SkImageInfoIsValid(bm.info()) || bm.rowBytes() < bm.info().minRowBytes()) {
393 return SkMakeImageFromRasterBitmapPriv(bm, cpm, kNeedNewImageUniqueID);
396 const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
397 return ((const SkImage_Raster*)image)->getPixelRef();
400 bool SkImage_Raster::onAsLegacyBitmap(GrDirectContext*, SkBitmap* bitmap) const {
401 // When we're a snapshot from a surface, our bitmap may not be marked immutable
402 // even though logically always we are, but in that case we can't physically share our
403 // pixelref since the caller might call setImmutable() themselves
404 // (thus changing our state).
405 if (fBitmap.isImmutable()) {
406 SkIPoint origin = fBitmap.pixelRefOrigin();
407 bitmap->setInfo(fBitmap.info(), fBitmap.rowBytes());
408 bitmap->setPixelRef(sk_ref_sp(fBitmap.pixelRef()), origin.x(), origin.y());
411 return this->INHERITED::onAsLegacyBitmap(nullptr, bitmap);
414 ///////////////////////////////////////////////////////////////////////////////
416 sk_sp<SkImage> SkImage_Raster::onMakeColorTypeAndColorSpace(SkColorType targetCT,
417 sk_sp<SkColorSpace> targetCS,
418 GrDirectContext*) const {
420 SkAssertResult(fBitmap.peekPixels(&src));
423 if (!dst.tryAllocPixels(fBitmap.info().makeColorType(targetCT).makeColorSpace(targetCS))) {
427 SkAssertResult(dst.writePixels(src));
429 return dst.asImage();
432 sk_sp<SkImage> SkImage_Raster::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
433 // TODO: If our bitmap is immutable, then we could theoretically create another image sharing
434 // our pixelRef. That doesn't work (without more invasive logic), because the image gets its
435 // gen ID from the bitmap, which gets it from the pixelRef.
436 SkPixmap pixmap = fBitmap.pixmap();
437 pixmap.setColorSpace(std::move(newCS));
438 return SkImage::MakeRasterCopy(pixmap);
442 std::tuple<GrSurfaceProxyView, GrColorType> SkImage_Raster::onAsView(
443 GrRecordingContext* rContext,
444 GrMipmapped mipmapped,
445 GrImageTexGenPolicy policy) const {
447 // We ignore the mipmap request here. If the pinned view isn't mipmapped then we will
448 // fallback to bilinear. The pin API is used by Android Framework which does not expose
449 // mipmapping . Moreover, we're moving towards requiring that images be made with mip levels
450 // if mipmapping is desired (skbug.com/10411)
451 mipmapped = GrMipmapped::kNo;
452 if (policy != GrImageTexGenPolicy::kDraw) {
453 return {CopyView(rContext, fPinnedView, mipmapped, policy), fPinnedColorType};
455 return {fPinnedView, fPinnedColorType};
457 if (policy == GrImageTexGenPolicy::kDraw) {
458 // If the draw doesn't require mipmaps but this SkImage has them go ahead and make a
459 // mipmapped texture. There are three reasons for this:
460 // 1) Avoiding another texture creation if a later draw requires mipmaps.
461 // 2) Ensuring we upload the bitmap's levels instead of generating on the GPU from the base.
462 if (this->hasMipmaps()) {
463 mipmapped = GrMipmapped::kYes;
465 return GrMakeCachedBitmapProxyView(rContext, fBitmap, mipmapped);
467 auto budgeted = (policy == GrImageTexGenPolicy::kNew_Uncached_Unbudgeted)
470 return GrMakeUncachedBitmapProxyView(rContext,
473 SkBackingFit::kExact,
477 std::unique_ptr<GrFragmentProcessor> SkImage_Raster::onAsFragmentProcessor(
478 GrRecordingContext* rContext,
479 SkSamplingOptions sampling,
480 const SkTileMode tileModes[2],
482 const SkRect* subset,
483 const SkRect* domain) const {
484 auto mm = sampling.mipmap == SkMipmapMode::kNone ? GrMipmapped::kNo : GrMipmapped::kYes;
485 return MakeFragmentProcessorFromView(rContext,
486 std::get<0>(this->asView(rContext, mm)),
496 #ifdef SK_GRAPHITE_ENABLED
497 std::tuple<skgpu::graphite::TextureProxyView, SkColorType> SkImage_Raster::onAsView(
498 skgpu::graphite::Recorder* recorder,
499 skgpu::graphite::Mipmapped mipmapped) const {
500 return MakeBitmapProxyView(recorder, fBitmap, mipmapped, SkBudgeted::kNo);