Add a mechanism for GMs to silently exclude themselves from Gold

This is useful, for example, when trying to test a hardware feature
that isn't supported in the current context.

Bug: skia:8731
Change-Id: I9a363159300c92e4039bfd05400238c27002efb1
Reviewed-on: https://skia-review.googlesource.com/c/189133
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
Chris Dalton 2019-02-07 16:20:09 -07:00 committed by Skia Commit-Bot
parent f439600429
commit 50e24d7d5f
37 changed files with 342 additions and 228 deletions

View File

@ -91,7 +91,11 @@ GMSrc::GMSrc(skiagm::GMFactory factory) : fFactory(factory) {}
Error GMSrc::draw(SkCanvas* canvas) const {
std::unique_ptr<skiagm::GM> gm(fFactory(nullptr));
gm->draw(canvas);
SkString errorMsg;
skiagm::DrawResult drawResult = gm->draw(canvas, &errorMsg);
if (skiagm::DrawResult::kSkip == drawResult) {
return Error::Nonfatal(std::move(errorMsg)); // Cause this test to be skipped.
}
return "";
}

View File

@ -101,10 +101,10 @@ protected:
proc(0xC0FF0000, m4 * tmp);
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
if (!fAnim) {
DrawFailureMessage(canvas, "No animation.");
return;
*errorMsg = "No animation.";
return DrawResult::kFail;
}
SkMatrix44 camera,
perspective,
@ -175,6 +175,7 @@ protected:
fAnim->seek(fAnimT);
draw_skia(canvas, mv, viewport, fAnim.get());
return DrawResult::kOk;
}
SkISize onISize() override { return { 1024, 768 }; }

View File

@ -112,10 +112,10 @@ private:
return true;
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
if (!this->initCodec()) {
DrawFailureMessage(canvas, "Could not create codec from %s", FLAGS_animatedGif[0]);
return;
errorMsg->printf("Could not create codec from %s", FLAGS_animatedGif[0]);
return DrawResult::kFail;
}
canvas->save();
@ -128,6 +128,7 @@ private:
SkAutoCanvasRestore acr(canvas, true);
canvas->translate(0, SkIntToScalar(fCodec->getInfo().height()));
this->drawFrame(canvas, fFrame);
return DrawResult::kOk;
}
bool onAnimate(const SkAnimTimer& timer) override {

View File

@ -86,16 +86,17 @@ protected:
fTypefaces[5] = sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::Bold());
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
if (!fRenderer || !fTarget || !fTarget->handle()) {
DrawFailureMessage(canvas, "No renderer and/or target.");
return;
*errorMsg = "No renderer and/or target.";
return DrawResult::kFail;
}
fRenderer->clearTarget(fTarget->handle(), 0xFF808080);
auto bmp = this->drawText();
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc);
canvas->drawBitmap(bmp, 0, 0);
return DrawResult::kOk;
}
private:

View File

@ -26,14 +26,14 @@ protected:
return SkISize::Make(2*kSize, 2*kSize);
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
// Create image.
const char* path = "images/mandrill_512_q075.jpg";
sk_sp<SkImage> image = GetResourceAsImage(path);
if (!image) {
DrawFailureMessage(canvas, "Couldn't load images/mandrill_512_q075.jpg. "
"Did you forget to set the resource path?");
return;
*errorMsg = "Couldn't load images/mandrill_512_q075.jpg. "
"Did you forget to set the resource path?";
return DrawResult::kFail;
}
// Create matching bitmap.
@ -63,6 +63,7 @@ protected:
srgbCanvas.translate(SkScalar(kSize), 0.0f);
srgbCanvas.drawBitmap(bitmap, 0.0f, 0.0f, nullptr);
canvas->drawBitmap(srgbBMCanvas, 0.0f, 0.0f, nullptr);
return DrawResult::kOk;
}
private:

View File

@ -52,12 +52,11 @@ DEF_SIMPLE_GM(blurimagevmask, canvas, 700, 1200) {
}
#include "Resources.h"
DEF_SIMPLE_GM(blur_image, canvas, 500, 500) {
DEF_SIMPLE_GM_CAN_FAIL(blur_image, canvas, errorMsg, 500, 500) {
auto image = GetResourceAsImage("images/mandrill_128.png");
if (!image) {
skiagm::GM::DrawFailureMessage(canvas, "Could not load mandrill_128.png. "
"Did you forget to set the resourcePath?");
return;
*errorMsg = "Could not load mandrill_128.png. Did you forget to set the resourcePath?";
return skiagm::DrawResult::kFail;
}
SkPaint paint;
@ -69,4 +68,5 @@ DEF_SIMPLE_GM(blur_image, canvas, 500, 500) {
canvas->drawImage(image, 10, 10, &paint);
canvas->scale(1.01f, 1.01f);
canvas->drawImage(image, 10 + image->width() + 10.f, 10, &paint);
return skiagm::DrawResult::kOk;
}

View File

@ -30,18 +30,18 @@ protected:
return SkISize::Make(360, 180);
}
virtual void onDraw(SkCanvas* canvas) {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) {
SkBitmap bm, bm4444;
if (!GetResourceAsBitmap("images/dog.jpg", &bm)) {
DrawFailureMessage(canvas, "Could not decode the file. "
"Did you forget to set the resourcePath?");
return;
*errorMsg = "Could not decode the file. Did you forget to set the resourcePath?";
return DrawResult::kFail;
}
canvas->drawBitmap(bm, 0, 0);
// This should dither or we will see artifacts in the background of the image.
SkAssertResult(sk_tool_utils::copy_to(&bm4444, kARGB_4444_SkColorType, bm));
canvas->drawBitmap(bm4444, SkIntToScalar(bm.width()), 0);
return DrawResult::kOk;
}
private:

View File

@ -8,11 +8,11 @@
#include "gm.h"
#include "SkParsePath.h"
DEF_SIMPLE_GM(crbug_691386, canvas, 256, 256) {
DEF_SIMPLE_GM_CAN_FAIL(crbug_691386, canvas, errorMsg, 256, 256) {
SkPath path;
if (!SkParsePath::FromSVGString("M -1 0 A 1 1 0 0 0 1 0 Z", &path)) {
skiagm::GM::DrawFailureMessage(canvas, "Failed to parse path.");
return;
*errorMsg = "Failed to parse path.";
return skiagm::DrawResult::kFail;
}
SkPaint p;
p.setStyle(SkPaint::kStroke_Style);
@ -20,4 +20,5 @@ DEF_SIMPLE_GM(crbug_691386, canvas, 256, 256) {
canvas->scale(96.0f, 96.0f);
canvas->translate(1.25f, 1.25f);
canvas->drawPath(path, p);
return skiagm::DrawResult::kOk;
}

View File

@ -11,12 +11,12 @@
#include "GrContext.h"
#include "SkImage.h"
DEF_SIMPLE_GPU_GM(cross_context_image, context, rtc, canvas, 5 * 256 + 60, 256 + 128 + 30) {
DEF_SIMPLE_GPU_GM_CAN_FAIL(cross_context_image, context, rtc, canvas, errorMsg,
5 * 256 + 60, 256 + 128 + 30) {
sk_sp<SkData> encodedData = GetResourceAsData("images/mandrill_256.png");
if (!encodedData) {
skiagm::GM::DrawFailureMessage(canvas, "Could not load mandrill_256.png. "
"Did you forget to set the resourcePath?");
return;
*errorMsg = "Could not load mandrill_256.png. Did you forget to set the resourcePath?";
return skiagm::DrawResult::kFail;
}
sk_sp<SkImage> images[5];
@ -50,4 +50,5 @@ DEF_SIMPLE_GPU_GM(cross_context_image, context, rtc, canvas, 5 * 256 + 60, 256 +
canvas->restore();
canvas->translate(256 + 10, 0);
}
return skiagm::DrawResult::kOk;
}

View File

@ -33,15 +33,16 @@ protected:
return SkISize::Make(100, 100);
}
void onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas) override {
DrawResult onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas,
SkString* errorMsg) override {
SkISize size = this->getISize();
size.fWidth /= 10;
size.fHeight /= 10;
SkImageInfo info = SkImageInfo::MakeN32Premul(size);
auto surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
if (nullptr == surface) {
DrawFailureMessage(canvas, "Could not create render target.");
return;
*errorMsg = "Could not create render target.";
return DrawResult::kFail;
}
canvas->clear(SK_ColorBLACK);
@ -70,6 +71,7 @@ protected:
}
surface->getCanvas()->discard();
return DrawResult::kOk;
}
private:

View File

@ -42,12 +42,12 @@ protected:
return SkISize::Make(400, 200);
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
sk_sp<SkImage> srcImg = GetResourceAsImage("images/rainbow-gradient.png");
if (!srcImg) {
DrawFailureMessage(canvas, "Could not load images/rainbow-gradient.png. "
"Did you forget to set the resourcePath?");
return;
*errorMsg = "Could not load images/rainbow-gradient.png. "
"Did you forget to set the resourcePath?";
return DrawResult::kFail;
}
fStorage.reset(srcImg->width() * srcImg->height() *
SkColorTypeBytesPerPixel(kRGBA_F16_SkColorType));
@ -89,6 +89,7 @@ protected:
canvas->drawImage(img0, 300.0f, 0.0f);
canvas->drawImage(img1, 300.0f, 100.0f);
}
return DrawResult::kOk;
}
private:

View File

@ -81,19 +81,19 @@ protected:
return SkISize::Make(256 * SK_ARRAY_COUNT(kTypes), 256 * 3);
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
SkBitmap opaqueBm, premulBm, unpremulBm;
if (!GetResourceAsBitmap("images/mandrill_256.png", &opaqueBm)) {
DrawFailureMessage(canvas, "Could not load images/mandrill_256.png.png. "
"Did you forget to set the resourcePath?");
return;
*errorMsg = "Could not load images/mandrill_256.png.png. "
"Did you forget to set the resourcePath?";
return DrawResult::kFail;
}
SkBitmap tmp;
if (!GetResourceAsBitmap("images/yellow_rose.png", &tmp)) {
DrawFailureMessage(canvas, "Could not load images/yellow_rose.png. "
"Did you forget to set the resourcePath?");
return;
*errorMsg = "Could not load images/yellow_rose.png. "
"Did you forget to set the resourcePath?";
return DrawResult::kFail;
}
tmp.extractSubset(&premulBm, SkIRect::MakeWH(256, 256));
tmp.reset();
@ -111,6 +111,7 @@ protected:
canvas->translate(256.0f, 0.0f);
}
return DrawResult::kOk;
}
private:

View File

@ -62,8 +62,7 @@ protected:
}
}
void onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
SkCanvas* canvas) override {
void onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas) override {
sk_sp<SkImage> image = SkImage::MakeFromCompressed(context, fETC1Data,
kTexWidth, kTexHeight,
SkImage::kETC1_CompressionType);

View File

@ -60,7 +60,7 @@ protected:
fTypefaces[5] = sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::Bold());
}
void onDraw(GrContext*, GrRenderTargetContext* renderTargetContext, SkCanvas* canvas) override {
void onDraw(GrContext*, GrRenderTargetContext*, SkCanvas* canvas) override {
this->drawText(canvas);
// Debugging tool for GPU.
static const bool kShowAtlas = false;

View File

@ -172,7 +172,7 @@ protected:
}
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
SkFont font;
font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
font.setSubpixel(true);
@ -190,14 +190,15 @@ protected:
}
}
if (nullptr == fset.get()) {
DrawFailureMessage(canvas, "No SkFontStyleSet");
return;
*errorMsg = "No SkFontStyleSet";
return DrawResult::kFail;
}
canvas->translate(20, 40);
this->exploreFamily(canvas, font, fset.get());
canvas->translate(150, 0);
this->iterateFamily(canvas, font, fset.get());
return DrawResult::kOk;
}
private:

View File

@ -76,7 +76,7 @@ protected:
fBlobs[2] = make_blob(kTexts[2], font);
}
void onDraw(GrContext*, GrRenderTargetContext* renderTargetContext, SkCanvas* canvas) override {
void onDraw(GrContext*, GrRenderTargetContext*, SkCanvas* canvas) override {
SkPaint paint;
paint.setColor(SK_ColorBLACK);
canvas->drawTextBlob(fBlobs[0], 10, 80, paint);

View File

@ -30,7 +30,7 @@ protected:
return SkISize::Make(550, 700);
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
SkPaint paint;
paint.setAntiAlias(true);
SkFont font;
@ -41,8 +41,8 @@ protected:
sk_sp<SkTypeface> distortable(MakeResourceAsTypeface("fonts/Distortable.ttf"));
if (!distortableStream) {
DrawFailureMessage(canvas, "No distortableStream");
return;
*errorMsg = "No distortableStream";
return DrawResult::kFail;
}
const char* text = "abc";
const size_t textLen = strlen(text);
@ -89,6 +89,7 @@ protected:
canvas->translate(0, SkIntToScalar(360));
font.setSubpixel(true);
}
return DrawResult::kOk;
}
private:

View File

@ -154,15 +154,16 @@ private:
////////////////////////////////////////////////////////////////////////////////////////////////////
// Test.
DEF_SIMPLE_GPU_GM(fwidth_squircle, ctx, rtc, canvas, 200, 200) {
DEF_SIMPLE_GPU_GM_CAN_FAIL(fwidth_squircle, ctx, rtc, canvas, errorMsg, 200, 200) {
if (!ctx->priv().caps()->shaderCaps()->shaderDerivativeSupport()) {
skiagm::GM::DrawFailureMessage(canvas, "Shader derivatives not supported.");
return;
*errorMsg = "Shader derivatives not supported.";
return DrawResult::kSkip;
}
// Draw the test directly to the frame buffer.
canvas->clear(SK_ColorWHITE);
rtc->priv().testingOnly_addDrawOp(FwidthSquircleTestOp::Make(ctx, canvas->getTotalMatrix()));
return skiagm::DrawResult::kOk;
}
}

106
gm/gm.cpp
View File

@ -13,6 +13,44 @@
#include "SkTraceEvent.h"
using namespace skiagm;
constexpr char GM::kErrorMsg_DrawSkippedGpuOnly[];
static void draw_failure_message(SkCanvas* canvas, const char format[], ...) {
SkString failureMsg;
va_list argp;
va_start(argp, format);
failureMsg.appendVAList(format, argp);
va_end(argp);
constexpr SkScalar kOffset = 5.0f;
canvas->drawColor(SkColorSetRGB(200,0,0));
SkFont font;
SkRect bounds;
font.measureText(failureMsg.c_str(), failureMsg.size(), kUTF8_SkTextEncoding, &bounds);
SkPaint textPaint;
textPaint.setColor(SK_ColorWHITE);
canvas->drawString(failureMsg, kOffset, bounds.height() + kOffset, font, textPaint);
}
static void draw_gpu_only_message(SkCanvas* canvas) {
SkBitmap bmp;
bmp.allocN32Pixels(128, 64);
SkCanvas bmpCanvas(bmp);
bmpCanvas.drawColor(SK_ColorWHITE);
SkFont font(sk_tool_utils::create_portable_typeface(), 20);
SkPaint paint;
paint.setColor(SK_ColorRED);
bmpCanvas.drawString("GPU Only", 20, 40, font, paint);
SkMatrix localM;
localM.setRotate(35.f);
localM.postTranslate(10.f, 0.f);
paint.setShader(SkShader::MakeBitmapShader(
bmp, SkShader::kMirror_TileMode, SkShader::kMirror_TileMode, &localM));
paint.setFilterQuality(kMedium_SkFilterQuality);
canvas->drawPaint(paint);
}
GM::GM(SkColor bgColor) {
fMode = kGM_Mode;
fBGColor = bgColor;
@ -22,20 +60,30 @@ GM::GM(SkColor bgColor) {
GM::~GM() {}
void GM::draw(SkCanvas* canvas) {
DrawResult GM::draw(SkCanvas* canvas, SkString* errorMsg) {
TRACE_EVENT1("GM", TRACE_FUNC, "name", TRACE_STR_COPY(this->getName()));
this->drawBackground(canvas);
this->drawContent(canvas);
return this->drawContent(canvas, errorMsg);
}
void GM::drawContent(SkCanvas* canvas) {
DrawResult GM::drawContent(SkCanvas* canvas, SkString* errorMsg) {
TRACE_EVENT0("GM", TRACE_FUNC);
if (!fHaveCalledOnceBeforeDraw) {
fHaveCalledOnceBeforeDraw = true;
this->onOnceBeforeDraw();
}
SkAutoCanvasRestore acr(canvas, true);
this->onDraw(canvas);
DrawResult drawResult = this->onDraw(canvas, errorMsg);
if (DrawResult::kOk != drawResult) {
if (DrawResult::kFail == drawResult) {
draw_failure_message(canvas, "DRAW FAILED: %s", errorMsg->c_str());
} else if (SkString(kErrorMsg_DrawSkippedGpuOnly) == *errorMsg) {
draw_gpu_only_message(canvas);
} else {
draw_failure_message(canvas, "DRAW SKIPPED: %s", errorMsg->c_str());
}
}
return drawResult;
}
void GM::drawBackground(SkCanvas* canvas) {
@ -74,59 +122,21 @@ void GM::drawSizeBounds(SkCanvas* canvas, SkColor color) {
canvas->drawRect(r, paint);
}
void GM::DrawGpuOnlyMessage(SkCanvas* canvas) {
SkBitmap bmp;
bmp.allocN32Pixels(128, 64);
SkCanvas bmpCanvas(bmp);
bmpCanvas.drawColor(SK_ColorWHITE);
SkFont font(sk_tool_utils::create_portable_typeface(), 20);
SkPaint paint;
paint.setColor(SK_ColorRED);
bmpCanvas.drawString("GPU Only", 20, 40, font, paint);
SkMatrix localM;
localM.setRotate(35.f);
localM.postTranslate(10.f, 0.f);
paint.setShader(SkShader::MakeBitmapShader(bmp, SkShader::kMirror_TileMode,
SkShader::kMirror_TileMode,
&localM));
paint.setFilterQuality(kMedium_SkFilterQuality);
canvas->drawPaint(paint);
return;
}
void GM::DrawFailureMessage(SkCanvas* canvas, const char format[], ...) {
SkString failureMsg;
va_list argp;
va_start(argp, format);
failureMsg.appendVAList(format, argp);
va_end(argp);
constexpr SkScalar kOffset = 5.0f;
canvas->drawColor(SkColorSetRGB(200,0,0));
SkFont font;
SkRect bounds;
font.measureText(failureMsg.c_str(), failureMsg.size(), kUTF8_SkTextEncoding, &bounds);
SkPaint textPaint;
textPaint.setColor(SK_ColorWHITE);
canvas->drawString(failureMsg, kOffset, bounds.height() + kOffset, font, textPaint);
}
// need to explicitly declare this, or we get some weird infinite loop llist
template GMRegistry* GMRegistry::gHead;
void GpuGM::onDraw(SkCanvas* canvas) {
DrawResult GpuGM::onDraw(SkCanvas* canvas, SkString* errorMsg) {
GrContext* ctx = canvas->getGrContext();
GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
if (!ctx || !rtc) {
skiagm::GM::DrawGpuOnlyMessage(canvas);
return;
*errorMsg = kErrorMsg_DrawSkippedGpuOnly;
return DrawResult::kSkip;
}
if (ctx->abandoned()) {
skiagm::GM::DrawFailureMessage(canvas, "GrContext abandoned.");
return;
*errorMsg = "GrContext abandoned.";
return DrawResult::kFail;
}
this->onDraw(ctx, rtc, canvas);
return this->onDraw(ctx, rtc, canvas, errorMsg);
}
template <typename Fn>

105
gm/gm.h
View File

@ -36,26 +36,62 @@ struct GrContextOptions;
#define DEF_SIMPLE_GM_BG(NAME, CANVAS, W, H, BGCOLOR) \
DEF_SIMPLE_GM_BG_NAME(NAME, CANVAS, W, H, BGCOLOR, SkString(#NAME))
#define DEF_SIMPLE_GM_BG_NAME(NAME, CANVAS, W, H, BGCOLOR, NAME_STR) \
static void SK_MACRO_CONCAT(NAME, _GM)(SkCanvas * CANVAS); \
DEF_GM(return new skiagm::SimpleGM(BGCOLOR, NAME_STR, SkISize::Make(W, H), \
SK_MACRO_CONCAT(NAME, _GM));) \
void SK_MACRO_CONCAT(NAME, _GM)(SkCanvas * CANVAS)
static void SK_MACRO_CONCAT(NAME,_GM_inner)(SkCanvas*); \
DEF_SIMPLE_GM_BG_NAME_CAN_FAIL(NAME, CANVAS,, W, H, BGCOLOR, NAME_STR) { \
SK_MACRO_CONCAT(NAME,_GM_inner)(CANVAS); \
return skiagm::DrawResult::kOk; \
} \
void SK_MACRO_CONCAT(NAME,_GM_inner)(SkCanvas* CANVAS)
#define DEF_SIMPLE_GM_CAN_FAIL(NAME, CANVAS, ERR_MSG, W, H) \
DEF_SIMPLE_GM_BG_NAME_CAN_FAIL(NAME, CANVAS, ERR_MSG, W, H, SK_ColorWHITE, SkString(#NAME))
#define DEF_SIMPLE_GM_BG_CAN_FAIL(NAME, CANVAS, ERR_MSG, W, H, BGCOLOR) \
DEF_SIMPLE_GM_BG_NAME_CAN_FAIL(NAME, CANVAS, ERR_MSG, W, H, BGCOLOR, SkString(#NAME))
#define DEF_SIMPLE_GM_BG_NAME_CAN_FAIL(NAME, CANVAS, ERR_MSG, W, H, BGCOLOR, NAME_STR) \
static skiagm::DrawResult SK_MACRO_CONCAT(NAME,_GM)(SkCanvas*, SkString*); \
DEF_GM(return new skiagm::SimpleGM(BGCOLOR, NAME_STR, {W,H}, SK_MACRO_CONCAT(NAME,_GM));) \
skiagm::DrawResult SK_MACRO_CONCAT(NAME,_GM)(SkCanvas* CANVAS, SkString* ERR_MSG)
// A Simple GpuGM makes direct GPU calls. Its onDraw hook that includes GPU objects as params, and
// is only invoked on GPU configs. Non-GPU configs automatically draw a GPU-only message and abort.
#define DEF_SIMPLE_GPU_GM(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS, W, H) \
DEF_SIMPLE_GPU_GM_BG(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS, W, H, SK_ColorWHITE)
#define DEF_SIMPLE_GPU_GM_BG(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS, W, H, BGCOLOR)\
static void SK_MACRO_CONCAT(NAME, _GM)(GrContext*, GrRenderTargetContext*, SkCanvas*); \
DEF_GM(return new skiagm::SimpleGpuGM(BGCOLOR, SkString(#NAME), SkISize::Make(W, H), \
SK_MACRO_CONCAT(NAME, _GM));) \
void SK_MACRO_CONCAT(NAME, _GM)( \
#define DEF_SIMPLE_GPU_GM_BG(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS, W, H, BGCOLOR) \
static void SK_MACRO_CONCAT(NAME,_GM_inner)(GrContext*, GrRenderTargetContext*, SkCanvas*); \
DEF_SIMPLE_GPU_GM_BG_CAN_FAIL(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS,, W, H, \
BGCOLOR) { \
SK_MACRO_CONCAT(NAME,_GM_inner)(GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS); \
return skiagm::DrawResult::kOk; \
} \
void SK_MACRO_CONCAT(NAME,_GM_inner)( \
GrContext* GR_CONTEXT, GrRenderTargetContext* RENDER_TARGET_CONTEXT, SkCanvas* CANVAS)
#define DEF_SIMPLE_GPU_GM_CAN_FAIL(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS, ERR_MSG, W, H) \
DEF_SIMPLE_GPU_GM_BG_CAN_FAIL(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS, \
ERR_MSG, W, H, SK_ColorWHITE)
#define DEF_SIMPLE_GPU_GM_BG_CAN_FAIL(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS, ERR_MSG, W, \
H, BGCOLOR) \
static skiagm::DrawResult SK_MACRO_CONCAT(NAME,_GM)( \
GrContext*, GrRenderTargetContext*, SkCanvas*, SkString*); \
DEF_GM(return new skiagm::SimpleGpuGM(BGCOLOR, SkString(#NAME), {W,H}, \
SK_MACRO_CONCAT(NAME,_GM));) \
skiagm::DrawResult SK_MACRO_CONCAT(NAME,_GM)( \
GrContext* GR_CONTEXT, GrRenderTargetContext* RENDER_TARGET_CONTEXT, SkCanvas* CANVAS, \
SkString* ERR_MSG)
namespace skiagm {
enum class DrawResult {
kOk, // Test drew successfully.
kFail, // Test failed to draw.
kSkip // Test is not applicable in this context and should be skipped.
};
class GM {
public:
using DrawResult = skiagm::DrawResult;
GM(SkColor backgroundColor = SK_ColorWHITE);
virtual ~GM();
@ -68,9 +104,20 @@ namespace skiagm {
void setMode(Mode mode) { fMode = mode; }
Mode getMode() const { return fMode; }
void draw(SkCanvas*);
static constexpr char kErrorMsg_DrawSkippedGpuOnly[] = "This test is for GPU configs only.";
DrawResult draw(SkCanvas* canvas) {
SkString errorMsg;
return this->draw(canvas, &errorMsg);
}
DrawResult draw(SkCanvas*, SkString* errorMsg);
void drawBackground(SkCanvas*);
void drawContent(SkCanvas*);
DrawResult drawContent(SkCanvas* canvas) {
SkString errorMsg;
return this->drawContent(canvas, &errorMsg);
}
DrawResult drawContent(SkCanvas*, SkString* errorMsg);
SkISize getISize() { return this->onISize(); }
const char* getName();
@ -105,14 +152,13 @@ namespace skiagm {
virtual void modifyGrContextOptions(GrContextOptions* options) {}
/** draws a standard message that the GM is only intended to be used with the GPU.*/
static void DrawGpuOnlyMessage(SkCanvas*);
static void DrawFailureMessage(SkCanvas*, const char[], ...) SK_PRINTF_LIKE(2, 3);
protected:
virtual void onOnceBeforeDraw() {}
virtual void onDraw(SkCanvas*) = 0;
virtual DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) {
this->onDraw(canvas);
return DrawResult::kOk;
}
virtual void onDraw(SkCanvas*) { SK_ABORT("Not implemented."); }
virtual SkISize onISize() = 0;
virtual SkString onShortName() = 0;
@ -139,22 +185,32 @@ namespace skiagm {
public:
GpuGM(SkColor backgroundColor = SK_ColorWHITE) : GM(backgroundColor) {}
private:
void onDraw(SkCanvas*) final;
virtual void onDraw(GrContext*, GrRenderTargetContext*, SkCanvas*) = 0;
using GM::onDraw;
DrawResult onDraw(SkCanvas*, SkString* errorMsg) final;
virtual DrawResult onDraw(GrContext* ctx, GrRenderTargetContext* rtc, SkCanvas* canvas,
SkString* errorMsg) {
this->onDraw(ctx, rtc, canvas);
return DrawResult::kOk;
}
virtual void onDraw(GrContext*, GrRenderTargetContext*, SkCanvas*) {
SK_ABORT("Not implemented.");
}
};
// SimpleGM is intended for basic GMs that can define their entire implementation inside a
// single "draw" function pointer.
class SimpleGM : public GM {
public:
using DrawProc = void(*)(SkCanvas*);
using DrawProc = DrawResult(*)(SkCanvas*, SkString*);
SimpleGM(SkColor bgColor, const SkString& name, const SkISize& size, DrawProc drawProc)
: GM(bgColor), fName(name), fSize(size), fDrawProc(drawProc) {}
private:
SkISize onISize() override { return fSize; }
SkString onShortName() override { return fName; }
void onDraw(SkCanvas* canvas) override { fDrawProc(canvas); }
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
return fDrawProc(canvas, errorMsg);
}
const SkString fName;
const SkISize fSize;
@ -163,15 +219,16 @@ namespace skiagm {
class SimpleGpuGM : public GpuGM {
public:
using DrawProc = void(*)(GrContext*, GrRenderTargetContext*, SkCanvas*);
using DrawProc = DrawResult(*)(GrContext*, GrRenderTargetContext*, SkCanvas*, SkString*);
SimpleGpuGM(SkColor bgColor, const SkString& name, const SkISize& size, DrawProc drawProc)
: GpuGM(bgColor), fName(name), fSize(size), fDrawProc(drawProc) {}
private:
SkISize onISize() override { return fSize; }
SkString onShortName() override { return fName; }
void onDraw(GrContext* ctx, GrRenderTargetContext* rtc, SkCanvas* canvas) override {
fDrawProc(ctx, rtc, canvas);
DrawResult onDraw(GrContext* ctx, GrRenderTargetContext* rtc, SkCanvas* canvas,
SkString* errorMsg) override {
return fDrawProc(ctx, rtc, canvas, errorMsg);
}
const SkString fName;

View File

@ -396,13 +396,13 @@ static sk_sp<SkImage> serial_deserial(SkImage* img) {
return reader.readImage();
}
DEF_SIMPLE_GM(image_subset, canvas, 440, 220) {
DEF_SIMPLE_GM_CAN_FAIL(image_subset, canvas, errorMsg, 440, 220) {
SkImageInfo info = SkImageInfo::MakeN32Premul(200, 200, nullptr);
auto surf = sk_tool_utils::makeSurface(canvas, info, nullptr);
auto img = make_lazy_image(surf.get());
if (!img) {
skiagm::GM::DrawFailureMessage(canvas, "Failed to make lazy image.");
return;
*errorMsg = "Failed to make lazy image.";
return skiagm::DrawResult::kFail;
}
canvas->drawImage(img, 10, 10, nullptr);
@ -410,4 +410,5 @@ DEF_SIMPLE_GM(image_subset, canvas, 440, 220) {
canvas->drawImage(sub, 220, 10);
sub = serial_deserial(sub.get());
canvas->drawImage(sub, 220+110, 10);
return skiagm::DrawResult::kOk;
}

View File

@ -122,7 +122,7 @@ protected:
return SkISize::Make(WIDTH, HEIGHT);
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
SkMatrix matrix;
matrix.reset();
matrix.setTranslate(WIDTH * .1f, HEIGHT * .1f);
@ -133,8 +133,8 @@ protected:
sk_sp<SkSurface> surface(make_color_matching_surface(canvas, WIDTH, HEIGHT,
kPremul_SkAlphaType));
if (!surface) {
DrawFailureMessage(canvas, "make_color_matching_surface failed");
return;
*errorMsg = "make_color_matching_surface failed";
return DrawResult::kFail;
}
surface->getCanvas()->clear(SK_ColorTRANSPARENT);
@ -143,6 +143,7 @@ protected:
SkPaint paint = create_filter_paint();
canvas->clipRect(SkRect::MakeLTRB(100, 100, WIDTH - 100, HEIGHT - 100));
canvas->drawImage(surface->makeImageSnapshot().get(), 0, 0, &paint);
return DrawResult::kOk;
}
private:

View File

@ -48,7 +48,7 @@ protected:
return SkISize::Make(128*3, 128*4);
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
sk_sp<SkColorSpace> wideGamut = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
SkNamedGamut::kAdobeRGB);
sk_sp<SkColorSpace> wideGamutLinear = wideGamut->makeLinearGamma();
@ -57,9 +57,8 @@ protected:
sk_sp<SkImage> opaqueImage = GetResourceAsImage("images/mandrill_128.png");
sk_sp<SkImage> premulImage = GetResourceAsImage("images/color_wheel.png");
if (!opaqueImage || !premulImage) {
DrawFailureMessage(canvas, "Failed to load images. "
"Did you forget to set the resourcePath?");
return;
*errorMsg = "Failed to load images. Did you forget to set the resourcePath?";
return DrawResult::kFail;
}
canvas->drawImage(opaqueImage, 0.0f, 0.0f);
canvas->drawImage(make_color_space(opaqueImage, wideGamut), 128.0f, 0.0f);
@ -78,6 +77,7 @@ protected:
canvas->drawImage(premulImage, 0.0f, 128.0f);
canvas->drawImage(make_color_space(premulImage, wideGamut), 128.0f, 128.0f);
canvas->drawImage(make_color_space(premulImage, wideGamutLinear), 256.0f, 128.0f);
return DrawResult::kOk;
}
private:

View File

@ -24,14 +24,14 @@ static void excercise_draw_pos_text(SkCanvas* canvas,
canvas->drawTextBlob(builder.make(), x, y, paint);
}
DEF_SIMPLE_GM(pdf_never_embed, canvas, 512, 512) {
DEF_SIMPLE_GM_CAN_FAIL(pdf_never_embed, canvas, errorMsg, 512, 512) {
SkPaint p;
SkFont font(MakeResourceAsTypeface("fonts/Roboto2-Regular_NoEmbed.ttf"), 60);
if (!font.getTypefaceOrDefault()) {
skiagm::GM::DrawFailureMessage(canvas, "Could not load fonts/Roboto2-Regular_NoEmbed.ttf. "
"Did you forget to set the resourcePath?");
return;
*errorMsg = "Could not load fonts/Roboto2-Regular_NoEmbed.ttf. "
"Did you forget to set the resourcePath?";
return skiagm::DrawResult::kFail;
}
const char text[] = "HELLO, WORLD!";
@ -54,6 +54,7 @@ DEF_SIMPLE_GM(pdf_never_embed, canvas, 512, 512) {
canvas->scale(1.0, 0.5);
p.setColor(0xF0000080);
canvas->drawSimpleText(text, strlen(text), kUTF8_SkTextEncoding, 30, 700, font, p);
return skiagm::DrawResult::kOk;
}

View File

@ -184,10 +184,10 @@ protected:
return SkISize::Make(3 * (kEncodedWidth + 1), 12 * (kEncodedHeight + 1));
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
if (!canvas->imageInfo().colorSpace()) {
// This gm is only interesting in color correct modes.
return;
*errorMsg = "This gm is only interesting in color correct modes.";
return DrawResult::kSkip;
}
const SkAlphaType alphaTypes[] = {
@ -224,6 +224,7 @@ protected:
canvas->restore();
canvas->translate((float) kEncodedWidth + 1, 0.0f);
}
return DrawResult::kOk;
}
private:
@ -247,10 +248,10 @@ protected:
return SkISize::Make(3 * kWidth, 12 * kHeight);
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
if (!canvas->imageInfo().colorSpace()) {
// This gm is only interesting in color correct modes.
return;
*errorMsg = "This gm is only interesting in color correct modes.";
return DrawResult::kSkip;
}
const sk_sp<SkImage> images[] = {
@ -291,6 +292,7 @@ protected:
canvas->translate((float) kWidth, 0.0f);
}
}
return DrawResult::kOk;
}
private:

View File

@ -117,7 +117,8 @@ protected:
return nullptr;
}
void onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas) override {
DrawResult onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas,
SkString* errorMsg) override {
constexpr int kWidth = 50;
constexpr int kHeight = 50;
constexpr SkScalar kPad = 5.f;
@ -133,8 +134,8 @@ protected:
};
SkASSERT(SkToBool(rectImgs[0]) == SkToBool(rectImgs[1]));
if (!rectImgs[0]) {
DrawFailureMessage(canvas, "Could not create rectangle texture image.");
return;
*errorMsg = "Could not create rectangle texture image.";
return DrawResult::kFail;
}
constexpr SkFilterQuality kQualities[] = {
@ -189,6 +190,7 @@ protected:
canvas->translate(0, kPad + 1.5f * kHeight * s);
}
}
return DrawResult::kOk;
}
private:

View File

@ -10,12 +10,13 @@
#include "gm.h"
#include "sk_tool_utils.h"
static void draw_rotated_image(SkCanvas* canvas, const SkImage* image) {
static skiagm::DrawResult draw_rotated_image(SkCanvas* canvas, const SkImage* image,
SkString* errorMsg) {
sk_tool_utils::draw_checkerboard(canvas, SkColorSetRGB(156, 154, 156),
SK_ColorWHITE, 12);
if (!image) {
skiagm::GM::DrawFailureMessage(canvas, "No image. Did you forget to set the resourcePath?");
return;
*errorMsg = "No image. Did you forget to set the resourcePath?";
return skiagm::DrawResult::kFail;
}
SkRect rect = SkRect::MakeLTRB(-68.0f, -68.0f, 68.0f, 68.0f);
SkPaint paint;
@ -33,12 +34,13 @@ static void draw_rotated_image(SkCanvas* canvas, const SkImage* image) {
canvas->drawImage(image, point[0], point[1]);
}
}
return skiagm::DrawResult::kOk;
}
DEF_SIMPLE_GM(repeated_bitmap, canvas, 576, 576) {
draw_rotated_image(canvas, GetResourceAsImage("images/randPixels.png").get());
DEF_SIMPLE_GM_CAN_FAIL(repeated_bitmap, canvas, errorMsg, 576, 576) {
return draw_rotated_image(canvas, GetResourceAsImage("images/randPixels.png").get(), errorMsg);
}
DEF_SIMPLE_GM(repeated_bitmap_jpg, canvas, 576, 576) {
draw_rotated_image(canvas, GetResourceAsImage("images/color_wheel.jpg").get());
DEF_SIMPLE_GM_CAN_FAIL(repeated_bitmap_jpg, canvas, errorMsg, 576, 576) {
return draw_rotated_image(canvas, GetResourceAsImage("images/color_wheel.jpg").get(), errorMsg);
}

View File

@ -60,18 +60,13 @@ protected:
SkISize onISize() override { return SkISize::Make(kImageWidth, kImageHeight); }
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
GrRenderTargetContext* renderTargetContext =
canvas->internal_private_accessTopLayerRenderTargetContext();
if (kEffect_Type == fType && !renderTargetContext) {
skiagm::GM::DrawGpuOnlyMessage(canvas);
return;
}
GrContext* context = canvas->getGrContext();
if (kEffect_Type == fType && !context) {
skiagm::GM::DrawGpuOnlyMessage(canvas);
return;
if (kEffect_Type == fType && (!renderTargetContext || !context)) {
*errorMsg = kErrorMsg_DrawSkippedGpuOnly;
return DrawResult::kSkip;
}
SkPaint paint;
@ -142,6 +137,7 @@ protected:
y += kTileY;
}
}
return DrawResult::kOk;
}
void setUpRRects() {

View File

@ -55,15 +55,14 @@ DEF_SIMPLE_GM(shadermaskfilter_gradient, canvas, 512, 512) {
}
#include "Resources.h"
DEF_SIMPLE_GM(shadermaskfilter_image, canvas, 560, 370) {
DEF_SIMPLE_GM_CAN_FAIL(shadermaskfilter_image, canvas, errorMsg, 560, 370) {
canvas->scale(1.25f, 1.25f);
auto image = GetResourceAsImage("images/mandrill_128.png");
auto mask = GetResourceAsImage("images/color_wheel.png");
if (!image || !mask) {
skiagm::GM::DrawFailureMessage(canvas, "Could not load images. "
"Did you forget to set the resourcePath?");
return;
*errorMsg = "Could not load images. Did you forget to set the resourcePath?";
return skiagm::DrawResult::kFail;
}
auto blurmf = SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 5);
auto gradmf = SkShaderMaskFilter::Make(make_shader(SkRect::MakeIWH(mask->width(),
@ -79,6 +78,7 @@ DEF_SIMPLE_GM(shadermaskfilter_image, canvas, 560, 370) {
canvas->restore();
canvas->translate(0, image->height() + 20.f);
}
return skiagm::DrawResult::kOk;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -15,7 +15,7 @@
namespace skiagm {
static void draw_diff(SkCanvas* canvas, SkImage* imgA, SkImage* imgB) {
skiagm::DrawResult draw_diff(SkCanvas* canvas, SkImage* imgA, SkImage* imgB, SkString* errorMsg) {
SkASSERT(imgA->dimensions() == imgB->dimensions());
int w = imgA->width(), h = imgA->height();
@ -34,8 +34,8 @@ static void draw_diff(SkCanvas* canvas, SkImage* imgA, SkImage* imgB) {
pmapA.alloc(info);
pmapB.alloc(info);
if (!imgA->readPixels(pmapA, 0, 0) || !imgB->readPixels(pmapB, 0, 0)) {
skiagm::GM::DrawFailureMessage(canvas, "Failed to read pixels.");
return;
*errorMsg = "Failed to read pixels.";
return skiagm::DrawResult::kFail;
}
int maxDiffX = 0, maxDiffY = 0, maxDiff = 0;
@ -95,6 +95,7 @@ static void draw_diff(SkCanvas* canvas, SkImage* imgA, SkImage* imgB) {
// Draw outline of whole test region
canvas->drawRect(SkRect::MakeWH(3 * w, h), outline);
return skiagm::DrawResult::kOk;
}
namespace {
@ -106,7 +107,8 @@ typedef std::function<void(SkCanvas*, const SkRect&, const SkPaint&)> ShapeDrawF
* user-supplied draw callbacks. Produces a grid clearly showing if the two callbacks produce the
* same visual results in all cases.
*/
static void draw_rect_geom_diff_grid(SkCanvas* canvas, ShapeDrawFunc f1, ShapeDrawFunc f2) {
static skiagm::DrawResult draw_rect_geom_diff_grid(SkCanvas* canvas, ShapeDrawFunc f1,
ShapeDrawFunc f2, SkString* errorMsg) {
// Variables:
// - Fill, hairline, wide stroke
// - Axis aligned, rotated, scaled, scaled negative, perspective
@ -182,13 +184,17 @@ static void draw_rect_geom_diff_grid(SkCanvas* canvas, ShapeDrawFunc f1, ShapeDr
surface->getCanvas()->restore();
auto imgB = surface->makeImageSnapshot();
draw_diff(canvas, imgA.get(), imgB.get());
skiagm::DrawResult drawResult = draw_diff(canvas, imgA.get(), imgB.get(), errorMsg);
if (skiagm::DrawResult::kOk != drawResult) {
return drawResult;
}
canvas->translate(160, 0);
}
canvas->restore();
canvas->translate(0, 60);
}
}
return skiagm::DrawResult::kOk;
}
static const int kNumRows = 9;
@ -196,7 +202,8 @@ static const int kNumColumns = 7;
static const int kTotalWidth = kNumColumns * 160 + 10;
static const int kTotalHeight = kNumRows * 60 + 10;
DEF_SIMPLE_GM_BG(rects_as_paths, canvas, kTotalWidth, kTotalHeight, SK_ColorBLACK) {
DEF_SIMPLE_GM_BG_CAN_FAIL(rects_as_paths, canvas, errorMsg, kTotalWidth, kTotalHeight,
SK_ColorBLACK) {
// Drawing a rect vs. adding it to a path and drawing the path, should produce same results.
auto rectDrawFunc = [](SkCanvas* canvas, const SkRect& rect, const SkPaint& paint) {
canvas->drawRect(rect, paint);
@ -207,10 +214,11 @@ DEF_SIMPLE_GM_BG(rects_as_paths, canvas, kTotalWidth, kTotalHeight, SK_ColorBLAC
canvas->drawPath(path, paint);
};
draw_rect_geom_diff_grid(canvas, rectDrawFunc, pathDrawFunc);
return draw_rect_geom_diff_grid(canvas, rectDrawFunc, pathDrawFunc, errorMsg);
}
DEF_SIMPLE_GM_BG(ovals_as_paths, canvas, kTotalWidth, kTotalHeight, SK_ColorBLACK) {
DEF_SIMPLE_GM_BG_CAN_FAIL(ovals_as_paths, canvas, errorMsg, kTotalWidth, kTotalHeight,
SK_ColorBLACK) {
// Drawing an oval vs. adding it to a path and drawing the path, should produce same results.
auto ovalDrawFunc = [](SkCanvas* canvas, const SkRect& rect, const SkPaint& paint) {
canvas->drawOval(rect, paint);
@ -221,10 +229,11 @@ DEF_SIMPLE_GM_BG(ovals_as_paths, canvas, kTotalWidth, kTotalHeight, SK_ColorBLAC
canvas->drawPath(path, paint);
};
draw_rect_geom_diff_grid(canvas, ovalDrawFunc, pathDrawFunc);
return draw_rect_geom_diff_grid(canvas, ovalDrawFunc, pathDrawFunc, errorMsg);
}
DEF_SIMPLE_GM_BG(arcs_as_paths, canvas, kTotalWidth, kTotalHeight, SK_ColorBLACK) {
DEF_SIMPLE_GM_BG_CAN_FAIL(arcs_as_paths, canvas, errorMsg, kTotalWidth, kTotalHeight,
SK_ColorBLACK) {
// Drawing an arc vs. adding it to a path and drawing the path, should produce same results.
auto arcDrawFunc = [](SkCanvas* canvas, const SkRect& rect, const SkPaint& paint) {
canvas->drawArc(rect, 10, 200, false, paint);
@ -235,7 +244,7 @@ DEF_SIMPLE_GM_BG(arcs_as_paths, canvas, kTotalWidth, kTotalHeight, SK_ColorBLACK
canvas->drawPath(path, paint);
};
draw_rect_geom_diff_grid(canvas, arcDrawFunc, pathDrawFunc);
return draw_rect_geom_diff_grid(canvas, arcDrawFunc, pathDrawFunc, errorMsg);
}
}

View File

@ -99,15 +99,14 @@ protected:
canvas->restore();
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
GrContext* context = canvas->getGrContext();
sk_sp<SkImage> bottomLImg = make_image(context, kImgSize, kBottomLeft_GrSurfaceOrigin);
sk_sp<SkImage> topLImg = make_image(context, kImgSize, kTopLeft_GrSurfaceOrigin);
if (!bottomLImg || !topLImg) {
DrawFailureMessage(canvas, "Could not load images. "
"Did you forget to set the resourcePath?");
return;
*errorMsg = "Could not load images. Did you forget to set the resourcePath?";
return DrawResult::kFail;
}
int bigOffset = 2 * kPad + kImgSize;
@ -116,6 +115,7 @@ protected:
this->draw(canvas, topLImg, SkIPoint::Make(bigOffset, kPad), 1);
this->draw(canvas, bottomLImg, SkIPoint::Make(kPad, bigOffset), 7);
this->draw(canvas, topLImg, SkIPoint::Make(bigOffset, bigOffset), 7);
return DrawResult::kOk;
}
private:

View File

@ -10,14 +10,14 @@
#include "SkShader.h"
#include "gm.h"
DEF_SIMPLE_GM(bitmap_subset_shader, canvas, 256, 256) {
DEF_SIMPLE_GM_CAN_FAIL(bitmap_subset_shader, canvas, errorMsg, 256, 256) {
canvas->clear(SK_ColorWHITE);
SkBitmap source;
if (!GetResourceAsBitmap("images/color_wheel.png", &source)) {
skiagm::GM::DrawFailureMessage(canvas, "Could not load images/color_wheel.png. "
"Did you forget to set the resourcePath?");
return;
*errorMsg = "Could not load images/color_wheel.png. "
"Did you forget to set the resourcePath?";
return skiagm::DrawResult::kFail;
}
SkIRect left = SkIRect::MakeWH(source.width()/2, source.height());
SkIRect right = SkIRect::MakeXYWH(source.width()/2, 0,
@ -35,4 +35,5 @@ DEF_SIMPLE_GM(bitmap_subset_shader, canvas, 256, 256) {
canvas->drawRect(SkRect::MakeWH(256.0f, 128.0f), paint);
paint.setShader(SkShader::MakeBitmapShader(rightBitmap, tm, tm, &matrix));
canvas->drawRect(SkRect::MakeXYWH(0, 128.0f, 256.0f, 128.0f), paint);
return skiagm::DrawResult::kOk;
}

View File

@ -93,7 +93,8 @@ protected:
return SkISize::Make(kWidth, kHeight);
}
void onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas) override {
DrawResult onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas,
SkString* errorMsg) override {
// This GM exists to test a specific feature of the GPU backend.
// This GM uses sk_tool_utils::makeSurface which doesn't work well with vias.
// This GM uses SkRandomTypeface which doesn't work well with serialization.
@ -105,8 +106,8 @@ protected:
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
auto surface(sk_tool_utils::makeSurface(canvas, info, &props));
if (!surface) {
DrawFailureMessage(canvas, "This test requires a surface");
return;
*errorMsg = "This test requires a surface";
return DrawResult::kFail;
}
SkPaint paint;
@ -139,6 +140,7 @@ protected:
canvas->rotate(-0.05f);
canvas->drawTextBlob(fBlob, 10, yOffset, paint);
yOffset += stride;
return DrawResult::kOk;
}
private:

View File

@ -82,16 +82,16 @@ protected:
fImage = surface->makeImageSnapshot();
}
void onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
SkCanvas* canvas) override {
DrawResult onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
SkCanvas* canvas, SkString* errorMsg) override {
GrProxyProvider* proxyProvider = context->priv().proxyProvider();
sk_sp<GrTextureProxy> proxy;
if (fFilter == GrSamplerState::Filter::kMipMap) {
SkBitmap copy;
SkImageInfo info = as_IB(fImage)->onImageInfo().makeColorType(kN32_SkColorType);
if (!copy.tryAllocPixels(info) || !fImage->readPixels(copy.pixmap(), 0, 0)) {
DrawFailureMessage(canvas, "Failed to read pixels.");
return;
*errorMsg = "Failed to read pixels.";
return DrawResult::kFail;
}
proxy = proxyProvider->createMipMapProxyFromBitmap(copy);
} else {
@ -99,8 +99,8 @@ protected:
fImage, kNone_GrSurfaceFlags, 1, SkBudgeted::kYes, SkBackingFit::kExact);
}
if (!proxy) {
DrawFailureMessage(canvas, "Failed to create proxy.");
return;
*errorMsg = "Failed to create proxy.";
return DrawResult::kFail;
}
SkTArray<SkMatrix> textureMatrices;
@ -150,6 +150,7 @@ protected:
y += renderRect.height() + kTestPad;
}
}
return DrawResult::kOk;
}
private:

View File

@ -30,14 +30,14 @@ namespace skiagm {
class WindowRectanglesBaseGM : public GM {
protected:
virtual void onCoverClipStack(const SkClipStack&, SkCanvas*) = 0;
virtual DrawResult onCoverClipStack(const SkClipStack&, SkCanvas*, SkString* errorMsg) = 0;
private:
SkISize onISize() override { return SkISize::Make(kDeviceRect.width(), kDeviceRect.height()); }
void onDraw(SkCanvas*) final;
DrawResult onDraw(SkCanvas*, SkString* errorMsg) final;
};
void WindowRectanglesBaseGM::onDraw(SkCanvas* canvas) {
DrawResult WindowRectanglesBaseGM::onDraw(SkCanvas* canvas, SkString* errorMsg) {
sk_tool_utils::draw_checkerboard(canvas, 0xffffffff, 0xffc6c3c6, 25);
SkClipStack stack;
@ -57,7 +57,7 @@ void WindowRectanglesBaseGM::onDraw(SkCanvas* canvas) {
complx.setRectRadii(SkRect::MakeXYWH(80.25, 80.75, 100, 149), complxRadii);
stack.clipRRect(complx, SkMatrix::I(), kDifference_SkClipOp, false);
this->onCoverClipStack(stack, canvas);
return this->onCoverClipStack(stack, canvas, errorMsg);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@ -68,10 +68,11 @@ void WindowRectanglesBaseGM::onDraw(SkCanvas* canvas) {
class WindowRectanglesGM : public WindowRectanglesBaseGM {
private:
SkString onShortName() final { return SkString("windowrectangles"); }
void onCoverClipStack(const SkClipStack&, SkCanvas*) final;
DrawResult onCoverClipStack(const SkClipStack&, SkCanvas*, SkString* errorMsg) final;
};
void WindowRectanglesGM::onCoverClipStack(const SkClipStack& stack, SkCanvas* canvas) {
DrawResult WindowRectanglesGM::onCoverClipStack(const SkClipStack& stack, SkCanvas* canvas,
SkString* errorMsg) {
SkPaint paint;
paint.setColor(0xff00aa80);
@ -97,6 +98,7 @@ void WindowRectanglesGM::onCoverClipStack(const SkClipStack& stack, SkCanvas* ca
}
canvas->drawRect(SkRect::Make(kCoverRect), paint);
return DrawResult::kOk;
}
DEF_GM( return new WindowRectanglesGM(); )
@ -121,7 +123,7 @@ class WindowRectanglesMaskGM : public WindowRectanglesBaseGM {
private:
constexpr static int kMaskCheckerSize = 5;
SkString onShortName() final { return SkString("windowrectangles_mask"); }
void onCoverClipStack(const SkClipStack&, SkCanvas*) final;
DrawResult onCoverClipStack(const SkClipStack&, SkCanvas*, SkString* errorMsg) final;
void visualizeAlphaMask(GrContext*, GrRenderTargetContext*, const GrReducedClip&, GrPaint&&);
void visualizeStencilMask(GrContext*, GrRenderTargetContext*, const GrReducedClip&, GrPaint&&);
void stencilCheckerboard(GrRenderTargetContext*, bool flip);
@ -170,13 +172,18 @@ static GrStencilClip make_stencil_only_clip() {
return GrStencilClip(SkClipStack::kEmptyGenID);
};
void WindowRectanglesMaskGM::onCoverClipStack(const SkClipStack& stack, SkCanvas* canvas) {
DrawResult WindowRectanglesMaskGM::onCoverClipStack(const SkClipStack& stack, SkCanvas* canvas,
SkString* errorMsg) {
GrContext* ctx = canvas->getGrContext();
GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
if (!ctx || !rtc || rtc->priv().maxWindowRectangles() < kNumWindows) {
DrawFailureMessage(canvas, "Requires GPU with %i window rectangles", kNumWindows);
return;
if (!ctx || !rtc) {
*errorMsg = kErrorMsg_DrawSkippedGpuOnly;
return DrawResult::kSkip;
}
if (rtc->priv().maxWindowRectangles() < kNumWindows) {
*errorMsg = "Requires at least 8 window rectangles. "
"(Are you off FBO 0? Use sRGB to force offscreen rendering.)";
return DrawResult::kSkip;
}
const GrReducedClip reducedClip(stack, SkRect::Make(kCoverRect), rtc->caps(), kNumWindows);
@ -189,6 +196,7 @@ void WindowRectanglesMaskGM::onCoverClipStack(const SkClipStack& stack, SkCanvas
paint.setColor4f({ 1, 0.25f, 0.25f, 1 });
this->visualizeStencilMask(ctx, rtc, reducedClip, std::move(paint));
}
return DrawResult::kOk;
}
void WindowRectanglesMaskGM::visualizeAlphaMask(GrContext* ctx, GrRenderTargetContext* rtc,

View File

@ -72,8 +72,8 @@ protected:
}
}
void onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
SkCanvas* canvas) override {
DrawResult onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
SkCanvas* canvas, SkString* errorMsg) override {
GrProxyProvider* proxyProvider = context->priv().proxyProvider();
sk_sp<GrTextureProxy> proxies[3];
@ -81,8 +81,8 @@ protected:
proxies[i] = proxyProvider->createTextureProxy(fImage[i], kNone_GrSurfaceFlags, 1,
SkBudgeted::kYes, SkBackingFit::kExact);
if (!proxies[i]) {
DrawFailureMessage(canvas, "Failed to create proxy");
return;
*errorMsg = "Failed to create proxy";
return DrawResult::kFail;
}
}
@ -126,6 +126,7 @@ protected:
x += renderRect.width() + kTestPad;
}
}
return DrawResult::kOk;
}
private:
@ -189,8 +190,8 @@ protected:
}
}
void onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
SkCanvas* canvas) override {
DrawResult onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
SkCanvas* canvas, SkString* errorMsg) override {
GrProxyProvider* proxyProvider = context->priv().proxyProvider();
sk_sp<GrTextureProxy> proxies[2];
@ -198,8 +199,8 @@ protected:
proxies[i] = proxyProvider->createTextureProxy(fImage[i], kNone_GrSurfaceFlags, 1,
SkBudgeted::kYes, SkBackingFit::kExact);
if (!proxies[i]) {
DrawFailureMessage(canvas, "Failed to create proxy");
return;
*errorMsg = "Failed to create proxy";
return DrawResult::kFail;
}
}
@ -236,6 +237,7 @@ protected:
renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
}
}
return DrawResult::kOk;
}
private:

View File

@ -61,14 +61,15 @@ protected:
}
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
if (!fAnimation) {
DrawFailureMessage(canvas, "No animation");
return;
*errorMsg = "No animation";
return DrawResult::kFail;
}
auto dest = SkRect::MakeWH(kSize, kSize);
fAnimation->render(canvas, &dest);
return DrawResult::kOk;
}
bool onAnimate(const SkAnimTimer& timer) override {
@ -113,14 +114,15 @@ protected:
}
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
if (!fAnimation) {
DrawFailureMessage(canvas, "No animation");
return;
*errorMsg = "No animation";
return DrawResult::kFail;
}
auto dest = SkRect::MakeWH(kSize, kSize);
fAnimation->render(canvas, &dest);
return DrawResult::kOk;
}
bool onAnimate(const SkAnimTimer& timer) override {
@ -185,14 +187,15 @@ protected:
}
}
void onDraw(SkCanvas* canvas) override {
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
if (!fAnimation) {
DrawFailureMessage(canvas, "No animation");
return;
*errorMsg = "No animation";
return DrawResult::kFail;
}
auto dest = SkRect::MakeWH(kSize, kSize);
fAnimation->render(canvas, &dest);
return DrawResult::kOk;
}
bool onAnimate(const SkAnimTimer& timer) override {