aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brian Osman <brianosman@google.com>2016-11-14 15:09:56 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2016-11-15 15:27:14 +0000
commitc73a1ecbed64652b3d7aa8dc6face9a2205ce830 (patch)
tree59e66c879ca0d1ab68720ccae740cecb2d5660ef
parentfd01ce05ef7902c49b0272b3524a389693c72b35 (diff)
Support decoding images to multiple formats, depending on usage
Our codec generator will now preserve any asked-for color space, and convert the encoded data to that representation. Cacherator now allows decoding an image to both legacy (nullptr color space), and color-correct formats. In color-correct mode, we choose the best decoded format, based on the original properties, and our backend's capabilities. Preference is given to the native format, when it's already texturable (sRGB 8888 or F16 linear). Otherwise, we prefer linear F16, and fall back to sRGB when that's not an option. BUG=skia:5907 GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4438 Change-Id: I847c243dcfb72d8c0f1f6fc73c09547adea933f0 Reviewed-on: https://skia-review.googlesource.com/4438 Reviewed-by: Matt Sarett <msarett@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
-rw-r--r--bench/SkBlend_optsBench.cpp2
-rw-r--r--gm/image_pict.cpp3
-rw-r--r--src/codec/SkCodecImageGenerator.cpp8
-rw-r--r--src/core/SkBitmapDevice.cpp7
-rw-r--r--src/core/SkBitmapProvider.cpp2
-rw-r--r--src/core/SkBitmapProvider.h10
-rw-r--r--src/core/SkDevice.cpp10
-rw-r--r--src/core/SkImageCacherator.cpp255
-rw-r--r--src/core/SkImageCacherator.h25
-rw-r--r--src/core/SkSpecialImage.cpp3
-rw-r--r--src/core/SkSpecialImage.h1
-rw-r--r--src/effects/SkImageSource.cpp4
-rw-r--r--src/gpu/SkGpuDevice.cpp12
-rw-r--r--src/image/SkImage.cpp29
-rw-r--r--src/image/SkImageShader.cpp6
-rw-r--r--src/image/SkImage_Base.h3
-rw-r--r--src/image/SkImage_Generator.cpp15
-rw-r--r--src/image/SkImage_Gpu.cpp18
-rw-r--r--src/image/SkImage_Gpu.h2
-rw-r--r--src/image/SkImage_Raster.cpp4
-rw-r--r--src/pdf/SkPDFBitmap.cpp5
-rw-r--r--src/pdf/SkPDFDevice.cpp6
-rw-r--r--tests/ImageFilterCacheTest.cpp6
-rw-r--r--tests/SkBlend_optsTest.cpp2
-rw-r--r--tests/SpecialImageTest.cpp15
-rw-r--r--tools/Resources.cpp7
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) {