Update wacky_yuv_formats GM to demonstrate YUV resizing on the GPU
Change-Id: Idd2b75ca84c1d7984aa983820b4325fbbda2b753
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/266203
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/gm/wacky_yuv_formats.cpp b/gm/wacky_yuv_formats.cpp
index 038921c..ba52783 100644
--- a/gm/wacky_yuv_formats.cpp
+++ b/gm/wacky_yuv_formats.cpp
@@ -1013,6 +1013,55 @@
return SkColorFilters::Matrix(kJPEGConversionMatrix);
}
+// Get the SkColorType to use when creating an SkSurface wrapping 'format'.
+static SkColorType get_color_type(const GrBackendFormat& format) {
+
+ GrGLFormat glFormat = format.asGLFormat();
+ if (GrGLFormat::kUnknown != glFormat) {
+ switch (glFormat) {
+ case GrGLFormat::kLUMINANCE8: // fall through
+ case GrGLFormat::kR8: // fall through
+ case GrGLFormat::kALPHA8: return kAlpha_8_SkColorType;
+ case GrGLFormat::kRG8: return kR8G8_unorm_SkColorType;
+ case GrGLFormat::kRGB8: return kRGB_888x_SkColorType;
+ case GrGLFormat::kRGBA8: return kRGBA_8888_SkColorType;
+ case GrGLFormat::kBGRA8: return kBGRA_8888_SkColorType;
+ case GrGLFormat::kRGB10_A2: return kRGBA_1010102_SkColorType;
+ case GrGLFormat::kLUMINANCE16F: // fall through
+ case GrGLFormat::kR16F: return kA16_float_SkColorType;
+ case GrGLFormat::kRG16F: return kR16G16_float_SkColorType;
+ case GrGLFormat::kR16: return kA16_unorm_SkColorType;
+ case GrGLFormat::kRG16: return kR16G16_unorm_SkColorType;
+ case GrGLFormat::kRGBA16: return kR16G16B16A16_unorm_SkColorType;
+ default: return kUnknown_SkColorType;
+ }
+
+ SkUNREACHABLE;
+ }
+
+ VkFormat vkFormat;
+ if (format.asVkFormat(&vkFormat)) {
+ switch (vkFormat) {
+ case VK_FORMAT_R8_UNORM: return kAlpha_8_SkColorType;
+ case VK_FORMAT_R8G8_UNORM: return kR8G8_unorm_SkColorType;
+ case VK_FORMAT_R8G8B8_UNORM: return kRGB_888x_SkColorType;
+ case VK_FORMAT_R8G8B8A8_UNORM: return kRGBA_8888_SkColorType;
+ case VK_FORMAT_B8G8R8A8_UNORM: return kBGRA_8888_SkColorType;
+ case VK_FORMAT_A2B10G10R10_UNORM_PACK32: return kRGBA_1010102_SkColorType;
+ case VK_FORMAT_R16_SFLOAT: return kA16_float_SkColorType;
+ case VK_FORMAT_R16G16_SFLOAT: return kR16G16_float_SkColorType;
+ case VK_FORMAT_R16_UNORM: return kA16_unorm_SkColorType;
+ case VK_FORMAT_R16G16_UNORM: return kR16G16_unorm_SkColorType;
+ case VK_FORMAT_R16G16B16A16_UNORM: return kR16G16B16A16_unorm_SkColorType;
+ default: return kUnknown_SkColorType;
+ }
+
+ SkUNREACHABLE;
+ }
+
+ return kUnknown_SkColorType;
+}
+
namespace skiagm {
// This GM creates an opaque and transparent bitmap, extracts the planes and then recombines
@@ -1033,9 +1082,10 @@
// YV12
class WackyYUVFormatsGM : public GM {
public:
- WackyYUVFormatsGM(bool useTargetColorSpace, bool useDomain)
+ WackyYUVFormatsGM(bool useTargetColorSpace, bool useDomain, bool quarterSize)
: fUseTargetColorSpace(useTargetColorSpace)
- , fUseDomain(useDomain) {
+ , fUseDomain(useDomain)
+ , fQuarterSize(quarterSize) {
this->setBGColor(0xFFCCCCCC);
}
@@ -1049,6 +1099,9 @@
if (fUseDomain) {
name += "_domain";
}
+ if (fQuarterSize) {
+ name += "_qtr";
+ }
return name;
}
@@ -1085,6 +1138,71 @@
}
}
+ // Resize all the backend textures in 'yuvaTextures' to a quarter their size.
+ sk_sp<SkImage> resizeOnGpu(GrContext* context,
+ YUVFormat yuvFormat,
+ SkYUVColorSpace yuvColorSpace,
+ bool opaque,
+ const GrBackendTexture yuvaTextures[],
+ const SkYUVAIndex yuvaIndices[4],
+ int numTextures,
+ SkISize imageSize) {
+ GrBackendTexture shrunkTextures[4];
+
+ for (int i = 0; i < numTextures; ++i) {
+ SkColorType ct = get_color_type(yuvaTextures[i].getBackendFormat());
+ if (ct == kUnknown_SkColorType || !context->colorTypeSupportedAsSurface(ct)) {
+ return nullptr;
+ }
+
+ SkISize shrunkPlaneSize = { yuvaTextures[i].width() / 2, yuvaTextures[i].height() / 2 };
+
+ sk_sp<SkImage> wrappedOrig = SkImage::MakeFromTexture(context, yuvaTextures[i],
+ kTopLeft_GrSurfaceOrigin,
+ ct,
+ kPremul_SkAlphaType,
+ nullptr);
+
+ shrunkTextures[i] = context->createBackendTexture(shrunkPlaneSize.width(),
+ shrunkPlaneSize.height(),
+ yuvaTextures[i].getBackendFormat(),
+ GrMipMapped::kNo,
+ GrRenderable::kYes);
+ if (!shrunkTextures[i].isValid()) {
+ return nullptr;
+ }
+
+ // Store this away so it will be cleaned up at the end.
+ fBackendTextures.push_back(shrunkTextures[i]);
+
+ sk_sp<SkSurface> s = SkSurface::MakeFromBackendTexture(context, shrunkTextures[i],
+ kTopLeft_GrSurfaceOrigin, 0,
+ ct, nullptr, nullptr);
+ if (!s) {
+ return nullptr;
+ }
+ SkCanvas* c = s->getCanvas();
+
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kSrc);
+
+ c->drawImageRect(wrappedOrig,
+ SkRect::MakeWH(shrunkPlaneSize.width(), shrunkPlaneSize.height()),
+ &paint);
+
+ s->flush();
+ }
+
+ SkISize shrunkImageSize = { imageSize.width() / 2, imageSize.height() / 2 };
+
+ return SkImage::MakeFromYUVATextures(context,
+ yuvColorSpace,
+ shrunkTextures,
+ yuvaIndices,
+ shrunkImageSize,
+ kTopLeft_GrSurfaceOrigin);
+ }
+
void createImages(GrContext* context) {
int counter = 0;
for (bool opaque : { false, true }) {
@@ -1125,43 +1243,56 @@
yuvaPixmaps[i] = resultBMs[i].pixmap();
}
- int counterMod = counter % 3;
- if (fUseDomain && counterMod == 0) {
- // Copies flatten to RGB when they copy the YUVA data, which doesn't
- // know about the intended domain and the domain padding bleeds in
- counterMod = 1;
- }
- switch (counterMod) {
- case 0:
- fImages[opaque][cs][format] = SkImage::MakeFromYUVATexturesCopy(
+ if (fQuarterSize) {
+ fImages[opaque][cs][format] = this->resizeOnGpu(
context,
- (SkYUVColorSpace)cs,
+ (YUVFormat) format,
+ (SkYUVColorSpace) cs,
+ opaque,
yuvaTextures,
yuvaIndices,
- { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() },
- kTopLeft_GrSurfaceOrigin);
- break;
- case 1:
- fImages[opaque][cs][format] = SkImage::MakeFromYUVATextures(
- context,
- (SkYUVColorSpace)cs,
- yuvaTextures,
- yuvaIndices,
- { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() },
- kTopLeft_GrSurfaceOrigin);
- break;
- case 2:
- default:
- fImages[opaque][cs][format] = SkImage::MakeFromYUVAPixmaps(
- context,
- (SkYUVColorSpace)cs,
- yuvaPixmaps,
- yuvaIndices,
- { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() },
- kTopLeft_GrSurfaceOrigin, true);
- break;
+ numTextures,
+ fOriginalBMs[opaque].dimensions());
+ } else {
+ int counterMod = counter % 3;
+ if (fUseDomain && counterMod == 0) {
+ // Copies flatten to RGB when they copy the YUVA data, which doesn't
+ // know about the intended domain and the domain padding bleeds in
+ counterMod = 1;
+ }
+
+ switch (counterMod) {
+ case 0:
+ fImages[opaque][cs][format] = SkImage::MakeFromYUVATexturesCopy(
+ context,
+ (SkYUVColorSpace)cs,
+ yuvaTextures,
+ yuvaIndices,
+ { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() },
+ kTopLeft_GrSurfaceOrigin);
+ break;
+ case 1:
+ fImages[opaque][cs][format] = SkImage::MakeFromYUVATextures(
+ context,
+ (SkYUVColorSpace)cs,
+ yuvaTextures,
+ yuvaIndices,
+ { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() },
+ kTopLeft_GrSurfaceOrigin);
+ break;
+ case 2:
+ default:
+ fImages[opaque][cs][format] = SkImage::MakeFromYUVAPixmaps(
+ context,
+ (SkYUVColorSpace)cs,
+ yuvaPixmaps,
+ yuvaIndices,
+ { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() },
+ kTopLeft_GrSurfaceOrigin, true);
+ break;
+ }
+ ++counter;
}
- ++counter;
} else {
fImages[opaque][cs][format] = make_yuv_gen_image(
fOriginalBMs[opaque].info(),
@@ -1177,12 +1308,32 @@
void onDraw(SkCanvas* canvas) override {
this->createImages(canvas->getGrContext());
+ float cellWidth = kTileWidthHeight, cellHeight = kTileWidthHeight;
+ if (fUseDomain) {
+ cellWidth *= 1.5f;
+ cellHeight *= 1.5f;
+ }
+
+ SkRect origSrcRect = SkRect::MakeWH(fOriginalBMs[0].width(), fOriginalBMs[0].height());
+
SkRect srcRect = SkRect::MakeWH(fOriginalBMs[0].width(), fOriginalBMs[0].height());
SkRect dstRect = SkRect::MakeXYWH(kLabelWidth, 0.f, srcRect.width(), srcRect.height());
+ if (fQuarterSize) {
+ if (canvas->getGrContext()) {
+ // The src is only shrunk on the GPU
+ srcRect = SkRect::MakeWH(fOriginalBMs[0].width()/2.0f,
+ fOriginalBMs[0].height()/2.0f);
+ }
+ // but the dest is always drawn smaller
+ dstRect = SkRect::MakeXYWH(kLabelWidth, 0.f,
+ fOriginalBMs[0].width()/2.0f,
+ fOriginalBMs[0].height()/2.0f);
+ }
SkCanvas::SrcRectConstraint constraint = SkCanvas::kFast_SrcRectConstraint;
if (fUseDomain) {
srcRect.inset(kDomainPadding, kDomainPadding);
+ origSrcRect.inset(kDomainPadding, kDomainPadding);
// Draw a larger rectangle to ensure bilerp filtering would normally read outside the
// srcRect and hit the red pixels, if strict constraint weren't used.
dstRect.fRight = kLabelWidth + 1.5f * srcRect.width();
@@ -1201,10 +1352,11 @@
for (int opaque : { 0, 1 }) {
dstRect.offsetTo(dstRect.fLeft, kLabelHeight);
- draw_col_label(canvas, dstRect.fLeft + dstRect.height() / 2, cs, opaque);
+ draw_col_label(canvas, dstRect.fLeft + cellWidth / 2, cs, opaque);
- canvas->drawBitmapRect(fOriginalBMs[opaque], srcRect, dstRect, nullptr, constraint);
- dstRect.offset(0.f, dstRect.height() + kPad);
+ canvas->drawBitmapRect(fOriginalBMs[opaque], origSrcRect, dstRect,
+ nullptr, constraint);
+ dstRect.offset(0.f, cellHeight + kPad);
for (int format = kP016_YUVFormat; format <= kLast_YUVFormat; ++format) {
draw_row_label(canvas, dstRect.fTop, format);
@@ -1216,13 +1368,13 @@
fImages[opaque][cs][format]->makeColorSpace(fTargetColorSpace);
canvas->drawImageRect(csImage, srcRect, dstRect, &paint, constraint);
} else {
- canvas->drawImageRect(fImages[opaque][cs][format], srcRect, dstRect, &paint,
- constraint);
+ canvas->drawImageRect(fImages[opaque][cs][format], srcRect, dstRect,
+ &paint, constraint);
}
- dstRect.offset(0.f, dstRect.height() + kPad);
+ dstRect.offset(0.f, cellHeight + kPad);
}
- dstRect.offset(dstRect.width() + kPad, 0.f);
+ dstRect.offset(cellWidth + kPad, 0.f);
}
}
if (auto context = canvas->getGrContext()) {
@@ -1246,6 +1398,7 @@
SkTArray<GrBackendTexture> fBackendTextures;
bool fUseTargetColorSpace;
bool fUseDomain;
+ bool fQuarterSize;
sk_sp<SkColorSpace> fTargetColorSpace;
typedef GM INHERITED;
@@ -1253,9 +1406,10 @@
//////////////////////////////////////////////////////////////////////////////
-DEF_GM(return new WackyYUVFormatsGM(/* cs */ false, /* domain */ false);)
-DEF_GM(return new WackyYUVFormatsGM(/* cs */ true, /* domain */ false);)
-DEF_GM(return new WackyYUVFormatsGM(/* cs */ false, /* domain */ true);)
+DEF_GM(return new WackyYUVFormatsGM(/* cs */ false, /* domain */ false, /* quarterSize */ false);)
+DEF_GM(return new WackyYUVFormatsGM(/* cs */ false, /* domain */ false, /* quarterSize */ true);)
+DEF_GM(return new WackyYUVFormatsGM(/* cs */ true, /* domain */ false, /* quarterSize */ false);)
+DEF_GM(return new WackyYUVFormatsGM(/* cs */ false, /* domain */ true, /* quarterSize */ false);)
class YUVMakeColorSpaceGM : public GpuGM {
public:
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 22deabd..12d8c5a 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -256,8 +256,7 @@
* use maxSurfaceSampleCountForColorType().
*/
bool colorTypeSupportedAsSurface(SkColorType colorType) const {
- if (kR8G8_unorm_SkColorType == colorType ||
- kR16G16_unorm_SkColorType == colorType ||
+ if (kR16G16_unorm_SkColorType == colorType ||
kA16_unorm_SkColorType == colorType ||
kA16_float_SkColorType == colorType ||
kR16G16_float_SkColorType == colorType ||
diff --git a/include/private/GrImageContext.h b/include/private/GrImageContext.h
index e651964..c9b869c 100644
--- a/include/private/GrImageContext.h
+++ b/include/private/GrImageContext.h
@@ -18,7 +18,7 @@
public:
~GrImageContext() override;
- GrBackendFormat defaultBackendFormat(SkColorType ct, GrRenderable renderable) const {
+ SK_API GrBackendFormat defaultBackendFormat(SkColorType ct, GrRenderable renderable) const {
return INHERITED::defaultBackendFormat(ct, renderable);
}
diff --git a/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-BonusConfigs.json b/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-BonusConfigs.json
index 92b9205..6d6076f 100644
--- a/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-BonusConfigs.json
+++ b/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-BonusConfigs.json
@@ -487,6 +487,10 @@
"serialize-8888",
"gm",
"_",
+ "wacky_yuv_formats_qtr",
+ "serialize-8888",
+ "gm",
+ "_",
"analytic_antialias_convex",
"serialize-8888",
"gm",
diff --git a/infra/bots/recipes/test.py b/infra/bots/recipes/test.py
index 0652b90..d7d30ca 100644
--- a/infra/bots/recipes/test.py
+++ b/infra/bots/recipes/test.py
@@ -555,6 +555,7 @@
bad_serialize_gms.append('readpixels')
bad_serialize_gms.append('draw_image_set_rect_to_rect')
bad_serialize_gms.append('compositor_quads_shader')
+ bad_serialize_gms.append('wacky_yuv_formats_qtr')
# This GM forces a path to be convex. That property doesn't survive
# serialization.
diff --git a/tests/ExtendedSkColorTypeTests.cpp b/tests/ExtendedSkColorTypeTests.cpp
index be5e90a..9c1063e 100644
--- a/tests/ExtendedSkColorTypeTests.cpp
+++ b/tests/ExtendedSkColorTypeTests.cpp
@@ -48,28 +48,30 @@
SkColorType fColorType;
SkAlphaType fAlphaType;
SkColorTypeComponentFlag fComponents;
- bool fCanMakeSurfaces;
+ bool fGpuCanMakeSurfaces;
+ bool fCpuCanMakeSurfaces;
};
static const TestCase gTests[] = {
- { kAlpha_8_SkColorType, kPremul_SkAlphaType, kAlpha_SkColorTypeComponentFlag, true },
- { kA16_unorm_SkColorType, kPremul_SkAlphaType, kAlpha_SkColorTypeComponentFlag, false },
- { kA16_float_SkColorType, kPremul_SkAlphaType, kAlpha_SkColorTypeComponentFlag, false },
- { kRGB_565_SkColorType, kOpaque_SkAlphaType, kRGB_SkColorTypeComponentFlags, true },
- { kARGB_4444_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true },
- { kRGBA_8888_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true },
- { kRGB_888x_SkColorType, kOpaque_SkAlphaType, kRGB_SkColorTypeComponentFlags, true },
- { kBGRA_8888_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true },
- { kRGBA_1010102_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true },
- { kRGB_101010x_SkColorType, kOpaque_SkAlphaType, kRGB_SkColorTypeComponentFlags, true },
- { kGray_8_SkColorType, kOpaque_SkAlphaType, kGray_SkColorTypeComponentFlag, true },
- { kRGBA_F16Norm_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true },
- { kRGBA_F16_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true },
- { kRGBA_F32_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true },
- { kR8G8_unorm_SkColorType, kOpaque_SkAlphaType, kRG_SkColorTypeComponentFlags, false },
- { kR16G16_unorm_SkColorType, kOpaque_SkAlphaType, kRG_SkColorTypeComponentFlags, false },
- { kR16G16_float_SkColorType, kOpaque_SkAlphaType, kRG_SkColorTypeComponentFlags, false },
- { kR16G16B16A16_unorm_SkColorType,kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, false },
+ { kAlpha_8_SkColorType, kPremul_SkAlphaType, kAlpha_SkColorTypeComponentFlag, true, true },
+ { kA16_unorm_SkColorType, kPremul_SkAlphaType, kAlpha_SkColorTypeComponentFlag, false, false},
+ { kA16_float_SkColorType, kPremul_SkAlphaType, kAlpha_SkColorTypeComponentFlag, false, false},
+ { kRGB_565_SkColorType, kOpaque_SkAlphaType, kRGB_SkColorTypeComponentFlags, true, true },
+ { kARGB_4444_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true, true },
+ { kRGBA_8888_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true, true },
+ { kRGB_888x_SkColorType, kOpaque_SkAlphaType, kRGB_SkColorTypeComponentFlags, true, true },
+ { kBGRA_8888_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true, true },
+ { kRGBA_1010102_SkColorType,kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true, true },
+ { kRGB_101010x_SkColorType, kOpaque_SkAlphaType, kRGB_SkColorTypeComponentFlags, true, true },
+ { kGray_8_SkColorType, kOpaque_SkAlphaType, kGray_SkColorTypeComponentFlag, true, true },
+ { kRGBA_F16Norm_SkColorType,kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true, true },
+ { kRGBA_F16_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true, true },
+ { kRGBA_F32_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true, true },
+ { kR8G8_unorm_SkColorType, kOpaque_SkAlphaType, kRG_SkColorTypeComponentFlags, true, false},
+ { kR16G16_unorm_SkColorType,kOpaque_SkAlphaType, kRG_SkColorTypeComponentFlags, false, false},
+ { kR16G16_float_SkColorType,kOpaque_SkAlphaType, kRG_SkColorTypeComponentFlags, false, false},
+ { kR16G16B16A16_unorm_SkColorType,
+ kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, false, false},
};
static void raster_tests(skiatest::Reporter* reporter, const TestCase& test) {
@@ -84,7 +86,7 @@
// Not all colorTypes can be drawn to
{
auto s = SkSurface::MakeRaster(nativeII);
- REPORTER_ASSERT(reporter, SkToBool(s) == test.fCanMakeSurfaces);
+ REPORTER_ASSERT(reporter, SkToBool(s) == test.fCpuCanMakeSurfaces);
}
// opaque formats should make transparent black become opaque
@@ -177,7 +179,7 @@
kUnpremul_SkAlphaType);
// We had better not be able to render to prohibited colorTypes
- if (!test.fCanMakeSurfaces) {
+ if (!test.fGpuCanMakeSurfaces) {
auto s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, nativeII);
REPORTER_ASSERT(reporter, !SkToBool(s));
}