• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "gm/gm.h"
9 #include "gm/verifiers/gmverifier.h"
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkBlendMode.h"
12 #include "include/core/SkCanvas.h"
13 #include "include/core/SkFont.h"
14 #include "include/core/SkFontTypes.h"
15 #include "include/core/SkMatrix.h"
16 #include "include/core/SkPaint.h"
17 #include "include/core/SkRect.h"
18 #include "include/core/SkShader.h"
19 #include "include/core/SkTileMode.h"
20 #include "include/core/SkTypeface.h"
21 #include "include/gpu/GrRecordingContext.h"
22 #include "src/core/SkCanvasPriv.h"
23 #include "src/core/SkTraceEvent.h"
24 #include "tools/ToolUtils.h"
25 
26 #include <stdarg.h>
27 
28 using namespace skiagm;
29 
30 static void draw_failure_message(SkCanvas* canvas, const char format[], ...) SK_PRINTF_LIKE(2, 3);
31 
draw_failure_message(SkCanvas * canvas,const char format[],...)32 static void draw_failure_message(SkCanvas* canvas, const char format[], ...) {
33     SkString failureMsg;
34 
35     va_list argp;
36     va_start(argp, format);
37     failureMsg.appendVAList(format, argp);
38     va_end(argp);
39 
40     constexpr SkScalar kOffset = 5.0f;
41     canvas->drawColor(SkColorSetRGB(200,0,0));
42     SkFont font;
43     SkRect bounds;
44     font.measureText(failureMsg.c_str(), failureMsg.size(), SkTextEncoding::kUTF8, &bounds);
45     SkPaint textPaint(SkColors::kWhite);
46     canvas->drawString(failureMsg, kOffset, bounds.height() + kOffset, font, textPaint);
47 }
48 
draw_gpu_only_message(SkCanvas * canvas)49 static void draw_gpu_only_message(SkCanvas* canvas) {
50     SkBitmap bmp;
51     bmp.allocN32Pixels(128, 64);
52     SkCanvas bmpCanvas(bmp);
53     bmpCanvas.drawColor(SK_ColorWHITE);
54     SkFont  font(ToolUtils::create_portable_typeface(), 20);
55     SkPaint paint(SkColors::kRed);
56     bmpCanvas.drawString("GPU Only", 20, 40, font, paint);
57     SkMatrix localM;
58     localM.setRotate(35.f);
59     localM.postTranslate(10.f, 0.f);
60     paint.setShader(bmp.makeShader(SkTileMode::kMirror, SkTileMode::kMirror,
61                                    SkSamplingOptions(SkFilterMode::kLinear,
62                                                      SkMipmapMode::kNearest),
63                                    localM));
64     canvas->drawPaint(paint);
65 }
66 
handle_gm_failure(SkCanvas * canvas,DrawResult result,const SkString & errorMsg)67 static void handle_gm_failure(SkCanvas* canvas, DrawResult result, const SkString& errorMsg) {
68     if (DrawResult::kFail == result) {
69         draw_failure_message(canvas, "DRAW FAILED: %s", errorMsg.c_str());
70     } else if (SkString(GM::kErrorMsg_DrawSkippedGpuOnly) == errorMsg) {
71         draw_gpu_only_message(canvas);
72     } else {
73         draw_failure_message(canvas, "DRAW SKIPPED: %s", errorMsg.c_str());
74     }
75 }
76 
GM(SkColor bgColor)77 GM::GM(SkColor bgColor) {
78     fMode = kGM_Mode;
79     fBGColor = bgColor;
80 }
81 
~GM()82 GM::~GM() {}
83 
gpuSetup(SkCanvas * canvas,SkString * errorMsg)84 DrawResult GM::gpuSetup(SkCanvas* canvas, SkString* errorMsg) {
85     TRACE_EVENT1("GM", TRACE_FUNC, "name", TRACE_STR_COPY(this->getName()));
86     if (!fGpuSetup) {
87         // When drawn in viewer, gpuSetup will be called multiple times with the same
88         // GrContext.
89         fGpuSetup = true;
90         fGpuSetupResult = this->onGpuSetup(canvas, errorMsg);
91     }
92     if (DrawResult::kOk != fGpuSetupResult) {
93         handle_gm_failure(canvas, fGpuSetupResult, *errorMsg);
94     }
95 
96     return fGpuSetupResult;
97 }
98 
gpuTeardown()99 void GM::gpuTeardown() {
100     this->onGpuTeardown();
101 
102     // After 'gpuTeardown' a GM can be reused with a different GrContext. Reset the flag
103     // so 'onGpuSetup' will be called.
104     fGpuSetup = false;
105 }
106 
draw(SkCanvas * canvas,SkString * errorMsg)107 DrawResult GM::draw(SkCanvas* canvas, SkString* errorMsg) {
108     TRACE_EVENT1("GM", TRACE_FUNC, "name", TRACE_STR_COPY(this->getName()));
109     this->drawBackground(canvas);
110     return this->drawContent(canvas, errorMsg);
111 }
112 
drawContent(SkCanvas * canvas,SkString * errorMsg)113 DrawResult GM::drawContent(SkCanvas* canvas, SkString* errorMsg) {
114     TRACE_EVENT0("GM", TRACE_FUNC);
115     this->onceBeforeDraw();
116     SkAutoCanvasRestore acr(canvas, true);
117     DrawResult drawResult = this->onDraw(canvas, errorMsg);
118     if (DrawResult::kOk != drawResult) {
119         handle_gm_failure(canvas, drawResult, *errorMsg);
120     }
121     return drawResult;
122 }
123 
drawBackground(SkCanvas * canvas)124 void GM::drawBackground(SkCanvas* canvas) {
125     TRACE_EVENT0("GM", TRACE_FUNC);
126     this->onceBeforeDraw();
127     canvas->drawColor(fBGColor, SkBlendMode::kSrc);
128 }
129 
onDraw(SkCanvas * canvas,SkString * errorMsg)130 DrawResult GM::onDraw(SkCanvas* canvas, SkString* errorMsg) {
131     this->onDraw(canvas);
132     return DrawResult::kOk;
133 }
onDraw(SkCanvas *)134 void GM::onDraw(SkCanvas*) { SK_ABORT("Not implemented."); }
135 
136 
onISize()137 SkISize SimpleGM::onISize() { return fSize; }
onShortName()138 SkString SimpleGM::onShortName() { return fName; }
onDraw(SkCanvas * canvas,SkString * errorMsg)139 DrawResult SimpleGM::onDraw(SkCanvas* canvas, SkString* errorMsg) {
140     return fDrawProc(canvas, errorMsg);
141 }
142 
onISize()143 SkISize SimpleGpuGM::onISize() { return fSize; }
onShortName()144 SkString SimpleGpuGM::onShortName() { return fName; }
onDraw(GrRecordingContext * rContext,SkCanvas * canvas,SkString * errorMsg)145 DrawResult SimpleGpuGM::onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) {
146     return fDrawProc(rContext, canvas, errorMsg);
147 }
148 
getName()149 const char* GM::getName() {
150     if (fShortName.size() == 0) {
151         fShortName = this->onShortName();
152     }
153     return fShortName.c_str();
154 }
155 
setBGColor(SkColor color)156 void GM::setBGColor(SkColor color) {
157     fBGColor = color;
158 }
159 
animate(double nanos)160 bool GM::animate(double nanos) { return this->onAnimate(nanos); }
161 
runAsBench() const162 bool GM::runAsBench() const { return false; }
modifyGrContextOptions(GrContextOptions * options)163 void GM::modifyGrContextOptions(GrContextOptions* options) {}
164 
getVerifiers() const165 std::unique_ptr<verifiers::VerifierList> GM::getVerifiers() const {
166     // No verifiers by default.
167     return nullptr;
168 }
169 
onOnceBeforeDraw()170 void GM::onOnceBeforeDraw() {}
171 
onAnimate(double)172 bool GM::onAnimate(double /*nanos*/) { return false; }
173 
onChar(SkUnichar uni)174 bool GM::onChar(SkUnichar uni) { return false; }
175 
onGetControls(SkMetaData *)176 bool GM::onGetControls(SkMetaData*) { return false; }
177 
onSetControls(const SkMetaData &)178 void GM::onSetControls(const SkMetaData&) {}
179 
180 /////////////////////////////////////////////////////////////////////////////////////////////
181 
drawSizeBounds(SkCanvas * canvas,SkColor color)182 void GM::drawSizeBounds(SkCanvas* canvas, SkColor color) {
183     canvas->drawRect(SkRect::Make(this->getISize()), SkPaint(SkColor4f::FromColor(color)));
184 }
185 
186 // need to explicitly declare this, or we get some weird infinite loop llist
187 template GMRegistry* GMRegistry::gHead;
188 
onDraw(GrRecordingContext * rContext,SkCanvas * canvas,SkString * errorMsg)189 DrawResult GpuGM::onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) {
190     this->onDraw(rContext, canvas);
191     return DrawResult::kOk;
192 }
onDraw(GrRecordingContext *,SkCanvas *)193 void GpuGM::onDraw(GrRecordingContext*, SkCanvas*) {
194     SK_ABORT("Not implemented.");
195 }
196 
onDraw(SkCanvas * canvas,SkString * errorMsg)197 DrawResult GpuGM::onDraw(SkCanvas* canvas, SkString* errorMsg) {
198 
199     auto rContext = canvas->recordingContext();
200     if (!rContext) {
201         *errorMsg = kErrorMsg_DrawSkippedGpuOnly;
202         return DrawResult::kSkip;
203     }
204     if (rContext->abandoned()) {
205         *errorMsg = "GrContext abandoned.";
206         return DrawResult::kSkip;
207     }
208     return this->onDraw(rContext, canvas, errorMsg);
209 }
210 
211 template <typename Fn>
mark(SkCanvas * canvas,SkScalar x,SkScalar y,Fn && fn)212 static void mark(SkCanvas* canvas, SkScalar x, SkScalar y, Fn&& fn) {
213     SkPaint alpha;
214     alpha.setAlpha(0x50);
215     canvas->saveLayer(nullptr, &alpha);
216         canvas->translate(x,y);
217         canvas->scale(2,2);
218         fn();
219     canvas->restore();
220 }
221 
MarkGMGood(SkCanvas * canvas,SkScalar x,SkScalar y)222 void MarkGMGood(SkCanvas* canvas, SkScalar x, SkScalar y) {
223     mark(canvas, x,y, [&]{
224         // A green circle.
225         canvas->drawCircle(0, 0, 12, SkPaint(SkColor4f::FromColor(SkColorSetRGB(27, 158, 119))));
226 
227         // Cut out a check mark.
228         SkPaint paint(SkColors::kTransparent);
229         paint.setBlendMode(SkBlendMode::kSrc);
230         paint.setStrokeWidth(2);
231         paint.setStyle(SkPaint::kStroke_Style);
232         canvas->drawLine(-6, 0,
233                          -1, 5, paint);
234         canvas->drawLine(-1, +5,
235                          +7, -5, paint);
236     });
237 }
238 
MarkGMBad(SkCanvas * canvas,SkScalar x,SkScalar y)239 void MarkGMBad(SkCanvas* canvas, SkScalar x, SkScalar y) {
240     mark(canvas, x,y, [&] {
241         // A red circle.
242         canvas->drawCircle(0,0, 12, SkPaint(SkColor4f::FromColor(SkColorSetRGB(231, 41, 138))));
243 
244         // Cut out an 'X'.
245         SkPaint paint(SkColors::kTransparent);
246         paint.setBlendMode(SkBlendMode::kSrc);
247         paint.setStrokeWidth(2);
248         paint.setStyle(SkPaint::kStroke_Style);
249         canvas->drawLine(-5,-5,
250                          +5,+5, paint);
251         canvas->drawLine(+5,-5,
252                          -5,+5, paint);
253     });
254 }
255