Add alphaType() to SkImage
Keep isOpaque as a convenience method -- many places really only need to know that for optimization purposes (SrcOver -> Src, etc...). In all the places where we pull data back out or convert to another object and need to supply an SkImageInfo, we can avoid losing information about premulness. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2250663002 Review-Url: https://codereview.chromium.org/2250663002
This commit is contained in:
parent
a7eaf2e7e8
commit
69c166d2ce
@ -303,8 +303,7 @@ DEF_GM( return new ScalePixelsGM; )
|
||||
#include "SkImageGenerator.h"
|
||||
|
||||
static SkImageInfo make_info(SkImage* img) {
|
||||
return SkImageInfo::MakeN32(img->width(), img->height(),
|
||||
img->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
|
||||
return SkImageInfo::MakeN32(img->width(), img->height(), img->alphaType());
|
||||
}
|
||||
|
||||
// Its simple, but I wonder if we should expose this formally?
|
||||
|
@ -166,7 +166,8 @@ public:
|
||||
SkISize dimensions() const { return SkISize::Make(fWidth, fHeight); }
|
||||
SkIRect bounds() const { return SkIRect::MakeWH(fWidth, fHeight); }
|
||||
uint32_t uniqueID() const { return fUniqueID; }
|
||||
virtual bool isOpaque() const { return false; }
|
||||
SkAlphaType alphaType() const;
|
||||
bool isOpaque() const { return SkAlphaTypeIsOpaque(this->alphaType()); }
|
||||
|
||||
/**
|
||||
* Extracts YUV planes from the SkImage and stores them in client-provided memory. The sizes
|
||||
|
@ -106,6 +106,10 @@ void SkImage::preroll(GrContext* ctx) const {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkAlphaType SkImage::alphaType() const {
|
||||
return as_IB(this)->onAlphaType();
|
||||
}
|
||||
|
||||
sk_sp<SkShader> SkImage::makeShader(SkShader::TileMode tileX, SkShader::TileMode tileY,
|
||||
const SkMatrix* localMatrix) const {
|
||||
return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tileX, tileY, localMatrix);
|
||||
@ -320,7 +324,7 @@ bool SkImage_Base::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) con
|
||||
// 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->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
|
||||
.makeAlphaType(this->alphaType());
|
||||
if (!bitmap->tryAllocPixels(info)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ public:
|
||||
// Implementors: if you can not return the value, return an invalid ImageInfo with w=0 & h=0
|
||||
// & unknown color space.
|
||||
virtual SkImageInfo onImageInfo() const = 0;
|
||||
virtual SkAlphaType onAlphaType() const = 0;
|
||||
|
||||
virtual bool onPeekPixels(SkPixmap*) const { return false; }
|
||||
|
||||
|
@ -24,11 +24,13 @@ public:
|
||||
virtual SkImageInfo onImageInfo() const override {
|
||||
return fCache->info();
|
||||
}
|
||||
SkAlphaType onAlphaType() const override {
|
||||
return fCache->info().alphaType();
|
||||
}
|
||||
|
||||
bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override;
|
||||
SkImageCacherator* peekCacherator() const override { return fCache; }
|
||||
SkData* onRefEncoded(GrContext*) const override;
|
||||
bool isOpaque() const override { return fCache->info().isOpaque(); }
|
||||
sk_sp<SkImage> onMakeSubset(const SkIRect&) const override;
|
||||
bool getROPixels(SkBitmap*, CachingHint) const override;
|
||||
GrTexture* asTextureRef(GrContext*, const GrTextureParams&,
|
||||
@ -84,7 +86,7 @@ sk_sp<SkImage> SkImage_Generator::onMakeSubset(const SkIRect& subset) const {
|
||||
// For now, we do effectively what we did before, make it a raster
|
||||
|
||||
const SkImageInfo info = SkImageInfo::MakeN32(subset.width(), subset.height(),
|
||||
this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
|
||||
this->alphaType());
|
||||
auto surface(SkSurface::MakeRaster(info));
|
||||
if (!surface) {
|
||||
return nullptr;
|
||||
|
@ -51,9 +51,8 @@ SkImageInfo SkImage_Gpu::onImageInfo() const {
|
||||
return SkImageInfo::Make(fTexture->width(), fTexture->height(), ct, fAlphaType, fColorSpace);
|
||||
}
|
||||
|
||||
static SkImageInfo make_info(int w, int h, bool isOpaque, sk_sp<SkColorSpace> colorSpace) {
|
||||
return SkImageInfo::MakeN32(w, h, isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType,
|
||||
std::move(colorSpace));
|
||||
static SkImageInfo make_info(int w, int h, SkAlphaType at, sk_sp<SkColorSpace> colorSpace) {
|
||||
return SkImageInfo::MakeN32(w, h, at, std::move(colorSpace));
|
||||
}
|
||||
|
||||
bool SkImage_Gpu::getROPixels(SkBitmap* dst, CachingHint chint) const {
|
||||
@ -64,7 +63,7 @@ bool SkImage_Gpu::getROPixels(SkBitmap* dst, CachingHint chint) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!dst->tryAllocPixels(make_info(this->width(), this->height(), this->isOpaque(),
|
||||
if (!dst->tryAllocPixels(make_info(this->width(), this->height(), this->alphaType(),
|
||||
this->fColorSpace))) {
|
||||
return false;
|
||||
}
|
||||
@ -88,10 +87,6 @@ GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrTextureParams& para
|
||||
return adjuster.refTextureSafeForParams(params, gammaTreatment, nullptr);
|
||||
}
|
||||
|
||||
bool SkImage_Gpu::isOpaque() const {
|
||||
return GrPixelConfigIsOpaque(fTexture->config()) || fAlphaType == kOpaque_SkAlphaType;
|
||||
}
|
||||
|
||||
static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
|
||||
switch (info.colorType()) {
|
||||
case kRGBA_8888_SkColorType:
|
||||
@ -309,17 +304,15 @@ sk_sp<SkImage> SkImage::makeTextureImage(GrContext *context) const {
|
||||
if (GrTexture* peek = as_IB(this)->peekTexture()) {
|
||||
return peek->getContext() == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr;
|
||||
}
|
||||
// No way to check whether a image is premul or not?
|
||||
SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
|
||||
|
||||
if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
|
||||
GrImageTextureMaker maker(context, cacher, this, kDisallow_CachingHint);
|
||||
return create_image_from_maker(&maker, at, this->uniqueID());
|
||||
return create_image_from_maker(&maker, this->alphaType(), this->uniqueID());
|
||||
}
|
||||
|
||||
if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
|
||||
GrBitmapTextureMaker maker(context, *bmp);
|
||||
return create_image_from_maker(&maker, at, this->uniqueID());
|
||||
return create_image_from_maker(&maker, this->alphaType(), this->uniqueID());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -445,8 +438,7 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox
|
||||
if (!data && !this->peekPixels(nullptr)) {
|
||||
return 0;
|
||||
}
|
||||
SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
|
||||
info = SkImageInfo::MakeN32(scaledSize.width(), scaledSize.height(), at);
|
||||
info = SkImageInfo::MakeN32(scaledSize.width(), scaledSize.height(), this->alphaType());
|
||||
pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr));
|
||||
if (fillMode) {
|
||||
pixmap.alloc(info);
|
||||
|
@ -28,6 +28,7 @@ public:
|
||||
~SkImage_Gpu() override;
|
||||
|
||||
SkImageInfo onImageInfo() const override;
|
||||
SkAlphaType onAlphaType() const override { return fAlphaType; }
|
||||
|
||||
void applyBudgetDecision() const {
|
||||
if (SkBudgeted::kYes == fBudgeted) {
|
||||
@ -47,7 +48,6 @@ public:
|
||||
*uniqueID = this->uniqueID();
|
||||
return sk_ref_sp(fTexture.get());
|
||||
}
|
||||
bool isOpaque() const override;
|
||||
bool onReadPixels(const SkImageInfo&, void* dstPixels, size_t dstRowBytes,
|
||||
int srcX, int srcY, CachingHint) const override;
|
||||
|
||||
|
@ -79,6 +79,9 @@ public:
|
||||
SkImageInfo onImageInfo() const override {
|
||||
return fBitmap.info();
|
||||
}
|
||||
SkAlphaType onAlphaType() const override {
|
||||
return fBitmap.alphaType();
|
||||
}
|
||||
|
||||
bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override;
|
||||
bool onPeekPixels(SkPixmap*) const override;
|
||||
@ -95,7 +98,6 @@ public:
|
||||
|
||||
SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
|
||||
|
||||
bool isOpaque() const override;
|
||||
bool onAsLegacyBitmap(SkBitmap*, LegacyBitmapMode) const override;
|
||||
|
||||
SkImage_Raster(const SkBitmap& bm, bool bitmapMayBeMutable = false)
|
||||
@ -359,10 +361,6 @@ const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
|
||||
return ((const SkImage_Raster*)image)->getPixelRef();
|
||||
}
|
||||
|
||||
bool SkImage_Raster::isOpaque() const {
|
||||
return fBitmap.isOpaque();
|
||||
}
|
||||
|
||||
bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const {
|
||||
if (kRO_LegacyBitmapMode == mode) {
|
||||
// When we're a snapshot from a surface, our bitmap may not be marked immutable
|
||||
|
@ -32,8 +32,7 @@ void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) {
|
||||
}
|
||||
}
|
||||
// no pixels or wrong size: fill with zeros.
|
||||
SkAlphaType at = image->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
|
||||
dst->setInfo(SkImageInfo::MakeN32(image->width(), image->height(), at));
|
||||
dst->setInfo(SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()));
|
||||
}
|
||||
|
||||
bool image_compute_is_opaque(const SkImage* image) {
|
||||
|
@ -43,8 +43,7 @@ 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->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
|
||||
SkImageInfo info = SkImageInfo::MakeN32(widthA, heightA, a->alphaType());
|
||||
SkAutoPixmapStorage pmapA, pmapB;
|
||||
pmapA.alloc(info);
|
||||
pmapB.alloc(info);
|
||||
@ -505,8 +504,8 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkImage_newTextureImage, reporter, contextInf
|
||||
if (image->width() != texImage->width() || image->height() != texImage->height()) {
|
||||
ERRORF(reporter, "newTextureImage changed the image size.");
|
||||
}
|
||||
if (image->isOpaque() != texImage->isOpaque()) {
|
||||
ERRORF(reporter, "newTextureImage changed image opaqueness.");
|
||||
if (image->alphaType() != texImage->alphaType()) {
|
||||
ERRORF(reporter, "newTextureImage changed image alpha type.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -669,7 +668,7 @@ static void check_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* ima
|
||||
const SkBitmap& bitmap, SkImage::LegacyBitmapMode mode) {
|
||||
REPORTER_ASSERT(reporter, image->width() == bitmap.width());
|
||||
REPORTER_ASSERT(reporter, image->height() == bitmap.height());
|
||||
REPORTER_ASSERT(reporter, image->isOpaque() == bitmap.isOpaque());
|
||||
REPORTER_ASSERT(reporter, image->alphaType() == bitmap.alphaType());
|
||||
|
||||
if (SkImage::kRO_LegacyBitmapMode == mode) {
|
||||
REPORTER_ASSERT(reporter, bitmap.isImmutable());
|
||||
@ -812,8 +811,8 @@ static void check_images_same(skiatest::Reporter* reporter, const SkImage* a, co
|
||||
ERRORF(reporter, "Images must have the same size");
|
||||
return;
|
||||
}
|
||||
if (a->isOpaque() != b->isOpaque()) {
|
||||
ERRORF(reporter, "Images must have the same opaquness");
|
||||
if (a->alphaType() != b->alphaType()) {
|
||||
ERRORF(reporter, "Images must have the same alpha type");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -948,9 +947,9 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DeferredTextureImage, reporter, ctxInfo) {
|
||||
if (newImage) {
|
||||
// Scale the image in software for comparison.
|
||||
SkImageInfo scaled_info = SkImageInfo::MakeN32(
|
||||
image->width() / testCase.fExpectedScaleFactor,
|
||||
image->height() / testCase.fExpectedScaleFactor,
|
||||
image->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
|
||||
image->width() / testCase.fExpectedScaleFactor,
|
||||
image->height() / testCase.fExpectedScaleFactor,
|
||||
image->alphaType());
|
||||
SkAutoPixmapStorage scaled;
|
||||
scaled.alloc(scaled_info);
|
||||
image->scalePixels(scaled, testCase.fExpectedQuality);
|
||||
|
@ -128,32 +128,31 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCanvasPeek_Gpu, reporter, ctxInfo) {
|
||||
#endif
|
||||
|
||||
static void test_snapshot_alphatype(skiatest::Reporter* reporter, const sk_sp<SkSurface>& surface,
|
||||
bool expectOpaque) {
|
||||
SkAlphaType expectedAlphaType) {
|
||||
REPORTER_ASSERT(reporter, surface);
|
||||
if (surface) {
|
||||
sk_sp<SkImage> image(surface->makeImageSnapshot());
|
||||
REPORTER_ASSERT(reporter, image);
|
||||
if (image) {
|
||||
REPORTER_ASSERT(reporter, image->isOpaque() == SkToBool(expectOpaque));
|
||||
REPORTER_ASSERT(reporter, image->alphaType() == expectedAlphaType);
|
||||
}
|
||||
}
|
||||
}
|
||||
DEF_TEST(SurfaceSnapshotAlphaType, reporter) {
|
||||
for (auto& surface_func : { &create_surface, &create_direct_surface }) {
|
||||
for (auto& isOpaque : { true, false }) {
|
||||
SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
|
||||
auto surface(surface_func(alphaType, nullptr));
|
||||
test_snapshot_alphatype(reporter, surface, isOpaque);
|
||||
for (auto& at: { kOpaque_SkAlphaType, kPremul_SkAlphaType, kUnpremul_SkAlphaType }) {
|
||||
auto surface(surface_func(at, nullptr));
|
||||
test_snapshot_alphatype(reporter, surface, at);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if SK_SUPPORT_GPU
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceSnapshotAlphaType_Gpu, reporter, ctxInfo) {
|
||||
for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
|
||||
for (auto& isOpaque : { true, false }) {
|
||||
SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
|
||||
auto surface(surface_func(ctxInfo.grContext(), alphaType, nullptr));
|
||||
test_snapshot_alphatype(reporter, surface, isOpaque);
|
||||
// GPU doesn't support creating unpremul surfaces, so only test opaque + premul
|
||||
for (auto& at : { kOpaque_SkAlphaType, kPremul_SkAlphaType }) {
|
||||
auto surface(surface_func(ctxInfo.grContext(), at, nullptr));
|
||||
test_snapshot_alphatype(reporter, surface, at);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user