aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-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) {