aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/image
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 /src/image
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>
Diffstat (limited to 'src/image')
-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
7 files changed, 57 insertions, 20 deletions
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;
}