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:
brianosman 2016-08-17 14:01:05 -07:00 committed by Commit bot
parent a7eaf2e7e8
commit 69c166d2ce
11 changed files with 42 additions and 48 deletions

View File

@ -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?

View File

@ -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

View File

@ -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;
}

View File

@ -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; }

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -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);

View File

@ -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);
}
}
}