Reland DeferredTextureImageData low-bit-depth/dithering support

Cause DeferredTextureImageData functionality to support low bit depth
(4444, 565) image formats (with dithering).

Updated to handle colorspace + 4444 colortype correctly.

Bug: 720105
Change-Id: Ib7e14d937849f4f6b08fda6992a240bb203d0089
Reviewed-on: https://skia-review.googlesource.com/19094
Commit-Queue: Eric Karl <ericrk@chromium.org>
Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Eric Karl 2017-06-12 10:05:49 -07:00 committed by Skia Commit-Bot
parent a8d45e5220
commit 7a8c84c6c9
7 changed files with 125 additions and 44 deletions

View File

@ -17,7 +17,9 @@
// Helper function that uploads the given SkImage using MakeFromDeferredTextureImageData and then // Helper function that uploads the given SkImage using MakeFromDeferredTextureImageData and then
// draws the uploaded version at the specified coordinates. // draws the uploaded version at the specified coordinates.
static void DrawDeferredTextureImageData(SkCanvas* canvas, static void DrawDeferredTextureImageData(SkCanvas* canvas,
SkImage::DeferredTextureImageUsageParams* params) { const char* resourceName,
SkImage::DeferredTextureImageUsageParams* params,
SkColorType dstColorType) {
GrContext* context = canvas->getGrContext(); GrContext* context = canvas->getGrContext();
if (!context) { if (!context) {
skiagm::GM::DrawGpuOnlyMessage(canvas); skiagm::GM::DrawGpuOnlyMessage(canvas);
@ -27,14 +29,14 @@ static void DrawDeferredTextureImageData(SkCanvas* canvas,
sk_sp<SkImage> encodedImage = GetResourceAsImage("mandrill_512.png"); sk_sp<SkImage> encodedImage = GetResourceAsImage(resourceName);
if (!encodedImage) { if (!encodedImage) {
SkDebugf("\nCould not load resource.\n"); SkDebugf("\nCould not load resource.\n");
return; return;
} }
size_t requiredMemoryInBytes = encodedImage->getDeferredTextureImageData( size_t requiredMemoryInBytes = encodedImage->getDeferredTextureImageData(
*proxy, params, 1, nullptr, canvas->imageInfo().colorSpace()); *proxy, params, 1, nullptr, canvas->imageInfo().colorSpace(), dstColorType);
if (requiredMemoryInBytes == 0) { if (requiredMemoryInBytes == 0) {
SkDebugf("\nCould not create DeferredTextureImageData.\n"); SkDebugf("\nCould not create DeferredTextureImageData.\n");
return; return;
@ -43,7 +45,7 @@ static void DrawDeferredTextureImageData(SkCanvas* canvas,
std::vector<uint8_t> memory; std::vector<uint8_t> memory;
memory.resize(requiredMemoryInBytes); memory.resize(requiredMemoryInBytes);
encodedImage->getDeferredTextureImageData( encodedImage->getDeferredTextureImageData(
*proxy, params, 1, memory.data(), canvas->imageInfo().colorSpace()); *proxy, params, 1, memory.data(), canvas->imageInfo().colorSpace(), dstColorType);
sk_sp<SkImage> uploadedEncodedImage = SkImage::MakeFromDeferredTextureImageData( sk_sp<SkImage> uploadedEncodedImage = SkImage::MakeFromDeferredTextureImageData(
context, memory.data(), SkBudgeted::kNo); context, memory.data(), SkBudgeted::kNo);
@ -52,14 +54,14 @@ static void DrawDeferredTextureImageData(SkCanvas* canvas,
SkBitmap bitmap; SkBitmap bitmap;
if (!GetResourceAsBitmap("mandrill_512.png", &bitmap)) { if (!GetResourceAsBitmap(resourceName, &bitmap)) {
SkDebugf("\nCould not decode resource.\n"); SkDebugf("\nCould not decode resource.\n");
return; return;
} }
sk_sp<SkImage> decodedImage = SkImage::MakeFromBitmap(bitmap); sk_sp<SkImage> decodedImage = SkImage::MakeFromBitmap(bitmap);
requiredMemoryInBytes = decodedImage->getDeferredTextureImageData( requiredMemoryInBytes = decodedImage->getDeferredTextureImageData(
*proxy, params, 1, nullptr, canvas->imageInfo().colorSpace()); *proxy, params, 1, nullptr, canvas->imageInfo().colorSpace(), dstColorType);
if (requiredMemoryInBytes == 0) { if (requiredMemoryInBytes == 0) {
SkDebugf("\nCould not create DeferredTextureImageData.\n"); SkDebugf("\nCould not create DeferredTextureImageData.\n");
return; return;
@ -67,15 +69,16 @@ static void DrawDeferredTextureImageData(SkCanvas* canvas,
memory.resize(requiredMemoryInBytes); memory.resize(requiredMemoryInBytes);
decodedImage->getDeferredTextureImageData( decodedImage->getDeferredTextureImageData(
*proxy, params, 1, memory.data(), canvas->imageInfo().colorSpace()); *proxy, params, 1, memory.data(), canvas->imageInfo().colorSpace(), dstColorType);
sk_sp<SkImage> uploadedDecodedImage = SkImage::MakeFromDeferredTextureImageData( sk_sp<SkImage> uploadedDecodedImage = SkImage::MakeFromDeferredTextureImageData(
context, memory.data(), SkBudgeted::kNo); context, memory.data(), SkBudgeted::kNo);
canvas->drawImage(uploadedDecodedImage, 512 + 20, 10); canvas->drawImage(uploadedDecodedImage, encodedImage->width() + 20, 10);
} }
static void DrawDeferredTextureImageMipMapTree(SkCanvas* canvas, SkImage* image, static void DrawDeferredTextureImageMipMapTree(SkCanvas* canvas, SkImage* image,
SkImage::DeferredTextureImageUsageParams* params) { SkImage::DeferredTextureImageUsageParams* params,
SkColorType dstColorType) {
GrContext* context = canvas->getGrContext(); GrContext* context = canvas->getGrContext();
if (!context) { if (!context) {
skiagm::GM::DrawGpuOnlyMessage(canvas); skiagm::GM::DrawGpuOnlyMessage(canvas);
@ -88,7 +91,7 @@ static void DrawDeferredTextureImageMipMapTree(SkCanvas* canvas, SkImage* image,
int mipLevelCount = SkMipMap::ComputeLevelCount(image->width(), image->height()); int mipLevelCount = SkMipMap::ComputeLevelCount(image->width(), image->height());
size_t requiredMemoryInBytes = image->getDeferredTextureImageData( size_t requiredMemoryInBytes = image->getDeferredTextureImageData(
*proxy, params, 1, nullptr, canvas->imageInfo().colorSpace()); *proxy, params, 1, nullptr, canvas->imageInfo().colorSpace(), dstColorType);
if (requiredMemoryInBytes == 0) { if (requiredMemoryInBytes == 0) {
SkDebugf("\nCould not create DeferredTextureImageData.\n"); SkDebugf("\nCould not create DeferredTextureImageData.\n");
return; return;
@ -97,7 +100,7 @@ static void DrawDeferredTextureImageMipMapTree(SkCanvas* canvas, SkImage* image,
std::vector<uint8_t> memory; std::vector<uint8_t> memory;
memory.resize(requiredMemoryInBytes); memory.resize(requiredMemoryInBytes);
image->getDeferredTextureImageData( image->getDeferredTextureImageData(
*proxy, params, 1, memory.data(), canvas->imageInfo().colorSpace()); *proxy, params, 1, memory.data(), canvas->imageInfo().colorSpace(), dstColorType);
sk_sp<SkImage> uploadedImage = SkImage::MakeFromDeferredTextureImageData( sk_sp<SkImage> uploadedImage = SkImage::MakeFromDeferredTextureImageData(
context, memory.data(), SkBudgeted::kNo); context, memory.data(), SkBudgeted::kNo);
@ -145,13 +148,19 @@ static void DrawDeferredTextureImageMipMapTree(SkCanvas* canvas, SkImage* image,
DEF_SIMPLE_GM(deferred_texture_image_none, canvas, 512 + 512 + 30, 512 + 20) { DEF_SIMPLE_GM(deferred_texture_image_none, canvas, 512 + 512 + 30, 512 + 20) {
auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(1.f, 1.f), auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(1.f, 1.f),
kNone_SkFilterQuality, 0); kNone_SkFilterQuality, 0);
DrawDeferredTextureImageData(canvas, &params); DrawDeferredTextureImageData(canvas, "mandrill_512.png", &params, kN32_SkColorType);
} }
DEF_SIMPLE_GM(deferred_texture_image_low, canvas, 512 + 512 + 30, 512 + 20) { DEF_SIMPLE_GM(deferred_texture_image_low, canvas, 512 + 512 + 30, 512 + 20) {
auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(1.f, 1.f), auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(1.f, 1.f),
kLow_SkFilterQuality, 0); kLow_SkFilterQuality, 0);
DrawDeferredTextureImageData(canvas, &params); DrawDeferredTextureImageData(canvas, "mandrill_512.png", &params, kN32_SkColorType);
}
DEF_SIMPLE_GM(deferred_texture_image_low_dithered, canvas, 180 + 180 + 30, 180 + 20) {
auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(0.25f, 0.25f),
kLow_SkFilterQuality, 0);
DrawDeferredTextureImageData(canvas, "dog.jpg", &params, kARGB_4444_SkColorType);
} }
DEF_SIMPLE_GM(deferred_texture_image_medium_encoded, canvas, 512 + 512 + 30, 1110) { DEF_SIMPLE_GM(deferred_texture_image_medium_encoded, canvas, 512 + 512 + 30, 1110) {
@ -163,7 +172,7 @@ DEF_SIMPLE_GM(deferred_texture_image_medium_encoded, canvas, 512 + 512 + 30, 111
auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(0.25f, 0.25f), auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(0.25f, 0.25f),
kMedium_SkFilterQuality, 0); kMedium_SkFilterQuality, 0);
DrawDeferredTextureImageMipMapTree(canvas, encodedImage.get(), &params); DrawDeferredTextureImageMipMapTree(canvas, encodedImage.get(), &params, kN32_SkColorType);
} }
DEF_SIMPLE_GM(deferred_texture_image_medium_decoded, canvas, 512 + 512 + 30, 1110) { DEF_SIMPLE_GM(deferred_texture_image_medium_decoded, canvas, 512 + 512 + 30, 1110) {
@ -176,13 +185,13 @@ DEF_SIMPLE_GM(deferred_texture_image_medium_decoded, canvas, 512 + 512 + 30, 111
auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(0.25f, 0.25f), auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(0.25f, 0.25f),
kMedium_SkFilterQuality, 0); kMedium_SkFilterQuality, 0);
DrawDeferredTextureImageMipMapTree(canvas, decodedImage.get(), &params); DrawDeferredTextureImageMipMapTree(canvas, decodedImage.get(), &params, kN32_SkColorType);
} }
DEF_SIMPLE_GM(deferred_texture_image_high, canvas, 512 + 512 + 30, 512 + 20) { DEF_SIMPLE_GM(deferred_texture_image_high, canvas, 512 + 512 + 30, 512 + 20) {
auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(1.f, 1.f), auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(1.f, 1.f),
kHigh_SkFilterQuality, 0); kHigh_SkFilterQuality, 0);
DrawDeferredTextureImageData(canvas, &params); DrawDeferredTextureImageData(canvas, "mandrill_512.png", &params, kN32_SkColorType);
} }
DEF_SIMPLE_GM(deferred_texture_image_medium_encoded_indexed, canvas, 128 + 128 + 30, 340) { DEF_SIMPLE_GM(deferred_texture_image_medium_encoded_indexed, canvas, 128 + 128 + 30, 340) {
@ -194,7 +203,7 @@ DEF_SIMPLE_GM(deferred_texture_image_medium_encoded_indexed, canvas, 128 + 128 +
auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(0.25f, 0.25f), auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(0.25f, 0.25f),
kMedium_SkFilterQuality, 0); kMedium_SkFilterQuality, 0);
DrawDeferredTextureImageMipMapTree(canvas, encodedImage.get(), &params); DrawDeferredTextureImageMipMapTree(canvas, encodedImage.get(), &params, kN32_SkColorType);
} }
DEF_SIMPLE_GM(deferred_texture_image_medium_decoded_indexed, canvas, 128 + 128 + 30, 340) { DEF_SIMPLE_GM(deferred_texture_image_medium_decoded_indexed, canvas, 128 + 128 + 30, 340) {
@ -207,7 +216,7 @@ DEF_SIMPLE_GM(deferred_texture_image_medium_decoded_indexed, canvas, 128 + 128 +
auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(0.25f, 0.25f), auto params = SkImage::DeferredTextureImageUsageParams(SkMatrix::MakeScale(0.25f, 0.25f),
kMedium_SkFilterQuality, 0); kMedium_SkFilterQuality, 0);
DrawDeferredTextureImageMipMapTree(canvas, decodedImage.get(), &params); DrawDeferredTextureImageMipMapTree(canvas, decodedImage.get(), &params, kN32_SkColorType);
} }
#endif #endif

View File

@ -477,12 +477,18 @@ public:
* dstColorSpace is the color space of the surface where this texture will ultimately be used. * dstColorSpace is the color space of the surface where this texture will ultimately be used.
* If the method determines that mip-maps are needed, this helps determine the correct strategy * If the method determines that mip-maps are needed, this helps determine the correct strategy
* for building them (gamma-correct or not). * for building them (gamma-correct or not).
*
* dstColorType is the color type of the surface where this texture will ultimately be used.
* This determines the format with which the image will be uploaded to the GPU. If dstColorType
* does not support color spaces (low bit depth types such as ARGB_4444), then dstColorSpace
* must be null.
*/ */
size_t getDeferredTextureImageData(const GrContextThreadSafeProxy&, size_t getDeferredTextureImageData(const GrContextThreadSafeProxy&,
const DeferredTextureImageUsageParams[], const DeferredTextureImageUsageParams[],
int paramCnt, int paramCnt,
void* buffer, void* buffer,
SkColorSpace* dstColorSpace = nullptr) const; SkColorSpace* dstColorSpace = nullptr,
SkColorType dstColorType = kN32_SkColorType) const;
/** /**
* Returns a texture-backed image from data produced in SkImage::getDeferredTextureImageData. * Returns a texture-backed image from data produced in SkImage::getDeferredTextureImageData.

View File

@ -14,6 +14,16 @@ SkAutoPixmapStorage::~SkAutoPixmapStorage() {
this->freeStorage(); this->freeStorage();
} }
SkAutoPixmapStorage& SkAutoPixmapStorage::operator=(SkAutoPixmapStorage&& other) {
this->fStorage = other.fStorage;
this->INHERITED::reset(other.info(), this->fStorage, other.rowBytes(), other.ctable());
other.fStorage = nullptr;
other.INHERITED::reset();
return *this;
}
size_t SkAutoPixmapStorage::AllocSize(const SkImageInfo& info, size_t* rowBytes) { size_t SkAutoPixmapStorage::AllocSize(const SkImageInfo& info, size_t* rowBytes) {
size_t rb = info.minRowBytes(); size_t rb = info.minRowBytes();
if (rowBytes) { if (rowBytes) {

View File

@ -16,6 +16,11 @@ public:
SkAutoPixmapStorage(); SkAutoPixmapStorage();
~SkAutoPixmapStorage(); ~SkAutoPixmapStorage();
/**
* Leave the moved-from object in a free-but-valid state.
*/
SkAutoPixmapStorage& operator=(SkAutoPixmapStorage&& other);
/** /**
* Try to allocate memory for the pixels needed to match the specified Info. On success * Try to allocate memory for the pixels needed to match the specified Info. On success
* return true and fill out the pixmap to point to that memory. The storage will be freed * return true and fill out the pixmap to point to that memory. The storage will be freed

View File

@ -347,7 +347,8 @@ sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy&, size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy&,
const DeferredTextureImageUsageParams[], const DeferredTextureImageUsageParams[],
int paramCnt, void* buffer, int paramCnt, void* buffer,
SkColorSpace* dstColorSpace) const { SkColorSpace* dstColorSpace,
SkColorType dstColorType) const {
return 0; return 0;
} }

View File

@ -597,10 +597,22 @@ private:
offsetof(DeferredTextureImage, member), \ offsetof(DeferredTextureImage, member), \
sizeof(DeferredTextureImage::member)); sizeof(DeferredTextureImage::member));
static bool SupportsColorSpace(SkColorType colorType) {
switch (colorType) {
case kRGBA_8888_SkColorType:
case kBGRA_8888_SkColorType:
case kRGBA_F16_SkColorType:
return true;
default:
return false;
}
}
size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& proxy, size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& proxy,
const DeferredTextureImageUsageParams params[], const DeferredTextureImageUsageParams params[],
int paramCnt, void* buffer, int paramCnt, void* buffer,
SkColorSpace* dstColorSpace) const { SkColorSpace* dstColorSpace,
SkColorType dstColorType) const {
// Some quick-rejects where is makes no sense to return CPU data // Some quick-rejects where is makes no sense to return CPU data
// e.g. // e.g.
// - texture backed // - texture backed
@ -613,6 +625,12 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox
return 0; return 0;
} }
bool supportsColorSpace = SupportsColorSpace(dstColorType);
// Quick reject if the caller requests a color space with an unsupported color type.
if (SkToBool(dstColorSpace) && !supportsColorSpace) {
return 0;
}
// Extract relevant min/max values from the params array. // Extract relevant min/max values from the params array.
int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel; int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel;
SkFilterQuality highestFilterQuality = params[0].fQuality; SkFilterQuality highestFilterQuality = params[0].fQuality;
@ -657,7 +675,8 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox
SkAutoPixmapStorage pixmap; SkAutoPixmapStorage pixmap;
SkImageInfo info; SkImageInfo info;
size_t pixelSize = 0; size_t pixelSize = 0;
if (!isScaled && this->peekPixels(&pixmap) && !pixmap.ctable()) { if (!isScaled && this->peekPixels(&pixmap) && !pixmap.ctable() &&
pixmap.info().colorType() == dstColorType) {
info = pixmap.info(); info = pixmap.info();
pixelSize = SkAlign8(pixmap.getSafeSize()); pixelSize = SkAlign8(pixmap.getSafeSize());
if (!dstColorSpace) { if (!dstColorSpace) {
@ -680,24 +699,35 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox
info = info.makeColorSpace(nullptr); info = info.makeColorSpace(nullptr);
} }
} }
if (kIndex_8_SkColorType == info.colorType()) { // Force color type to be the requested type.
// Force Index8 to be N32 instead. Index8 is unsupported in Ganesh. info = info.makeColorType(dstColorType);
info = info.makeColorType(kN32_SkColorType);
}
pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr)); pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr));
if (fillMode) { if (fillMode) {
pixmap.alloc(info); // Always decode to N32 and convert to the requested type if necessary.
SkImageInfo decodeInfo = info.makeColorType(kN32_SkColorType);
SkAutoPixmapStorage decodePixmap;
decodePixmap.alloc(decodeInfo);
if (isScaled) { if (isScaled) {
if (!this->scalePixels(pixmap, scaleFilterQuality, if (!this->scalePixels(decodePixmap, scaleFilterQuality,
SkImage::kDisallow_CachingHint)) { SkImage::kDisallow_CachingHint)) {
return 0; return 0;
} }
} else { } else {
if (!this->readPixels(pixmap, 0, 0, SkImage::kDisallow_CachingHint)) { if (!this->readPixels(decodePixmap, 0, 0, SkImage::kDisallow_CachingHint)) {
return 0; return 0;
} }
} }
SkASSERT(!pixmap.ctable()); SkASSERT(!decodePixmap.ctable());
if (decodeInfo.colorType() != info.colorType()) {
pixmap.alloc(info);
// Convert and copy the decoded pixmap to the target pixmap.
decodePixmap.readPixels(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes(), 0,
0);
} else {
pixmap = std::move(decodePixmap);
}
} }
} }
int mipMapLevelCount = 1; int mipMapLevelCount = 1;
@ -735,10 +765,11 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox
SkColorSpaceTransferFn fn; SkColorSpaceTransferFn fn;
if (info.colorSpace()) { if (info.colorSpace()) {
SkASSERT(dstColorSpace); SkASSERT(dstColorSpace);
SkASSERT(supportsColorSpace);
colorSpaceOffset = size; colorSpaceOffset = size;
colorSpaceSize = info.colorSpace()->writeToMemory(nullptr); colorSpaceSize = info.colorSpace()->writeToMemory(nullptr);
size += colorSpaceSize; size += colorSpaceSize;
} else if (this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn)) { } else if (supportsColorSpace && this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn)) {
// In legacy mode, preserve the color space tag on the SkImage. This is only // In legacy mode, preserve the color space tag on the SkImage. This is only
// supported if the color space has a parametric transfer function. // supported if the color space has a parametric transfer function.
SkASSERT(!dstColorSpace); SkASSERT(!dstColorSpace);
@ -762,6 +793,7 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox
SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy; SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy;
if (proxy.fCaps->srgbSupport() && SkToBool(dstColorSpace) && if (proxy.fCaps->srgbSupport() && SkToBool(dstColorSpace) &&
info.colorSpace() && info.colorSpace()->gammaCloseToSRGB()) { info.colorSpace() && info.colorSpace()->gammaCloseToSRGB()) {
SkASSERT(supportsColorSpace);
colorMode = SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware; colorMode = SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware;
} }

View File

@ -1024,21 +1024,23 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DeferredTextureImage, reporter, ctxInfo) {
struct { struct {
std::function<sk_sp<SkImage> ()> fImageFactory; std::function<sk_sp<SkImage> ()> fImageFactory;
std::vector<SkImage::DeferredTextureImageUsageParams> fParams; std::vector<SkImage::DeferredTextureImageUsageParams> fParams;
sk_sp<SkColorSpace> fColorSpace;
SkColorType fColorType;
SkFilterQuality fExpectedQuality; SkFilterQuality fExpectedQuality;
int fExpectedScaleFactor; int fExpectedScaleFactor;
bool fExpectation; bool fExpectation;
} testCases[] = { } testCases[] = {
{ create_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}}, { create_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
kNone_SkFilterQuality, 1, true }, nullptr, kN32_SkColorType, kNone_SkFilterQuality, 1, true },
{ create_codec_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}}, { create_codec_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
kNone_SkFilterQuality, 1, true }, nullptr, kN32_SkColorType, kNone_SkFilterQuality, 1, true },
{ create_data_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}}, { create_data_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
kNone_SkFilterQuality, 1, true }, nullptr, kN32_SkColorType, kNone_SkFilterQuality, 1, true },
{ create_picture_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}}, { create_picture_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
kNone_SkFilterQuality, 1, false }, nullptr, kN32_SkColorType, kNone_SkFilterQuality, 1, false },
{ [context] { return create_gpu_image(context); }, { [context] { return create_gpu_image(context); },
{{SkMatrix::I(), kNone_SkFilterQuality, 0}}, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
kNone_SkFilterQuality, 1, false }, nullptr, kN32_SkColorType, kNone_SkFilterQuality, 1, false },
// Create a texture image in a another GrContext. // Create a texture image in a another GrContext.
{ [testContext, otherContextInfo] { { [testContext, otherContextInfo] {
otherContextInfo.testContext()->makeCurrent(); otherContextInfo.testContext()->makeCurrent();
@ -1046,21 +1048,34 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DeferredTextureImage, reporter, ctxInfo) {
testContext->makeCurrent(); testContext->makeCurrent();
return otherContextImage; return otherContextImage;
}, {{SkMatrix::I(), kNone_SkFilterQuality, 0}}, }, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
kNone_SkFilterQuality, 1, false }, nullptr, kN32_SkColorType, kNone_SkFilterQuality, 1, false },
// Create an image that is too large to upload. // Create an image that is too large to upload.
{ createLarge, {{SkMatrix::I(), kNone_SkFilterQuality, 0}}, { createLarge, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
kNone_SkFilterQuality, 1, false }, nullptr, kN32_SkColorType, kNone_SkFilterQuality, 1, false },
// Create an image that is too large, but is scaled to an acceptable size. // Create an image that is too large, but is scaled to an acceptable size.
{ createLarge, {{SkMatrix::I(), kMedium_SkFilterQuality, 4}}, { createLarge, {{SkMatrix::I(), kMedium_SkFilterQuality, 4}},
kMedium_SkFilterQuality, 16, true}, nullptr, kN32_SkColorType, kMedium_SkFilterQuality, 16, true},
// Create an image with multiple low filter qualities, make sure we round up. // Create an image with multiple low filter qualities, make sure we round up.
{ createLarge, {{SkMatrix::I(), kNone_SkFilterQuality, 4}, { createLarge, {{SkMatrix::I(), kNone_SkFilterQuality, 4},
{SkMatrix::I(), kMedium_SkFilterQuality, 4}}, {SkMatrix::I(), kMedium_SkFilterQuality, 4}},
kMedium_SkFilterQuality, 16, true}, nullptr, kN32_SkColorType, kMedium_SkFilterQuality, 16, true},
// Create an image with multiple prescale levels, make sure we chose the minimum scale. // Create an image with multiple prescale levels, make sure we chose the minimum scale.
{ createLarge, {{SkMatrix::I(), kMedium_SkFilterQuality, 5}, { createLarge, {{SkMatrix::I(), kMedium_SkFilterQuality, 5},
{SkMatrix::I(), kMedium_SkFilterQuality, 4}}, {SkMatrix::I(), kMedium_SkFilterQuality, 4}},
kMedium_SkFilterQuality, 16, true}, nullptr, kN32_SkColorType, kMedium_SkFilterQuality, 16, true},
// Create a images which are decoded to a 4444 backing.
{ create_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
nullptr, kARGB_4444_SkColorType, kNone_SkFilterQuality, 1, true },
{ create_codec_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
nullptr, kARGB_4444_SkColorType, kNone_SkFilterQuality, 1, true },
{ create_data_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
nullptr, kARGB_4444_SkColorType, kNone_SkFilterQuality, 1, true },
// Valid SkColorSpace and SkColorType.
{ create_data_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
SkColorSpace::MakeSRGB(), kN32_SkColorType, kNone_SkFilterQuality, 1, true },
// Invalid SkColorSpace and SkColorType.
{ create_data_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
SkColorSpace::MakeSRGB(), kARGB_4444_SkColorType, kNone_SkFilterQuality, 1, false },
}; };
@ -1073,7 +1088,8 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DeferredTextureImage, reporter, ctxInfo) {
size_t size = image->getDeferredTextureImageData(*proxy, testCase.fParams.data(), size_t size = image->getDeferredTextureImageData(*proxy, testCase.fParams.data(),
static_cast<int>(testCase.fParams.size()), static_cast<int>(testCase.fParams.size()),
nullptr, nullptr); nullptr, testCase.fColorSpace.get(),
testCase.fColorType);
static const char *const kFS[] = { "fail", "succeed" }; static const char *const kFS[] = { "fail", "succeed" };
if (SkToBool(size) != testCase.fExpectation) { if (SkToBool(size) != testCase.fExpectation) {
ERRORF(reporter, "This image was expected to %s but did not.", ERRORF(reporter, "This image was expected to %s but did not.",
@ -1084,12 +1100,14 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DeferredTextureImage, reporter, ctxInfo) {
void* misaligned = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(buffer) + 3); void* misaligned = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(buffer) + 3);
if (image->getDeferredTextureImageData(*proxy, testCase.fParams.data(), if (image->getDeferredTextureImageData(*proxy, testCase.fParams.data(),
static_cast<int>(testCase.fParams.size()), static_cast<int>(testCase.fParams.size()),
misaligned, nullptr)) { misaligned, testCase.fColorSpace.get(),
testCase.fColorType)) {
ERRORF(reporter, "Should fail when buffer is misaligned."); ERRORF(reporter, "Should fail when buffer is misaligned.");
} }
if (!image->getDeferredTextureImageData(*proxy, testCase.fParams.data(), if (!image->getDeferredTextureImageData(*proxy, testCase.fParams.data(),
static_cast<int>(testCase.fParams.size()), static_cast<int>(testCase.fParams.size()),
buffer, nullptr)) { buffer, testCase.fColorSpace.get(),
testCase.fColorType)) {
ERRORF(reporter, "deferred image size succeeded but creation failed."); ERRORF(reporter, "deferred image size succeeded but creation failed.");
} else { } else {
for (auto budgeted : { SkBudgeted::kNo, SkBudgeted::kYes }) { for (auto budgeted : { SkBudgeted::kNo, SkBudgeted::kYes }) {