diff options
-rw-r--r-- | bench/SkBlend_optsBench.cpp | 2 | ||||
-rw-r--r-- | gm/image_pict.cpp | 3 | ||||
-rw-r--r-- | src/codec/SkCodecImageGenerator.cpp | 8 | ||||
-rw-r--r-- | src/core/SkBitmapDevice.cpp | 7 | ||||
-rw-r--r-- | src/core/SkBitmapProvider.cpp | 2 | ||||
-rw-r--r-- | src/core/SkBitmapProvider.h | 10 | ||||
-rw-r--r-- | src/core/SkDevice.cpp | 10 | ||||
-rw-r--r-- | src/core/SkImageCacherator.cpp | 255 | ||||
-rw-r--r-- | src/core/SkImageCacherator.h | 25 | ||||
-rw-r--r-- | src/core/SkSpecialImage.cpp | 3 | ||||
-rw-r--r-- | src/core/SkSpecialImage.h | 1 | ||||
-rw-r--r-- | src/effects/SkImageSource.cpp | 4 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 12 | ||||
-rw-r--r-- | src/image/SkImage.cpp | 29 | ||||
-rw-r--r-- | src/image/SkImageShader.cpp | 6 | ||||
-rw-r--r-- | src/image/SkImage_Base.h | 3 | ||||
-rw-r--r-- | src/image/SkImage_Generator.cpp | 15 | ||||
-rw-r--r-- | src/image/SkImage_Gpu.cpp | 18 | ||||
-rw-r--r-- | src/image/SkImage_Gpu.h | 2 | ||||
-rw-r--r-- | src/image/SkImage_Raster.cpp | 4 | ||||
-rw-r--r-- | src/pdf/SkPDFBitmap.cpp | 5 | ||||
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 6 | ||||
-rw-r--r-- | tests/ImageFilterCacheTest.cpp | 6 | ||||
-rw-r--r-- | tests/SkBlend_optsTest.cpp | 2 | ||||
-rw-r--r-- | tests/SpecialImageTest.cpp | 15 | ||||
-rw-r--r-- | tools/Resources.cpp | 7 |
26 files changed, 378 insertions, 82 deletions
diff --git a/bench/SkBlend_optsBench.cpp b/bench/SkBlend_optsBench.cpp index 6a4593e664..b5827ef03b 100644 --- a/bench/SkBlend_optsBench.cpp +++ b/bench/SkBlend_optsBench.cpp @@ -146,7 +146,7 @@ protected: if (!fPixmap.addr()) { sk_sp<SkImage> image = GetResourceAsImage(fFileName.c_str()); SkBitmap bm; - if (!as_IB(image)->getROPixels(&bm)) { + if (!as_IB(image)->getROPixels(&bm, SkDestinationSurfaceColorMode::kLegacy)) { SkFAIL("Could not read resource"); } bm.peekPixels(&fPixmap); diff --git a/gm/image_pict.cpp b/gm/image_pict.cpp index 903024b8ee..53f83ac4c2 100644 --- a/gm/image_pict.cpp +++ b/gm/image_pict.cpp @@ -308,7 +308,8 @@ protected: static void draw_as_bitmap(SkCanvas* canvas, SkImageCacherator* cache, SkScalar x, SkScalar y) { SkBitmap bitmap; - cache->lockAsBitmap(&bitmap, nullptr); + cache->lockAsBitmap(&bitmap, nullptr, + SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware); canvas->drawBitmap(bitmap, x, y); } diff --git a/src/codec/SkCodecImageGenerator.cpp b/src/codec/SkCodecImageGenerator.cpp index 8108f0de44..9f85971f89 100644 --- a/src/codec/SkCodecImageGenerator.cpp +++ b/src/codec/SkCodecImageGenerator.cpp @@ -36,13 +36,7 @@ SkData* SkCodecImageGenerator::onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) { bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) { - - // FIXME (msarett): - // We don't give the client the chance to request an SkColorSpace. Until we improve - // the API, let's assume that they want legacy mode. - SkImageInfo decodeInfo = info.makeColorSpace(nullptr); - - SkCodec::Result result = fCodec->getPixels(decodeInfo, pixels, rowBytes, nullptr, ctable, + SkCodec::Result result = fCodec->getPixels(info, pixels, rowBytes, nullptr, ctable, ctableCount); switch (result) { case SkCodec::kSuccess: diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp index e44b76926a..1e618accb0 100644 --- a/src/core/SkBitmapDevice.cpp +++ b/src/core/SkBitmapDevice.cpp @@ -418,8 +418,13 @@ sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) { } sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkImage* image) { + // This is called when we're about to draw the special-ized version of image to *this* device, + // so we can use our own presense/absence of a color space to decide how to decode the image. + SkDestinationSurfaceColorMode decodeColorMode = fBitmap.colorSpace() + ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware + : SkDestinationSurfaceColorMode::kLegacy; return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->height()), - image->makeNonTextureImage()); + image->makeNonTextureImage(), decodeColorMode); } sk_sp<SkSpecialImage> SkBitmapDevice::snapSpecial() { diff --git a/src/core/SkBitmapProvider.cpp b/src/core/SkBitmapProvider.cpp index 8347d32d7f..0951393b73 100644 --- a/src/core/SkBitmapProvider.cpp +++ b/src/core/SkBitmapProvider.cpp @@ -44,5 +44,5 @@ void SkBitmapProvider::notifyAddedToCache() const { } bool SkBitmapProvider::asBitmap(SkBitmap* bm) const { - return as_IB(fImage)->getROPixels(bm, SkImage::kAllow_CachingHint); + return as_IB(fImage)->getROPixels(bm, fColorMode, SkImage::kAllow_CachingHint); } diff --git a/src/core/SkBitmapProvider.h b/src/core/SkBitmapProvider.h index 2e878b18ab..9cbbf0d470 100644 --- a/src/core/SkBitmapProvider.h +++ b/src/core/SkBitmapProvider.h @@ -13,9 +13,14 @@ class SkBitmapProvider { public: - explicit SkBitmapProvider(const SkImage* img) : fImage(img) { SkASSERT(img); } + explicit SkBitmapProvider(const SkImage* img, SkDestinationSurfaceColorMode colorMode) + : fImage(img) + , fColorMode(colorMode) { + SkASSERT(img); + } SkBitmapProvider(const SkBitmapProvider& other) : fImage(other.fImage) + , fColorMode(other.fColorMode) {} int width() const; @@ -40,7 +45,8 @@ private: // SkBitmapProvider is always short-lived/stack allocated, and the source image is guaranteed // to outlive its scope => we can store a raw ptr to avoid ref churn. - const SkImage* fImage; + const SkImage* fImage; + SkDestinationSurfaceColorMode fColorMode; }; #endif diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index b2ff2423ed..5f0ecb99c6 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -180,8 +180,11 @@ void SkBaseDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkSc void SkBaseDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x, SkScalar y, const SkPaint& paint) { // Default impl : turns everything into raster bitmap + SkDestinationSurfaceColorMode colorMode = this->imageInfo().colorSpace() + ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware + : SkDestinationSurfaceColorMode::kLegacy; SkBitmap bm; - if (as_IB(image)->getROPixels(&bm)) { + if (as_IB(image)->getROPixels(&bm, colorMode)) { this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); } } @@ -190,8 +193,11 @@ void SkBaseDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { // Default impl : turns everything into raster bitmap + SkDestinationSurfaceColorMode colorMode = this->imageInfo().colorSpace() + ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware + : SkDestinationSurfaceColorMode::kLegacy; SkBitmap bm; - if (as_IB(image)->getROPixels(&bm)) { + if (as_IB(image)->getROPixels(&bm, colorMode)) { this->drawBitmapRect(draw, bm, src, dst, paint, constraint); } } diff --git a/src/core/SkImageCacherator.cpp b/src/core/SkImageCacherator.cpp index 54045d5821..d6f816e8ef 100644 --- a/src/core/SkImageCacherator.cpp +++ b/src/core/SkImageCacherator.cpp @@ -7,6 +7,7 @@ #include "SkBitmap.h" #include "SkBitmapCache.h" +#include "SkColorSpace_Base.h" #include "SkImage_Base.h" #include "SkImageCacherator.h" #include "SkMallocPixelRef.h" @@ -84,8 +85,19 @@ SkImageCacherator::Validator::Validator(sk_sp<SharedGenerator> gen, const SkIRec subset = &bounds; } - fInfo = info.makeWH(subset->width(), subset->height()); + fInfo = info.makeWH(subset->width(), subset->height()); fOrigin = SkIPoint::Make(subset->x(), subset->y()); + + // If the encoded data is in a strange color space (it's not an XYZ matrix space), we won't be + // able to preserve the gamut of the encoded data when we decode it. Instead, we'll have to + // decode to a known color space (linear sRGB is a good choice). But we need to adjust the + // stored color space, because drawing code will ask the SkImage for its color space, which + // will in turn ask the cacherator. If we return the A2B color space, then we will be unable to + // construct a source-to-dest gamut transformation matrix. + if (fInfo.colorSpace() && + SkColorSpace_Base::Type::kXYZ != as_CSB(fInfo.colorSpace())->type()) { + fInfo = fInfo.makeColorSpace(SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named)); + } } SkImageCacherator* SkImageCacherator::NewFromGenerator(SkImageGenerator* gen, @@ -99,8 +111,12 @@ SkImageCacherator::SkImageCacherator(Validator* validator) : fSharedGenerator(std::move(validator->fSharedGenerator)) // we take ownership , fInfo(validator->fInfo) , fOrigin(validator->fOrigin) - , fUniqueID(validator->fUniqueID) { + fUniqueIDs[kLegacy_CachedFormat] = validator->fUniqueID; + for (int i = 1; i < kNumCachedFormats; ++i) { + // We lazily allocate IDs for non-default caching cases + fUniqueIDs[i] = kNeedNewImageUniqueID; + } SkASSERT(fSharedGenerator); } @@ -121,24 +137,26 @@ static bool check_output_bitmap(const SkBitmap& bitmap, uint32_t expectedID) { // Note, this returns a new, mutable, bitmap, with a new genID. // If you want the immutable bitmap with the same ID as our cacherator, call tryLockAsBitmap() // -bool SkImageCacherator::generateBitmap(SkBitmap* bitmap) { +bool SkImageCacherator::generateBitmap(SkBitmap* bitmap, const SkImageInfo& decodeInfo) { SkBitmap::Allocator* allocator = SkResourceCache::GetAllocator(); ScopedGenerator generator(fSharedGenerator); const SkImageInfo& genInfo = generator->getInfo(); - if (fInfo.dimensions() == genInfo.dimensions()) { + if (decodeInfo.dimensions() == genInfo.dimensions()) { SkASSERT(fOrigin.x() == 0 && fOrigin.y() == 0); // fast-case, no copy needed - return generator->tryGenerateBitmap(bitmap, fInfo, allocator); + return generator->tryGenerateBitmap(bitmap, decodeInfo, allocator); } else { // need to handle subsetting, so we first generate the full size version, and then // "read" from it to get our subset. See https://bug.skia.org/4213 SkBitmap full; - if (!generator->tryGenerateBitmap(&full, genInfo, allocator)) { + if (!generator->tryGenerateBitmap(&full, + decodeInfo.makeWH(genInfo.width(), genInfo.height()), + allocator)) { return false; } - if (!bitmap->tryAllocPixels(fInfo, nullptr, full.getColorTable())) { + if (!bitmap->tryAllocPixels(decodeInfo, nullptr, full.getColorTable())) { return false; } return full.readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), @@ -159,22 +177,28 @@ bool SkImageCacherator::directGeneratePixels(const SkImageInfo& info, void* pixe ////////////////////////////////////////////////////////////////////////////////////////////////// -bool SkImageCacherator::lockAsBitmapOnlyIfAlreadyCached(SkBitmap* bitmap) { - return SkBitmapCache::Find(fUniqueID, bitmap) && check_output_bitmap(*bitmap, fUniqueID); +bool SkImageCacherator::lockAsBitmapOnlyIfAlreadyCached(SkBitmap* bitmap, CachedFormat format) { + return kNeedNewImageUniqueID != fUniqueIDs[format] && + SkBitmapCache::Find(fUniqueIDs[format], bitmap) && + check_output_bitmap(*bitmap, fUniqueIDs[format]); } bool SkImageCacherator::tryLockAsBitmap(SkBitmap* bitmap, const SkImage* client, - SkImage::CachingHint chint) { - if (this->lockAsBitmapOnlyIfAlreadyCached(bitmap)) { + SkImage::CachingHint chint, CachedFormat format, + const SkImageInfo& info) { + if (this->lockAsBitmapOnlyIfAlreadyCached(bitmap, format)) { return true; } - if (!this->generateBitmap(bitmap)) { + if (!this->generateBitmap(bitmap, info)) { return false; } - bitmap->pixelRef()->setImmutableWithID(fUniqueID); + if (kNeedNewImageUniqueID == fUniqueIDs[format]) { + fUniqueIDs[format] = SkNextID::ImageID(); + } + bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]); if (SkImage::kAllow_CachingHint == chint) { - SkBitmapCache::Add(fUniqueID, *bitmap); + SkBitmapCache::Add(fUniqueIDs[format], *bitmap); if (client) { as_IB(client)->notifyAddedToCache(); } @@ -183,9 +207,17 @@ bool SkImageCacherator::tryLockAsBitmap(SkBitmap* bitmap, const SkImage* client, } bool SkImageCacherator::lockAsBitmap(SkBitmap* bitmap, const SkImage* client, + SkDestinationSurfaceColorMode colorMode, SkImage::CachingHint chint) { - if (this->tryLockAsBitmap(bitmap, client, chint)) { - return check_output_bitmap(*bitmap, fUniqueID); + CachedFormat format = chooseCacheFormat(colorMode); + SkImageInfo cacheInfo = buildCacheInfo(format); + + if (kNeedNewImageUniqueID == fUniqueIDs[format]) { + fUniqueIDs[format] = SkNextID::ImageID(); + } + + if (this->tryLockAsBitmap(bitmap, client, chint, format, cacheInfo)) { + return check_output_bitmap(*bitmap, fUniqueIDs[format]); } #if SK_SUPPORT_GPU @@ -194,7 +226,8 @@ bool SkImageCacherator::lockAsBitmap(SkBitmap* bitmap, const SkImage* client, { ScopedGenerator generator(fSharedGenerator); - SkIRect subset = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), fInfo.width(), fInfo.height()); + SkIRect subset = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), + cacheInfo.width(), cacheInfo.height()); tex.reset(generator->generateTexture(nullptr, &subset)); } if (!tex) { @@ -202,27 +235,27 @@ bool SkImageCacherator::lockAsBitmap(SkBitmap* bitmap, const SkImage* client, return false; } - if (!bitmap->tryAllocPixels(fInfo)) { + if (!bitmap->tryAllocPixels(cacheInfo)) { bitmap->reset(); return false; } const uint32_t pixelOpsFlags = 0; if (!tex->readPixels(0, 0, bitmap->width(), bitmap->height(), - SkImageInfo2GrPixelConfig(fInfo, *tex->getContext()->caps()), + SkImageInfo2GrPixelConfig(cacheInfo, *tex->getContext()->caps()), bitmap->getPixels(), bitmap->rowBytes(), pixelOpsFlags)) { bitmap->reset(); return false; } - bitmap->pixelRef()->setImmutableWithID(fUniqueID); + bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]); if (SkImage::kAllow_CachingHint == chint) { - SkBitmapCache::Add(fUniqueID, *bitmap); + SkBitmapCache::Add(fUniqueIDs[format], *bitmap); if (client) { as_IB(client)->notifyAddedToCache(); } } - return check_output_bitmap(*bitmap, fUniqueID); + return check_output_bitmap(*bitmap, fUniqueIDs[format]); #else return false; #endif @@ -268,6 +301,171 @@ static GrTexture* set_key_and_return(GrTexture* tex, const GrUniqueKey& key) { return tex; } +// Abstraction of GrCaps that handles the cases where we don't have a caps pointer (because +// we're in raster mode), or where GPU support is entirely missing. +struct CacheCaps { + CacheCaps(const GrCaps* caps) : fCaps(caps) {} + +#if SK_SUPPORT_GPU + bool supportsHalfFloat() const { + return !fCaps || fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig); + } + + bool supportsSRGB() const { + return !fCaps || fCaps->isConfigTexturable(kSRGBA_8888_GrPixelConfig); + } + + bool supportsSBGR() const { + return !fCaps || fCaps->isConfigTexturable(kSBGRA_8888_GrPixelConfig); + } +#else + bool supportsHalfFloat() const { return true; } + bool supportsSRGB() const { return true; } + bool supportsSBGR() const { return true; } +#endif + + const GrCaps* fCaps; +}; + +SkImageCacherator::CachedFormat SkImageCacherator::chooseCacheFormat( + SkDestinationSurfaceColorMode colorMode, + const GrCaps* grCaps) { + SkColorSpace* cs = fInfo.colorSpace(); + if (!cs || SkDestinationSurfaceColorMode::kLegacy == colorMode) { + return kLegacy_CachedFormat; + } + + CacheCaps caps(grCaps); + switch (fInfo.colorType()) { + case kUnknown_SkColorType: + case kAlpha_8_SkColorType: + case kRGB_565_SkColorType: + case kARGB_4444_SkColorType: + // We don't support color space on these formats, so always decode in legacy mode: + // TODO: Ask the codec to decode these to something else (at least sRGB 8888)? + return kLegacy_CachedFormat; + + case kIndex_8_SkColorType: + // We can't draw from indexed textures with a color space, so ask the codec to expand + if (cs->gammaCloseToSRGB()) { + if (caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else if (caps.supportsHalfFloat()) { + return kLinearF16_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + } else { + if (caps.supportsHalfFloat()) { + return kLinearF16_CachedFormat; + } else if (caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + } + + case kGray_8_SkColorType: + // TODO: What do we do with grayscale sources that have strange color spaces attached? + // The codecs and color space xform don't handle this correctly (yet), so drop it on + // the floor. (Also, inflating by a factor of 8 is going to be unfortunate). + // As it is, we don't directly support sRGB grayscale, so ask the codec to convert + // it for us. This bypasses some really sketchy code GrUploadPixmapToTexture. + if (cs->gammaCloseToSRGB() && caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + + case kRGBA_8888_SkColorType: + if (cs->gammaCloseToSRGB()) { + if (caps.supportsSRGB()) { + return kAsIs_CachedFormat; + } else if (caps.supportsHalfFloat()) { + return kLinearF16_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + } else { + if (caps.supportsHalfFloat()) { + return kLinearF16_CachedFormat; + } else if (caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + } + + case kBGRA_8888_SkColorType: + // Odd case. sBGRA isn't a real thing, so we may not have this texturable. + if (caps.supportsSBGR()) { + if (cs->gammaCloseToSRGB()) { + return kAsIs_CachedFormat; + } else if (caps.supportsHalfFloat()) { + return kLinearF16_CachedFormat; + } else if (caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else { + // sBGRA support without sRGBA is highly unlikely (impossible?) Nevertheless. + return kLegacy_CachedFormat; + } + } else { + if (cs->gammaCloseToSRGB()) { + if (caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else if (caps.supportsHalfFloat()) { + return kLinearF16_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + } else { + if (caps.supportsHalfFloat()) { + return kLinearF16_CachedFormat; + } else if (caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + } + } + + case kRGBA_F16_SkColorType: + if (!caps.supportsHalfFloat()) { + if (caps.supportsSRGB()) { + return kSRGB8888_CachedFormat; + } else { + return kLegacy_CachedFormat; + } + } else if (cs->gammaIsLinear()) { + return kAsIs_CachedFormat; + } else { + return kLinearF16_CachedFormat; + } + } + SkDEBUGFAIL("Unreachable"); + return kLegacy_CachedFormat; +} + +SkImageInfo SkImageCacherator::buildCacheInfo(CachedFormat format) { + switch (format) { + case kLegacy_CachedFormat: + return fInfo.makeColorSpace(nullptr); + case kAsIs_CachedFormat: + return fInfo; + case kLinearF16_CachedFormat: + return fInfo + .makeColorType(kRGBA_F16_SkColorType) + .makeColorSpace(as_CSB(fInfo.colorSpace())->makeLinearGamma()); + case kSRGB8888_CachedFormat: + return fInfo + .makeColorType(kRGBA_8888_SkColorType) + .makeColorSpace(as_CSB(fInfo.colorSpace())->makeSRGBGamma()); + default: + SkDEBUGFAIL("Invalid cached format"); + return fInfo; + } +} + /* * We have a 5 ways to try to return a texture (in sorted order) * @@ -314,7 +512,16 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key } } - const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(fInfo, *ctx->caps()); + // Determine which cached format we're going to use (which may involve decoding to a different + // info than the generator provides). + CachedFormat format = chooseCacheFormat(colorMode, ctx->caps()); + + // The CachedFormat is both an index for which cache "slot" we'll use to store this particular + // decoded variant of the encoded data, and also a recipe for how to transform the original + // info to get the one that we're going to decode to. + SkImageInfo cacheInfo = buildCacheInfo(format); + + const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(cacheInfo, *ctx->caps()); #ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR // 3. Ask the generator to return a compressed form that the GPU might support @@ -343,7 +550,7 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key // 5. Ask the generator to return RGB(A) data, which the GPU can convert SkBitmap bitmap; - if (this->tryLockAsBitmap(&bitmap, client, chint)) { + if (this->tryLockAsBitmap(&bitmap, client, chint, format, cacheInfo)) { GrTexture* tex = nullptr; if (willBeMipped) { tex = GrGenerateMipMapsAndUploadToTexture(ctx, bitmap, colorMode); diff --git a/src/core/SkImageCacherator.h b/src/core/SkImageCacherator.h index a8a05a1f90..fc03e8e5e9 100644 --- a/src/core/SkImageCacherator.h +++ b/src/core/SkImageCacherator.h @@ -12,6 +12,7 @@ #include "SkMutex.h" #include "SkTemplates.h" +class GrCaps; class GrContext; class GrTextureParams; class GrUniqueKey; @@ -29,7 +30,16 @@ public: ~SkImageCacherator(); const SkImageInfo& info() const { return fInfo; } - uint32_t uniqueID() const { return fUniqueID; } + uint32_t uniqueID() const { return fUniqueIDs[kLegacy_CachedFormat]; } + + enum CachedFormat { + kLegacy_CachedFormat, // The format from the generator, with any color space stripped out + kAsIs_CachedFormat, // The format from the generator, with no modification + kLinearF16_CachedFormat, // Half float RGBA with linear gamma + kSRGB8888_CachedFormat, // sRGB bytes + + kNumCachedFormats, + }; /** * On success (true), bitmap will point to the pixels for this generator. If this returns @@ -38,7 +48,7 @@ public: * If not NULL, the client will be notified (->notifyAddedToCache()) when resources are * added to the cache on its behalf. */ - bool lockAsBitmap(SkBitmap*, const SkImage* client, + bool lockAsBitmap(SkBitmap*, const SkImage* client, SkDestinationSurfaceColorMode colorMode, SkImage::CachingHint = SkImage::kAllow_CachingHint); /** @@ -64,7 +74,7 @@ public: SkData* refEncoded(GrContext*); // Only return true if the generate has already been cached. - bool lockAsBitmapOnlyIfAlreadyCached(SkBitmap*); + bool lockAsBitmapOnlyIfAlreadyCached(SkBitmap*, CachedFormat); // Call the underlying generator directly bool directGeneratePixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, int srcX, int srcY); @@ -102,19 +112,22 @@ private: SkImageCacherator(Validator*); - bool generateBitmap(SkBitmap*); - bool tryLockAsBitmap(SkBitmap*, const SkImage*, SkImage::CachingHint); + bool generateBitmap(SkBitmap*, const SkImageInfo&); + bool tryLockAsBitmap(SkBitmap*, const SkImage*, SkImage::CachingHint, CachedFormat, + const SkImageInfo&); #if SK_SUPPORT_GPU // Returns the texture. If the cacherator is generating the texture and wants to cache it, // it should use the passed in key (if the key is valid). GrTexture* lockTexture(GrContext*, const GrUniqueKey& key, const SkImage* client, SkImage::CachingHint, bool willBeMipped, SkDestinationSurfaceColorMode); + CachedFormat chooseCacheFormat(SkDestinationSurfaceColorMode, const GrCaps* = nullptr); + SkImageInfo buildCacheInfo(CachedFormat); #endif sk_sp<SharedGenerator> fSharedGenerator; const SkImageInfo fInfo; const SkIPoint fOrigin; - const uint32_t fUniqueID; + uint32_t fUniqueIDs[kNumCachedFormats]; friend class GrImageTextureMaker; friend class SkImage; diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp index f18878175b..2c96626d1d 100644 --- a/src/core/SkSpecialImage.cpp +++ b/src/core/SkSpecialImage.cpp @@ -181,6 +181,7 @@ static bool rect_fits(const SkIRect& rect, int width, int height) { sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(const SkIRect& subset, sk_sp<SkImage> image, + SkDestinationSurfaceColorMode colorMode, const SkSurfaceProps* props) { SkASSERT(rect_fits(subset, image->width(), image->height())); @@ -192,7 +193,7 @@ sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(const SkIRect& subset, #endif { SkBitmap bm; - if (as_IB(image)->getROPixels(&bm)) { + if (as_IB(image)->getROPixels(&bm, colorMode)) { return MakeFromRaster(subset, bm, props); } } diff --git a/src/core/SkSpecialImage.h b/src/core/SkSpecialImage.h index 12847df115..c6afa1d0c7 100644 --- a/src/core/SkSpecialImage.h +++ b/src/core/SkSpecialImage.h @@ -73,6 +73,7 @@ public: static sk_sp<SkSpecialImage> MakeFromImage(const SkIRect& subset, sk_sp<SkImage>, + SkDestinationSurfaceColorMode, const SkSurfaceProps* = nullptr); static sk_sp<SkSpecialImage> MakeFromRaster(const SkIRect& subset, const SkBitmap&, diff --git a/src/effects/SkImageSource.cpp b/src/effects/SkImageSource.cpp index f96a4a1676..de849416c8 100644 --- a/src/effects/SkImageSource.cpp +++ b/src/effects/SkImageSource.cpp @@ -86,8 +86,12 @@ sk_sp<SkSpecialImage> SkImageSource::onFilterImage(SkSpecialImage* source, const if (fSrcRect == bounds && dstRect == bounds) { // No regions cropped out or resized; return entire image. offset->fX = offset->fY = 0; + SkDestinationSurfaceColorMode decodeColorMode = ctx.outputProperties().colorSpace() + ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware + : SkDestinationSurfaceColorMode::kLegacy; return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(fImage->width(), fImage->height()), fImage, + decodeColorMode, &source->props()); } diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 1fbc953b65..79df90f4d3 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1379,7 +1379,7 @@ void SkGpuDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x if (this->shouldTileImage(image, nullptr, SkCanvas::kFast_SrcRectConstraint, paint.getFilterQuality(), *draw.fMatrix, SkMatrix::I())) { // only support tiling as bitmap at the moment, so force raster-version - if (!as_IB(image)->getROPixels(&bm)) { + if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->colorMode())) { return; } this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); @@ -1388,7 +1388,7 @@ void SkGpuDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x GrImageTextureMaker maker(fContext.get(), cacher, image, SkImage::kAllow_CachingHint); this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint, viewMatrix, fClip, paint); - } else if (as_IB(image)->getROPixels(&bm)) { + } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->colorMode())) { this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); } } @@ -1413,7 +1413,7 @@ void SkGpuDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality(), *draw.fMatrix, srcToDstRect)) { // only support tiling as bitmap at the moment, so force raster-version - if (!as_IB(image)->getROPixels(&bm)) { + if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->colorMode())) { return; } this->drawBitmapRect(draw, bm, src, dst, paint, constraint); @@ -1421,7 +1421,7 @@ void SkGpuDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const CHECK_SHOULD_DRAW(draw); GrImageTextureMaker maker(fContext.get(), cacher, image, SkImage::kAllow_CachingHint); this->drawTextureProducer(&maker, src, &dst, constraint, *draw.fMatrix, fClip, paint); - } else if (as_IB(image)->getROPixels(&bm)) { + } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->colorMode())) { this->drawBitmapRect(draw, bm, src, dst, paint, constraint); } } @@ -1483,7 +1483,7 @@ void SkGpuDevice::drawImageNine(const SkDraw& draw, const SkImage* image, if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) { GrImageTextureMaker maker(fContext.get(), cacher, image, SkImage::kAllow_CachingHint); this->drawProducerNine(draw, &maker, center, dst, paint); - } else if (as_IB(image)->getROPixels(&bm)) { + } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->colorMode())) { this->drawBitmapNine(draw, bm, center, dst, paint); } } @@ -1538,7 +1538,7 @@ void SkGpuDevice::drawImageLattice(const SkDraw& draw, const SkImage* image, if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) { GrImageTextureMaker maker(fContext.get(), cacher, image, SkImage::kAllow_CachingHint); this->drawProducerLattice(draw, &maker, lattice, dst, paint); - } else if (as_IB(image)->getROPixels(&bm)) { + } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->colorMode())) { this->drawBitmapLattice(draw, bm, lattice, dst, paint); } } diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp index 4d76638cbd..f976242eca 100644 --- a/src/image/SkImage.cpp +++ b/src/image/SkImage.cpp @@ -65,8 +65,11 @@ bool SkImage::scalePixels(const SkPixmap& dst, SkFilterQuality quality, CachingH // Idea: If/when SkImageGenerator supports a native-scaling API (where the generator itself // can scale more efficiently) we should take advantage of it here. // + SkDestinationSurfaceColorMode decodeColorMode = dst.info().colorSpace() + ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware + : SkDestinationSurfaceColorMode::kLegacy; SkBitmap bm; - if (as_IB(this)->getROPixels(&bm, chint)) { + if (as_IB(this)->getROPixels(&bm, decodeColorMode, chint)) { bm.lockPixels(); SkPixmap pmap; // Note: By calling the pixmap scaler, we never cache the final result, so the chint @@ -83,7 +86,7 @@ void SkImage::preroll(GrContext* ctx) const { // to produce a cached raster-bitmap form, so that drawing to a raster canvas should be fast. // SkBitmap bm; - if (as_IB(this)->getROPixels(&bm)) { + if (as_IB(this)->getROPixels(&bm, SkDestinationSurfaceColorMode::kLegacy)) { bm.lockPixels(); bm.unlockPixels(); } @@ -102,7 +105,10 @@ sk_sp<SkShader> SkImage::makeShader(SkShader::TileMode tileX, SkShader::TileMode SkData* SkImage::encode(SkImageEncoder::Type type, int quality) const { SkBitmap bm; - if (as_IB(this)->getROPixels(&bm)) { + // TODO: Right now, the encoders don't handle F16 or linearly premultiplied data. Once they do, + // we should decode in "color space aware" mode, then re-encode that. For now, work around this + // by asking for a legacy decode (which gives us the raw data in N32). + if (as_IB(this)->getROPixels(&bm, SkDestinationSurfaceColorMode::kLegacy)) { return SkImageEncoder::EncodeData(bm, type, quality); } return nullptr; @@ -123,7 +129,11 @@ SkData* SkImage::encode(SkPixelSerializer* serializer) const { SkBitmap bm; SkAutoPixmapUnlock apu; - if (as_IB(this)->getROPixels(&bm) && bm.requestLock(&apu)) { + // TODO: Right now, the encoders don't handle F16 or linearly premultiplied data. Once they do, + // we should decode in "color space aware" mode, then re-encode that. For now, work around this + // by asking for a legacy decode (which gives us the raw data in N32). + if (as_IB(this)->getROPixels(&bm, SkDestinationSurfaceColorMode::kLegacy) && + bm.requestLock(&apu)) { return effectiveSerializer->encode(apu.pixmap()); } @@ -284,8 +294,7 @@ bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const { bool SkImage_Base::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const { // As the base-class, all we can do is make a copy (regardless of mode). // Subclasses that want to be more optimal should override. - SkImageInfo info = this->onImageInfo().makeColorType(kN32_SkColorType) - .makeAlphaType(this->alphaType()); + SkImageInfo info = this->onImageInfo().makeColorType(kN32_SkColorType).makeColorSpace(nullptr); if (!bitmap->tryAllocPixels(info)) { return false; } @@ -315,15 +324,19 @@ sk_sp<SkImage> SkImage::makeWithFilter(const SkImageFilter* filter, const SkIRec if (!filter || !outSubset || !offset || !this->bounds().contains(subset)) { return nullptr; } + SkColorSpace* colorSpace = as_IB(this)->onImageInfo().colorSpace(); + SkDestinationSurfaceColorMode decodeColorMode = colorSpace + ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware + : SkDestinationSurfaceColorMode::kLegacy; sk_sp<SkSpecialImage> srcSpecialImage = SkSpecialImage::MakeFromImage( - subset, sk_ref_sp(const_cast<SkImage*>(this))); + subset, sk_ref_sp(const_cast<SkImage*>(this)), decodeColorMode); if (!srcSpecialImage) { return nullptr; } sk_sp<SkImageFilterCache> cache( SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize)); - SkImageFilter::OutputProperties outputProperties(as_IB(this)->onImageInfo().colorSpace()); + SkImageFilter::OutputProperties outputProperties(colorSpace); SkImageFilter::Context context(SkMatrix::I(), clipBounds, cache.get(), outputProperties); sk_sp<SkSpecialImage> result = diff --git a/src/image/SkImageShader.cpp b/src/image/SkImageShader.cpp index eed817554e..04babb8ec2 100644 --- a/src/image/SkImageShader.cpp +++ b/src/image/SkImageShader.cpp @@ -50,8 +50,12 @@ size_t SkImageShader::onContextSize(const ContextRec& rec) const { } SkShader::Context* SkImageShader::onCreateContext(const ContextRec& rec, void* storage) const { + // TODO: This is wrong. We should be plumbing destination color space to context creation, + // and use that to determine the decoding mode of the image. + SkDestinationSurfaceColorMode decodeColorMode = SkMipMap::DeduceColorMode(rec); return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY, - SkBitmapProvider(fImage.get()), rec, storage); + SkBitmapProvider(fImage.get(), decodeColorMode), + rec, storage); } SkImage* SkImageShader::onIsAImage(SkMatrix* texM, TileMode xy[]) const { diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h index 7fbe97deac..94bf783ed4 100644 --- a/src/image/SkImage_Base.h +++ b/src/image/SkImage_Base.h @@ -52,7 +52,8 @@ public: // return a read-only copy of the pixels. We promise to not modify them, // but only inspect them (or encode them). - virtual bool getROPixels(SkBitmap*, CachingHint = kAllow_CachingHint) const = 0; + virtual bool getROPixels(SkBitmap*, SkDestinationSurfaceColorMode, + CachingHint = kAllow_CachingHint) const = 0; // Caller must call unref when they are done. virtual GrTexture* asTextureRef(GrContext*, const GrTextureParams&, diff --git a/src/image/SkImage_Generator.cpp b/src/image/SkImage_Generator.cpp index 03dda91e5e..43d26d0083 100644 --- a/src/image/SkImage_Generator.cpp +++ b/src/image/SkImage_Generator.cpp @@ -30,7 +30,7 @@ public: SkImageCacherator* peekCacherator() const override { return &fCache; } SkData* onRefEncoded(GrContext*) const override; sk_sp<SkImage> onMakeSubset(const SkIRect&) const override; - bool getROPixels(SkBitmap*, CachingHint) const override; + bool getROPixels(SkBitmap*, SkDestinationSurfaceColorMode, CachingHint) const override; GrTexture* asTextureRef(GrContext*, const GrTextureParams&, SkDestinationSurfaceColorMode) const override; bool onIsLazyGenerated() const override { return true; } @@ -45,9 +45,13 @@ private: bool SkImage_Generator::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, int srcX, int srcY, CachingHint chint) const { + SkDestinationSurfaceColorMode decodeColorMode = dstInfo.colorSpace() + ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware + : SkDestinationSurfaceColorMode::kLegacy; SkBitmap bm; if (kDisallow_CachingHint == chint) { - if (fCache.lockAsBitmapOnlyIfAlreadyCached(&bm)) { + SkImageCacherator::CachedFormat cacheFormat = fCache.chooseCacheFormat(decodeColorMode); + if (fCache.lockAsBitmapOnlyIfAlreadyCached(&bm, cacheFormat)) { return bm.readPixels(dstInfo, dstPixels, dstRB, srcX, srcY); } else { // Try passing the caller's buffer directly down to the generator. If this fails we @@ -60,7 +64,7 @@ bool SkImage_Generator::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels } } - if (this->getROPixels(&bm, chint)) { + if (this->getROPixels(&bm, decodeColorMode, chint)) { return bm.readPixels(dstInfo, dstPixels, dstRB, srcX, srcY); } return false; @@ -70,8 +74,9 @@ SkData* SkImage_Generator::onRefEncoded(GrContext* ctx) const { return fCache.refEncoded(ctx); } -bool SkImage_Generator::getROPixels(SkBitmap* bitmap, CachingHint chint) const { - return fCache.lockAsBitmap(bitmap, this, chint); +bool SkImage_Generator::getROPixels(SkBitmap* bitmap, SkDestinationSurfaceColorMode colorMode, + CachingHint chint) const { + return fCache.lockAsBitmap(bitmap, this, colorMode, chint); } GrTexture* SkImage_Generator::asTextureRef(GrContext* ctx, const GrTextureParams& params, diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp index a006e14ecf..0bcfbd2294 100644 --- a/src/image/SkImage_Gpu.cpp +++ b/src/image/SkImage_Gpu.cpp @@ -20,6 +20,7 @@ #include "SkBitmapCache.h" #include "SkGrPriv.h" #include "SkImage_Gpu.h" +#include "SkImageCacherator.h" #include "SkMipMap.h" #include "SkPixelRef.h" @@ -60,7 +61,8 @@ static SkImageInfo make_info(int w, int h, SkAlphaType at, sk_sp<SkColorSpace> c return SkImageInfo::MakeN32(w, h, at, std::move(colorSpace)); } -bool SkImage_Gpu::getROPixels(SkBitmap* dst, CachingHint chint) const { +bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkDestinationSurfaceColorMode, + CachingHint chint) const { if (SkBitmapCache::Find(this->uniqueID(), dst)) { SkASSERT(dst->getGenerationID() == this->uniqueID()); SkASSERT(dst->isImmutable()); @@ -494,7 +496,19 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox if (!data && !this->peekPixels(nullptr)) { return 0; } - info = as_IB(this)->onImageInfo().makeWH(scaledSize.width(), scaledSize.height()); + if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) { + // Generator backed image. Tweak info to trigger correct kind of decode. + SkDestinationSurfaceColorMode decodeColorMode = dstColorSpace + ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware + : SkDestinationSurfaceColorMode::kLegacy; + SkImageCacherator::CachedFormat cacheFormat = cacher->chooseCacheFormat( + decodeColorMode, proxy.fCaps.get()); + info = cacher->buildCacheInfo(cacheFormat).makeWH(scaledSize.width(), + scaledSize.height()); + + } else { + info = as_IB(this)->onImageInfo().makeWH(scaledSize.width(), scaledSize.height()); + } pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr)); if (fillMode) { pixmap.alloc(info); diff --git a/src/image/SkImage_Gpu.h b/src/image/SkImage_Gpu.h index 13c1e306dc..fbcddf8f1a 100644 --- a/src/image/SkImage_Gpu.h +++ b/src/image/SkImage_Gpu.h @@ -38,7 +38,7 @@ public: } } - bool getROPixels(SkBitmap*, CachingHint) const override; + bool getROPixels(SkBitmap*, SkDestinationSurfaceColorMode, CachingHint) const override; GrTexture* asTextureRef(GrContext* ctx, const GrTextureParams& params, SkDestinationSurfaceColorMode) const override; sk_sp<SkImage> onMakeSubset(const SkIRect&) const override; diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp index be86a2a6ef..149d0a6f65 100644 --- a/src/image/SkImage_Raster.cpp +++ b/src/image/SkImage_Raster.cpp @@ -88,7 +88,7 @@ public: const SkBitmap* onPeekBitmap() const override { return &fBitmap; } SkData* onRefEncoded(GrContext*) const override; - bool getROPixels(SkBitmap*, CachingHint) const override; + bool getROPixels(SkBitmap*, SkDestinationSurfaceColorMode, CachingHint) const override; GrTexture* asTextureRef(GrContext*, const GrTextureParams&, SkDestinationSurfaceColorMode) const override; sk_sp<SkImage> onMakeSubset(const SkIRect&) const override; @@ -192,7 +192,7 @@ SkData* SkImage_Raster::onRefEncoded(GrContext*) const { return nullptr; } -bool SkImage_Raster::getROPixels(SkBitmap* dst, CachingHint) const { +bool SkImage_Raster::getROPixels(SkBitmap* dst, SkDestinationSurfaceColorMode, CachingHint) const { *dst = fBitmap; return true; } diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp index 2d789d04d8..ea6887ac80 100644 --- a/src/pdf/SkPDFBitmap.cpp +++ b/src/pdf/SkPDFBitmap.cpp @@ -17,7 +17,7 @@ #include "SkUnPreMultiply.h" void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) { - if(as_IB(image)->getROPixels(dst) + if(as_IB(image)->getROPixels(dst, SkDestinationSurfaceColorMode::kLegacy) && dst->dimensions() == image->dimensions()) { if (dst->colorType() != kIndex_8_SkColorType) { return; @@ -502,7 +502,8 @@ sk_sp<SkPDFObject> SkPDFCreateBitmapObject(sk_sp<SkImage> image, if (pixelSerializer) { SkBitmap bm; SkAutoPixmapUnlock apu; - if (as_IB(image.get())->getROPixels(&bm) && bm.requestLock(&apu)) { + if (as_IB(image.get())->getROPixels(&bm, SkDestinationSurfaceColorMode::kLegacy) && + bm.requestLock(&apu)) { data.reset(pixelSerializer->encode(apu.pixmap())); if (data && SkIsJFIF(data.get(), &info)) { bool yuv = info.fType == SkJFIFInfo::kYCbCr; diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index a04b380005..9a70f68c31 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -2315,8 +2315,12 @@ sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkBitmap& bitmap) { } sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { + // TODO: See comment above in drawSpecial. The color mode we use for decode should be driven + // by the destination where we're going to draw thing thing (ie this device). But we don't have + // a color space, so we always decode in legacy mode for now. return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->height()), - image->makeNonTextureImage()); + image->makeNonTextureImage(), + SkDestinationSurfaceColorMode::kLegacy); } sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { diff --git a/tests/ImageFilterCacheTest.cpp b/tests/ImageFilterCacheTest.cpp index ebd3186e01..e3a652b06b 100644 --- a/tests/ImageFilterCacheTest.cpp +++ b/tests/ImageFilterCacheTest.cpp @@ -155,11 +155,13 @@ DEF_TEST(ImageFilterCache_RasterBacked, reporter) { static void test_image_backed(skiatest::Reporter* reporter, const sk_sp<SkImage>& srcImage) { const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize); - sk_sp<SkSpecialImage> fullImg(SkSpecialImage::MakeFromImage(full, srcImage)); + sk_sp<SkSpecialImage> fullImg( + SkSpecialImage::MakeFromImage(full, srcImage, SkDestinationSurfaceColorMode::kLegacy)); const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize); - sk_sp<SkSpecialImage> subsetImg(SkSpecialImage::MakeFromImage(subset, srcImage)); + sk_sp<SkSpecialImage> subsetImg( + SkSpecialImage::MakeFromImage(subset, srcImage, SkDestinationSurfaceColorMode::kLegacy)); test_find_existing(reporter, fullImg, subsetImg); test_dont_find_if_diff_key(reporter, fullImg, subsetImg); diff --git a/tests/SkBlend_optsTest.cpp b/tests/SkBlend_optsTest.cpp index e681374852..2ae179c6a9 100644 --- a/tests/SkBlend_optsTest.cpp +++ b/tests/SkBlend_optsTest.cpp @@ -52,7 +52,7 @@ static void test_blender(std::string resourceName, skiatest::Reporter* reporter) return; } SkBitmap bm; - if (!as_IB(image)->getROPixels(&bm)) { + if (!as_IB(image)->getROPixels(&bm, SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware)) { ERRORF(reporter, "Could not read resource"); return; } diff --git a/tests/SpecialImageTest.cpp b/tests/SpecialImageTest.cpp index 62a5da6089..8cd874a3c8 100644 --- a/tests/SpecialImageTest.cpp +++ b/tests/SpecialImageTest.cpp @@ -155,19 +155,20 @@ DEF_TEST(SpecialImage_Raster, reporter) { } } -DEF_TEST(SpecialImage_Image, reporter) { +static void test_specialimage_image(skiatest::Reporter* reporter, + SkDestinationSurfaceColorMode colorMode) { SkBitmap bm = create_bm(); sk_sp<SkImage> fullImage(SkImage::MakeFromBitmap(bm)); sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromImage( SkIRect::MakeWH(kFullSize, kFullSize), - fullImage)); + fullImage, colorMode)); const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize); { - sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromImage(subset, fullImage)); + sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromImage(subset, fullImage, colorMode)); test_image(subSImg1, reporter, nullptr, false, kPad, kFullSize); } @@ -177,6 +178,14 @@ DEF_TEST(SpecialImage_Image, reporter) { } } +DEF_TEST(SpecialImage_Image_Legacy, reporter) { + test_specialimage_image(reporter, SkDestinationSurfaceColorMode::kLegacy); +} + +DEF_TEST(SpecialImage_Image_ColorSpaceAware, reporter) { + test_specialimage_image(reporter, SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware); +} + #if SK_SUPPORT_GPU static void test_texture_backed(skiatest::Reporter* reporter, diff --git a/tools/Resources.cpp b/tools/Resources.cpp index 3a9bb58c4e..981bfba337 100644 --- a/tools/Resources.cpp +++ b/tools/Resources.cpp @@ -30,7 +30,12 @@ bool GetResourceAsBitmap(const char* resource, SkBitmap* dst) { SkString resourcePath = GetResourcePath(resource); sk_sp<SkData> resourceData(SkData::MakeFromFileName(resourcePath.c_str())); std::unique_ptr<SkImageGenerator> gen(SkImageGenerator::NewFromEncoded(resourceData.get())); - return gen && gen->tryGenerateBitmap(dst); + SkPMColor ctStorage[256]; + sk_sp<SkColorTable> ctable(new SkColorTable(ctStorage, 256)); + int count = ctable->count(); + return dst->tryAllocPixels(gen->getInfo(), nullptr, ctable.get()) && + gen->getPixels(gen->getInfo().makeColorSpace(nullptr), dst->getPixels(), dst->rowBytes(), + const_cast<SkPMColor*>(ctable->readColors()), &count); } sk_sp<SkImage> GetResourceAsImage(const char* resource) { |