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