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