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. Re-land (and fix) of: https://skia-review.googlesource.com/c/4438/ https://skia-review.googlesource.com/c/4796/ BUG=skia:5907 GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4838 Change-Id: I20ff972ffe1c7e6535ddc501e2a8ab8c246e4061 Reviewed-on: https://skia-review.googlesource.com/4838 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: Matt Sarett <msarett@google.com>
This commit is contained in:
parent
dc940a63c4
commit
7992da32f0
@ -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);
|
||||
|
@ -308,15 +308,18 @@ 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);
|
||||
}
|
||||
|
||||
static void draw_as_tex(SkCanvas* canvas, SkImageCacherator* cache, SkScalar x, SkScalar y) {
|
||||
#if SK_SUPPORT_GPU
|
||||
sk_sp<SkColorSpace> texColorSpace;
|
||||
sk_sp<GrTexture> texture(
|
||||
cache->lockAsTexture(canvas->getGrContext(), GrSamplerParams::ClampBilerp(),
|
||||
SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware, nullptr));
|
||||
SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware,
|
||||
&texColorSpace, nullptr));
|
||||
if (!texture) {
|
||||
// show placeholder if we have no texture
|
||||
SkPaint paint;
|
||||
@ -331,8 +334,7 @@ protected:
|
||||
// No API to draw a GrTexture directly, so we cheat and create a private image subclass
|
||||
sk_sp<SkImage> image(new SkImage_Gpu(cache->info().width(), cache->info().height(),
|
||||
cache->uniqueID(), kPremul_SkAlphaType,
|
||||
std::move(texture),
|
||||
sk_ref_sp(cache->info().colorSpace()),
|
||||
std::move(texture), std::move(texColorSpace),
|
||||
SkBudgeted::kNo));
|
||||
canvas->drawImage(image.get(), x, y);
|
||||
#endif
|
||||
|
@ -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:
|
||||
|
@ -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() {
|
||||
|
@ -45,7 +45,7 @@ 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);
|
||||
}
|
||||
|
||||
bool SkBitmapProvider::accessScaledImage(const SkRect& srcRect,
|
||||
|
@ -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;
|
||||
@ -44,7 +49,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
|
||||
|
@ -209,8 +209,11 @@ bool SkBaseDevice::drawExternallyScaledImage(const SkDraw& draw,
|
||||
return false;
|
||||
}
|
||||
|
||||
SkDestinationSurfaceColorMode colorMode = this->imageInfo().colorSpace()
|
||||
? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware
|
||||
: SkDestinationSurfaceColorMode::kLegacy;
|
||||
SkBitmap bm;
|
||||
if (!as_IB(rec.fImage)->getROPixels(&bm)) {
|
||||
if (!as_IB(rec.fImage)->getROPixels(&bm, colorMode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -226,15 +229,17 @@ bool SkBaseDevice::drawExternallyScaledImage(const SkDraw& draw,
|
||||
void SkBaseDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x, SkScalar y,
|
||||
const SkPaint& paint) {
|
||||
// Default impl : turns everything into raster bitmap
|
||||
|
||||
if (this->drawExternallyScaledImage(draw, image, nullptr,
|
||||
SkRect::Make(image->bounds()).makeOffset(x, y),
|
||||
paint, SkCanvas::kFast_SrcRectConstraint)) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -243,13 +248,15 @@ 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
|
||||
|
||||
if (this->drawExternallyScaledImage(draw, image, src, dst, paint, constraint)) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "SkBitmap.h"
|
||||
#include "SkBitmapCache.h"
|
||||
#include "SkColorSpace_Base.h"
|
||||
#include "SkImage_Base.h"
|
||||
#include "SkImageCacherator.h"
|
||||
#include "SkMallocPixelRef.h"
|
||||
@ -86,6 +87,17 @@ SkImageCacherator::Validator::Validator(sk_sp<SharedGenerator> gen, const SkIRec
|
||||
|
||||
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(),
|
||||
@ -166,22 +184,28 @@ bool SkImageCacherator::directAccessScaledImage(const SkRect& srcRect,
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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();
|
||||
}
|
||||
@ -190,9 +214,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 = this->chooseCacheFormat(colorMode);
|
||||
SkImageInfo cacheInfo = this->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
|
||||
@ -201,7 +233,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) {
|
||||
@ -209,27 +242,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
|
||||
@ -237,7 +270,190 @@ bool SkImageCacherator::lockAsBitmap(SkBitmap* bitmap, const SkImage* client,
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 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. In theory, we only need the
|
||||
// chosen format to be texturable, but that lets us choose F16 on GLES implemenations where we
|
||||
// won't be able to read the texture back. We'd like to ensure that SkImake::makeNonTextureImage
|
||||
// works, so we require that the formats we choose are renderable (as a proxy for being readable).
|
||||
struct CacheCaps {
|
||||
CacheCaps(const GrCaps* caps) : fCaps(caps) {}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
bool supportsHalfFloat() const {
|
||||
return !fCaps ||
|
||||
(fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) &&
|
||||
fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig, false));
|
||||
}
|
||||
|
||||
bool supportsSRGB() const {
|
||||
return !fCaps ||
|
||||
(fCaps->srgbSupport() && fCaps->isConfigTexturable(kSRGBA_8888_GrPixelConfig));
|
||||
}
|
||||
|
||||
bool supportsSBGR() const {
|
||||
return !fCaps || fCaps->srgbSupport();
|
||||
}
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
void SkImageCacherator::makeCacheKeyFromOrigKey(const GrUniqueKey& origKey, CachedFormat format,
|
||||
GrUniqueKey* cacheKey) {
|
||||
SkASSERT(!cacheKey->isValid());
|
||||
if (origKey.isValid()) {
|
||||
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
|
||||
GrUniqueKey::Builder builder(cacheKey, origKey, kDomain, 1);
|
||||
builder[0] = format;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
|
||||
static GrTexture* load_compressed_into_texture(GrContext* ctx, SkData* data, GrSurfaceDesc desc) {
|
||||
@ -275,6 +491,16 @@ static GrTexture* set_key_and_return(GrTexture* tex, const GrUniqueKey& key) {
|
||||
return tex;
|
||||
}
|
||||
|
||||
sk_sp<SkColorSpace> SkImageCacherator::getColorSpace(GrContext* ctx,
|
||||
SkDestinationSurfaceColorMode colorMode) {
|
||||
// TODO: This isn't always correct. Picture generator currently produces textures in N32,
|
||||
// and will (soon) emit them in an arbitrary (destination) space. We will need to stash that
|
||||
// information in/on the key so we can return the correct space in case #1 of lockTexture.
|
||||
CachedFormat format = this->chooseCacheFormat(colorMode, ctx->caps());
|
||||
SkImageInfo cacheInfo = this->buildCacheInfo(format);
|
||||
return sk_ref_sp(cacheInfo.colorSpace());
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a 5 ways to try to return a texture (in sorted order)
|
||||
*
|
||||
@ -284,7 +510,7 @@ static GrTexture* set_key_and_return(GrTexture* tex, const GrUniqueKey& key) {
|
||||
* 4. Ask the generator to return YUV planes, which the GPU can convert
|
||||
* 5. Ask the generator to return RGB(A) data, which the GPU can convert
|
||||
*/
|
||||
GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key,
|
||||
GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& origKey,
|
||||
const SkImage* client, SkImage::CachingHint chint,
|
||||
bool willBeMipped,
|
||||
SkDestinationSurfaceColorMode colorMode) {
|
||||
@ -301,6 +527,14 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key
|
||||
|
||||
enum { kLockTexturePathCount = kRGBA_LockTexturePath + 1 };
|
||||
|
||||
// Determine which cached format we're going to use (which may involve decoding to a different
|
||||
// info than the generator provides).
|
||||
CachedFormat format = this->chooseCacheFormat(colorMode, ctx->caps());
|
||||
|
||||
// Fold the cache format into our texture key
|
||||
GrUniqueKey key;
|
||||
this->makeCacheKeyFromOrigKey(origKey, format, &key);
|
||||
|
||||
// 1. Check the cache for a pre-existing one
|
||||
if (key.isValid()) {
|
||||
if (GrTexture* tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(key)) {
|
||||
@ -321,7 +555,12 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key
|
||||
}
|
||||
}
|
||||
|
||||
const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(fInfo, *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 = this->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
|
||||
@ -350,7 +589,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);
|
||||
@ -373,18 +612,21 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key
|
||||
|
||||
GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrSamplerParams& params,
|
||||
SkDestinationSurfaceColorMode colorMode,
|
||||
sk_sp<SkColorSpace>* texColorSpace,
|
||||
const SkImage* client, SkImage::CachingHint chint) {
|
||||
if (!ctx) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return GrImageTextureMaker(ctx, this, client, chint).refTextureForParams(params, colorMode);
|
||||
return GrImageTextureMaker(ctx, this, client, chint).refTextureForParams(params, colorMode,
|
||||
texColorSpace);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrSamplerParams&,
|
||||
SkDestinationSurfaceColorMode colorMode,
|
||||
sk_sp<SkColorSpace>* texColorSpace,
|
||||
const SkImage* client, SkImage::CachingHint) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "SkMutex.h"
|
||||
#include "SkTemplates.h"
|
||||
|
||||
class GrCaps;
|
||||
class GrContext;
|
||||
class GrSamplerParams;
|
||||
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);
|
||||
|
||||
/**
|
||||
@ -51,7 +61,8 @@ public:
|
||||
* The caller is responsible for calling texture->unref() when they are done.
|
||||
*/
|
||||
GrTexture* lockAsTexture(GrContext*, const GrSamplerParams&,
|
||||
SkDestinationSurfaceColorMode colorMode, const SkImage* client,
|
||||
SkDestinationSurfaceColorMode colorMode,
|
||||
sk_sp<SkColorSpace>* texColorSpace, const SkImage* client,
|
||||
SkImage::CachingHint = SkImage::kAllow_CachingHint);
|
||||
|
||||
/**
|
||||
@ -64,7 +75,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);
|
||||
@ -105,19 +116,28 @@ private:
|
||||
|
||||
SkImageCacherator(Validator*);
|
||||
|
||||
bool generateBitmap(SkBitmap*);
|
||||
bool tryLockAsBitmap(SkBitmap*, const SkImage*, SkImage::CachingHint);
|
||||
CachedFormat chooseCacheFormat(SkDestinationSurfaceColorMode, const GrCaps* = nullptr);
|
||||
SkImageInfo buildCacheInfo(CachedFormat);
|
||||
|
||||
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);
|
||||
// Returns the color space of the texture that would be returned if you called lockTexture.
|
||||
// Separate code path to allow querying of the color space for textures that cached (even
|
||||
// externally).
|
||||
sk_sp<SkColorSpace> getColorSpace(GrContext*, SkDestinationSurfaceColorMode);
|
||||
void makeCacheKeyFromOrigKey(const GrUniqueKey& origKey, CachedFormat, GrUniqueKey* cacheKey);
|
||||
#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;
|
||||
|
@ -139,7 +139,8 @@ public:
|
||||
// gets deleted when the ShadowFP is destroyed, and frees the GrTexture*
|
||||
fTexture[fNumNonAmbLights] = sk_sp<GrTexture>(shadowMap->asTextureRef(context,
|
||||
GrSamplerParams::ClampNoFilter(),
|
||||
SkDestinationSurfaceColorMode::kLegacy));
|
||||
SkDestinationSurfaceColorMode::kLegacy,
|
||||
nullptr));
|
||||
fDepthMapSampler[fNumNonAmbLights].reset(fTexture[fNumNonAmbLights].get());
|
||||
this->addTextureSampler(&fDepthMapSampler[fNumNonAmbLights]);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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&,
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,9 @@ GrTexture* GrBitmapTextureMaker::refOriginalTexture(bool willBeMipped,
|
||||
return tex;
|
||||
}
|
||||
|
||||
void GrBitmapTextureMaker::makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) {
|
||||
void GrBitmapTextureMaker::makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey,
|
||||
SkDestinationSurfaceColorMode colorMode) {
|
||||
// Color mode is irrelevant in this case - we always upload the bitmap's contents as-is
|
||||
if (fOriginalKey.isValid()) {
|
||||
MakeCopyKeyFromOrigKey(fOriginalKey, copyParams, copyKey);
|
||||
}
|
||||
@ -66,8 +68,9 @@ SkAlphaType GrBitmapTextureMaker::alphaType() const {
|
||||
return fBitmap.alphaType();
|
||||
}
|
||||
|
||||
SkColorSpace* GrBitmapTextureMaker::getColorSpace() {
|
||||
return fBitmap.colorSpace();
|
||||
sk_sp<SkColorSpace> GrBitmapTextureMaker::getColorSpace(SkDestinationSurfaceColorMode colorMode) {
|
||||
// Color space doesn't depend on mode - it's just whatever is in the bitmap
|
||||
return sk_ref_sp(fBitmap.colorSpace());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@ -93,9 +96,14 @@ GrTexture* GrImageTextureMaker::refOriginalTexture(bool willBeMipped,
|
||||
colorMode);
|
||||
}
|
||||
|
||||
void GrImageTextureMaker::makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey) {
|
||||
void GrImageTextureMaker::makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey,
|
||||
SkDestinationSurfaceColorMode colorMode) {
|
||||
if (fOriginalKey.isValid() && SkImage::kAllow_CachingHint == fCachingHint) {
|
||||
MakeCopyKeyFromOrigKey(fOriginalKey, stretch, paramsCopyKey);
|
||||
SkImageCacherator::CachedFormat cacheFormat =
|
||||
fCacher->chooseCacheFormat(colorMode, this->context()->caps());
|
||||
GrUniqueKey cacheKey;
|
||||
fCacher->makeCacheKeyFromOrigKey(fOriginalKey, cacheFormat, &cacheKey);
|
||||
MakeCopyKeyFromOrigKey(cacheKey, stretch, paramsCopyKey);
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,7 +116,6 @@ void GrImageTextureMaker::didCacheCopy(const GrUniqueKey& copyKey) {
|
||||
SkAlphaType GrImageTextureMaker::alphaType() const {
|
||||
return fCacher->info().alphaType();
|
||||
}
|
||||
|
||||
SkColorSpace* GrImageTextureMaker::getColorSpace() {
|
||||
return fCacher->info().colorSpace();
|
||||
sk_sp<SkColorSpace> GrImageTextureMaker::getColorSpace(SkDestinationSurfaceColorMode colorMode) {
|
||||
return fCacher->getColorSpace(this->context(), colorMode);
|
||||
}
|
||||
|
@ -25,12 +25,13 @@ public:
|
||||
protected:
|
||||
GrTexture* refOriginalTexture(bool willBeMipped, SkDestinationSurfaceColorMode) override;
|
||||
|
||||
void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) override;
|
||||
void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey,
|
||||
SkDestinationSurfaceColorMode colorMode) override;
|
||||
|
||||
void didCacheCopy(const GrUniqueKey& copyKey) override;
|
||||
|
||||
SkAlphaType alphaType() const override;
|
||||
SkColorSpace* getColorSpace() override;
|
||||
sk_sp<SkColorSpace> getColorSpace(SkDestinationSurfaceColorMode) override;
|
||||
|
||||
private:
|
||||
const SkBitmap fBitmap;
|
||||
@ -52,11 +53,12 @@ protected:
|
||||
// GrTexture* generateTextureForParams(const CopyParams&) override;
|
||||
|
||||
GrTexture* refOriginalTexture(bool willBeMipped, SkDestinationSurfaceColorMode) override;
|
||||
void makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey) override;
|
||||
void makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey,
|
||||
SkDestinationSurfaceColorMode colorMode) override;
|
||||
void didCacheCopy(const GrUniqueKey& copyKey) override;
|
||||
|
||||
SkAlphaType alphaType() const override;
|
||||
SkColorSpace* getColorSpace() override;
|
||||
sk_sp<SkColorSpace> getColorSpace(SkDestinationSurfaceColorMode) override;
|
||||
|
||||
private:
|
||||
SkImageCacherator* fCacher;
|
||||
|
@ -105,7 +105,9 @@ GrTextureAdjuster::GrTextureAdjuster(GrTexture* original, SkAlphaType alphaType,
|
||||
}
|
||||
}
|
||||
|
||||
void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) {
|
||||
void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey,
|
||||
SkDestinationSurfaceColorMode) {
|
||||
// Color mode is irrelevant in this case - we already have a texture so we're just sub-setting
|
||||
GrUniqueKey baseKey;
|
||||
GrMakeKeyFromImageID(&baseKey, fUniqueID, SkIRect::MakeWH(this->width(), this->height()));
|
||||
MakeCopyKeyFromOrigKey(baseKey, params, copyKey);
|
||||
@ -115,16 +117,12 @@ void GrTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey) {
|
||||
// We don't currently have a mechanism for notifications on Images!
|
||||
}
|
||||
|
||||
SkColorSpace* GrTextureAdjuster::getColorSpace() {
|
||||
return fColorSpace;
|
||||
}
|
||||
|
||||
GrTexture* GrTextureAdjuster::refCopy(const CopyParams& copyParams) {
|
||||
GrTexture* texture = this->originalTexture();
|
||||
GrContext* context = texture->getContext();
|
||||
const SkIRect* contentArea = this->contentAreaOrNull();
|
||||
GrUniqueKey key;
|
||||
this->makeCopyKey(copyParams, &key);
|
||||
this->makeCopyKey(copyParams, &key, SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware);
|
||||
if (key.isValid()) {
|
||||
GrTexture* cachedCopy = context->textureProvider()->findAndRefTextureByUniqueKey(key);
|
||||
if (cachedCopy) {
|
||||
@ -421,7 +419,7 @@ sk_sp<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
|
||||
SkASSERT(kNoDomain_DomainMode == domainMode ||
|
||||
(domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom));
|
||||
textureMatrix.postIDiv(texture->width(), texture->height());
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(this->getColorSpace(),
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace,
|
||||
dstColorSpace);
|
||||
return create_fp_for_domain_and_filter(texture.get(), std::move(colorSpaceXform), textureMatrix,
|
||||
domainMode, domain, filterOrNullForBicubic);
|
||||
@ -430,7 +428,8 @@ sk_sp<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrTexture* GrTextureMaker::refTextureForParams(const GrSamplerParams& params,
|
||||
SkDestinationSurfaceColorMode colorMode) {
|
||||
SkDestinationSurfaceColorMode colorMode,
|
||||
sk_sp<SkColorSpace>* texColorSpace) {
|
||||
CopyParams copyParams;
|
||||
bool willBeMipped = params.filterMode() == GrSamplerParams::kMipMap_FilterMode;
|
||||
|
||||
@ -438,12 +437,16 @@ GrTexture* GrTextureMaker::refTextureForParams(const GrSamplerParams& params,
|
||||
willBeMipped = false;
|
||||
}
|
||||
|
||||
if (texColorSpace) {
|
||||
*texColorSpace = this->getColorSpace(colorMode);
|
||||
}
|
||||
|
||||
if (!fContext->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params,
|
||||
©Params)) {
|
||||
return this->refOriginalTexture(willBeMipped, colorMode);
|
||||
}
|
||||
GrUniqueKey copyKey;
|
||||
this->makeCopyKey(copyParams, ©Key);
|
||||
this->makeCopyKey(copyParams, ©Key, colorMode);
|
||||
if (copyKey.isValid()) {
|
||||
GrTexture* result = fContext->textureProvider()->findAndRefTextureByUniqueKey(copyKey);
|
||||
if (result) {
|
||||
@ -491,7 +494,8 @@ sk_sp<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor(
|
||||
// Bicubic doesn't use filtering for it's texture accesses.
|
||||
params.reset(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
|
||||
}
|
||||
sk_sp<GrTexture> texture(this->refTextureForParams(params, colorMode));
|
||||
sk_sp<SkColorSpace> texColorSpace;
|
||||
sk_sp<GrTexture> texture(this->refTextureForParams(params, colorMode, &texColorSpace));
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -503,7 +507,7 @@ sk_sp<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor(
|
||||
SkASSERT(kTightCopy_DomainMode != domainMode);
|
||||
SkMatrix normalizedTextureMatrix = textureMatrix;
|
||||
normalizedTextureMatrix.postIDiv(texture->width(), texture->height());
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(this->getColorSpace(),
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(),
|
||||
dstColorSpace);
|
||||
return create_fp_for_domain_and_filter(texture.get(), std::move(colorSpaceXform),
|
||||
normalizedTextureMatrix, domainMode, domain,
|
||||
|
@ -74,7 +74,6 @@ public:
|
||||
int height() const { return fHeight; }
|
||||
bool isAlphaOnly() const { return fIsAlphaOnly; }
|
||||
virtual SkAlphaType alphaType() const = 0;
|
||||
virtual SkColorSpace* getColorSpace() = 0;
|
||||
|
||||
protected:
|
||||
GrTextureProducer(int width, int height, bool isAlphaOnly)
|
||||
@ -100,9 +99,11 @@ protected:
|
||||
* If we need to make a copy in order to be compatible with GrTextureParams producer is asked to
|
||||
* return a key that identifies its original content + the CopyParms parameter. If the producer
|
||||
* does not want to cache the stretched version (e.g. the producer is volatile), this should
|
||||
* simply return without initializing the copyKey.
|
||||
* simply return without initializing the copyKey. If the texture generated by this producer
|
||||
* depends on colorMode, then that information should also be incorporated in the key.
|
||||
*/
|
||||
virtual void makeCopyKey(const CopyParams&, GrUniqueKey* copyKey) = 0;
|
||||
virtual void makeCopyKey(const CopyParams&, GrUniqueKey* copyKey,
|
||||
SkDestinationSurfaceColorMode colorMode) = 0;
|
||||
|
||||
/**
|
||||
* If a stretched version of the texture is generated, it may be cached (assuming that
|
||||
@ -150,8 +151,8 @@ public:
|
||||
|
||||
protected:
|
||||
SkAlphaType alphaType() const override { return fAlphaType; }
|
||||
SkColorSpace* getColorSpace() override;
|
||||
void makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) override;
|
||||
void makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey,
|
||||
SkDestinationSurfaceColorMode colorMode) override;
|
||||
void didCacheCopy(const GrUniqueKey& copyKey) override;
|
||||
|
||||
GrTexture* originalTexture() const { return fOriginal; }
|
||||
@ -177,10 +178,13 @@ private:
|
||||
*/
|
||||
class GrTextureMaker : public GrTextureProducer {
|
||||
public:
|
||||
/** Returns a texture that is safe for use with the params. If the size of the returned texture
|
||||
does not match width()/height() then the contents of the original must be scaled to fit
|
||||
the texture. */
|
||||
GrTexture* refTextureForParams(const GrSamplerParams&, SkDestinationSurfaceColorMode);
|
||||
/**
|
||||
* Returns a texture that is safe for use with the params. If the size of the returned texture
|
||||
* does not match width()/height() then the contents of the original must be scaled to fit
|
||||
* the texture. Places the color space of the texture in (*texColorSpace).
|
||||
*/
|
||||
GrTexture* refTextureForParams(const GrSamplerParams&, SkDestinationSurfaceColorMode,
|
||||
sk_sp<SkColorSpace>* texColorSpace);
|
||||
|
||||
sk_sp<GrFragmentProcessor> createFragmentProcessor(
|
||||
const SkMatrix& textureMatrix,
|
||||
@ -202,6 +206,12 @@ protected:
|
||||
*/
|
||||
virtual GrTexture* refOriginalTexture(bool willBeMipped, SkDestinationSurfaceColorMode) = 0;
|
||||
|
||||
/**
|
||||
* Returns the color space of the maker's "original" texture, assuming it was retrieved with
|
||||
* the same destination color mode.
|
||||
*/
|
||||
virtual sk_sp<SkColorSpace> getColorSpace(SkDestinationSurfaceColorMode) = 0;
|
||||
|
||||
/**
|
||||
* Return a new (uncached) texture that is the stretch of the maker's original.
|
||||
*
|
||||
|
@ -1383,7 +1383,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);
|
||||
@ -1392,7 +1392,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);
|
||||
}
|
||||
}
|
||||
@ -1417,7 +1417,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);
|
||||
@ -1425,7 +1425,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);
|
||||
}
|
||||
}
|
||||
@ -1487,7 +1487,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);
|
||||
}
|
||||
}
|
||||
@ -1542,7 +1542,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);
|
||||
}
|
||||
}
|
||||
|
@ -426,13 +426,16 @@ GrTexture* GrUploadMipMapToTexture(GrContext* ctx, const SkImageInfo& info,
|
||||
GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap,
|
||||
const GrSamplerParams& params,
|
||||
SkDestinationSurfaceColorMode colorMode) {
|
||||
return GrBitmapTextureMaker(ctx, bitmap).refTextureForParams(params, colorMode);
|
||||
// Caller doesn't care about the texture's color space (they can always get it from the bitmap)
|
||||
return GrBitmapTextureMaker(ctx, bitmap).refTextureForParams(params, colorMode, nullptr);
|
||||
}
|
||||
|
||||
sk_sp<GrTexture> GrMakeCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap,
|
||||
const GrSamplerParams& params,
|
||||
SkDestinationSurfaceColorMode colorMode) {
|
||||
GrTexture* tex = GrBitmapTextureMaker(ctx, bitmap).refTextureForParams(params, colorMode);
|
||||
// Caller doesn't care about the texture's color space (they can always get it from the bitmap)
|
||||
GrTexture* tex = GrBitmapTextureMaker(ctx, bitmap).refTextureForParams(params, colorMode,
|
||||
nullptr);
|
||||
return sk_sp<GrTexture>(tex);
|
||||
}
|
||||
|
||||
|
@ -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 =
|
||||
|
@ -52,8 +52,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 {
|
||||
@ -211,13 +215,14 @@ sk_sp<GrFragmentProcessor> SkImageShader::asFragmentProcessor(const AsFPArgs& ar
|
||||
GrSkFilterQualityToGrFilterMode(args.fFilterQuality, *args.fViewMatrix, this->getLocalMatrix(),
|
||||
&doBicubic);
|
||||
GrSamplerParams params(tm, textureFilterMode);
|
||||
sk_sp<GrTexture> texture(as_IB(fImage)->asTextureRef(args.fContext, params, args.fColorMode));
|
||||
sk_sp<SkColorSpace> texColorSpace;
|
||||
sk_sp<GrTexture> texture(as_IB(fImage)->asTextureRef(args.fContext, params, args.fColorMode,
|
||||
&texColorSpace));
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkImageInfo info = as_IB(fImage)->onImageInfo();
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(info.colorSpace(),
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(),
|
||||
args.fDstColorSpace);
|
||||
sk_sp<GrFragmentProcessor> inner;
|
||||
if (doBicubic) {
|
||||
|
@ -52,11 +52,12 @@ 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 GrSamplerParams&,
|
||||
SkDestinationSurfaceColorMode) const = 0;
|
||||
SkDestinationSurfaceColorMode, sk_sp<SkColorSpace>*) const = 0;
|
||||
|
||||
virtual sk_sp<SkImage> onMakeSubset(const SkIRect&) const = 0;
|
||||
|
||||
|
@ -30,9 +30,9 @@ 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 GrSamplerParams&,
|
||||
SkDestinationSurfaceColorMode) const override;
|
||||
SkDestinationSurfaceColorMode, sk_sp<SkColorSpace>*) const override;
|
||||
bool onIsLazyGenerated() const override { return true; }
|
||||
|
||||
private:
|
||||
@ -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,13 +74,15 @@ 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 GrSamplerParams& params,
|
||||
SkDestinationSurfaceColorMode colorMode) const {
|
||||
return fCache.lockAsTexture(ctx, params, colorMode, this);
|
||||
SkDestinationSurfaceColorMode colorMode,
|
||||
sk_sp<SkColorSpace>* texColorSpace) const {
|
||||
return fCache.lockAsTexture(ctx, params, colorMode, texColorSpace, this);
|
||||
}
|
||||
|
||||
sk_sp<SkImage> SkImage_Generator::onMakeSubset(const SkIRect& subset) const {
|
||||
|
@ -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());
|
||||
@ -86,9 +88,13 @@ bool SkImage_Gpu::getROPixels(SkBitmap* dst, CachingHint chint) const {
|
||||
}
|
||||
|
||||
GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrSamplerParams& params,
|
||||
SkDestinationSurfaceColorMode colorMode) const {
|
||||
GrTextureAdjuster adjuster(this->peekTexture(), this->alphaType(), this->bounds(), this->uniqueID(),
|
||||
this->onImageInfo().colorSpace());
|
||||
SkDestinationSurfaceColorMode colorMode,
|
||||
sk_sp<SkColorSpace>* texColorSpace) const {
|
||||
if (texColorSpace) {
|
||||
*texColorSpace = this->fColorSpace;
|
||||
}
|
||||
GrTextureAdjuster adjuster(this->peekTexture(), this->alphaType(), this->bounds(),
|
||||
this->uniqueID(), this->fColorSpace.get());
|
||||
return adjuster.refTextureSafeForParams(params, colorMode, nullptr);
|
||||
}
|
||||
|
||||
@ -298,14 +304,16 @@ sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace
|
||||
}
|
||||
|
||||
static sk_sp<SkImage> create_image_from_maker(GrTextureMaker* maker, SkAlphaType at, uint32_t id) {
|
||||
sk_sp<SkColorSpace> texColorSpace;
|
||||
sk_sp<GrTexture> texture(
|
||||
maker->refTextureForParams(GrSamplerParams::ClampNoFilter(),
|
||||
SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware));
|
||||
SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware,
|
||||
&texColorSpace));
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
return sk_make_sp<SkImage_Gpu>(texture->width(), texture->height(), id, at, std::move(texture),
|
||||
sk_ref_sp(maker->getColorSpace()), SkBudgeted::kNo);
|
||||
std::move(texColorSpace), SkBudgeted::kNo);
|
||||
}
|
||||
|
||||
sk_sp<SkImage> SkImage::makeTextureImage(GrContext *context) const {
|
||||
@ -498,7 +506,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);
|
||||
|
@ -38,9 +38,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool getROPixels(SkBitmap*, CachingHint) const override;
|
||||
bool getROPixels(SkBitmap*, SkDestinationSurfaceColorMode, CachingHint) const override;
|
||||
GrTexture* asTextureRef(GrContext* ctx, const GrSamplerParams& params,
|
||||
SkDestinationSurfaceColorMode) const override;
|
||||
SkDestinationSurfaceColorMode, sk_sp<SkColorSpace>*) const override;
|
||||
sk_sp<SkImage> onMakeSubset(const SkIRect&) const override;
|
||||
|
||||
GrTexture* peekTexture() const override { return fTexture.get(); }
|
||||
|
@ -88,9 +88,9 @@ 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 GrSamplerParams&,
|
||||
SkDestinationSurfaceColorMode) const override;
|
||||
SkDestinationSurfaceColorMode, sk_sp<SkColorSpace>*) const override;
|
||||
sk_sp<SkImage> onMakeSubset(const SkIRect&) const override;
|
||||
|
||||
// exposed for SkSurface_Raster via SkNewImageFromPixelRef
|
||||
@ -192,18 +192,23 @@ 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;
|
||||
}
|
||||
|
||||
GrTexture* SkImage_Raster::asTextureRef(GrContext* ctx, const GrSamplerParams& params,
|
||||
SkDestinationSurfaceColorMode colorMode) const {
|
||||
SkDestinationSurfaceColorMode colorMode,
|
||||
sk_sp<SkColorSpace>* texColorSpace) const {
|
||||
#if SK_SUPPORT_GPU
|
||||
if (!ctx) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (texColorSpace) {
|
||||
*texColorSpace = sk_ref_sp(fBitmap.colorSpace());
|
||||
}
|
||||
|
||||
uint32_t uniqueID;
|
||||
sk_sp<GrTexture> tex = this->refPinnedTexture(&uniqueID);
|
||||
if (tex) {
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -43,7 +43,8 @@ static void assert_equal(skiatest::Reporter* reporter, SkImage* a, const SkIRect
|
||||
// see https://bug.skia.org/3965
|
||||
//REPORTER_ASSERT(reporter, a->isOpaque() == b->isOpaque());
|
||||
|
||||
SkImageInfo info = SkImageInfo::MakeN32(widthA, heightA, a->alphaType());
|
||||
// The codecs may have given us back F16, we can't read from F16 raster to N32, only S32.
|
||||
SkImageInfo info = SkImageInfo::MakeS32(widthA, heightA, a->alphaType());
|
||||
SkAutoPixmapStorage pmapA, pmapB;
|
||||
pmapA.alloc(info);
|
||||
pmapB.alloc(info);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user