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 #ifndef skiagm_DEFINED
9 #define skiagm_DEFINED
10 
11 #include "gm/verifiers/gmverifier.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkScalar.h"
14 #include "include/core/SkSize.h"
15 #include "include/core/SkString.h"
16 #include "include/core/SkTypes.h"
17 #include "include/private/SkMacros.h"
18 #include "tools/Registry.h"
19 
20 #include <memory>
21 
22 class GrDirectContext;
23 class GrRecordingContext;
24 class GrRenderTargetContext;
25 class SkCanvas;
26 class SkMetaData;
27 struct GrContextOptions;
28 
29 #define DEF_GM(CODE) \
30     static skiagm::GMRegistry SK_MACRO_APPEND_LINE(REG_)(\
31             [](){return std::unique_ptr<skiagm::GM>([](){ CODE ; }());});
32 
33 // A Simple GM is a rendering test that does not store state between rendering calls or make use of
34 // the onOnceBeforeDraw() virtual; it consists of:
35 //   *   A name.
36 //   *   Prefered width and height.
37 //   *   Optionally, a background color (default is white).
38 //   *   A standalone function pointer that implements its onDraw method.
39 #define DEF_SIMPLE_GM(NAME, CANVAS, W, H) \
40     DEF_SIMPLE_GM_BG_NAME(NAME, CANVAS, W, H, SK_ColorWHITE, SkString(#NAME))
41 #define DEF_SIMPLE_GM_BG(NAME, CANVAS, W, H, BGCOLOR) \
42     DEF_SIMPLE_GM_BG_NAME(NAME, CANVAS, W, H, BGCOLOR, SkString(#NAME))
43 #define DEF_SIMPLE_GM_BG_NAME(NAME, CANVAS, W, H, BGCOLOR, NAME_STR) \
44     static void SK_MACRO_CONCAT(NAME,_GM_inner)(SkCanvas*); \
45     DEF_SIMPLE_GM_BG_NAME_CAN_FAIL(NAME, CANVAS,, W, H, BGCOLOR, NAME_STR) { \
46         SK_MACRO_CONCAT(NAME,_GM_inner)(CANVAS); \
47         return skiagm::DrawResult::kOk; \
48     } \
49     void SK_MACRO_CONCAT(NAME,_GM_inner)(SkCanvas* CANVAS)
50 
51 #define DEF_SIMPLE_GM_CAN_FAIL(NAME, CANVAS, ERR_MSG, W, H) \
52     DEF_SIMPLE_GM_BG_NAME_CAN_FAIL(NAME, CANVAS, ERR_MSG, W, H, SK_ColorWHITE, SkString(#NAME))
53 #define DEF_SIMPLE_GM_BG_CAN_FAIL(NAME, CANVAS, ERR_MSG, W, H, BGCOLOR) \
54     DEF_SIMPLE_GM_BG_NAME_CAN_FAIL(NAME, CANVAS, ERR_MSG, W, H, BGCOLOR, SkString(#NAME))
55 #define DEF_SIMPLE_GM_BG_NAME_CAN_FAIL(NAME, CANVAS, ERR_MSG, W, H, BGCOLOR, NAME_STR) \
56     static skiagm::DrawResult SK_MACRO_CONCAT(NAME,_GM)(SkCanvas*, SkString*); \
57     DEF_GM(return new skiagm::SimpleGM(BGCOLOR, NAME_STR, {W,H}, SK_MACRO_CONCAT(NAME,_GM));) \
58     skiagm::DrawResult SK_MACRO_CONCAT(NAME,_GM)(SkCanvas* CANVAS, SkString* ERR_MSG)
59 
60 
61 // A Simple GpuGM makes direct GPU calls. Its onDraw hook that includes GPU objects as params, and
62 // is only invoked on GPU configs. Non-GPU configs automatically draw a GPU-only message and abort.
63 #define DEF_SIMPLE_GPU_GM(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS, W, H) \
64     DEF_SIMPLE_GPU_GM_BG(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS, W, H, SK_ColorWHITE)
65 #define DEF_SIMPLE_GPU_GM_BG(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS, W, H, BGCOLOR) \
66     static void SK_MACRO_CONCAT(NAME,_GM_inner)(GrRecordingContext*, GrRenderTargetContext*, \
67                                                 SkCanvas*); \
68     DEF_SIMPLE_GPU_GM_BG_CAN_FAIL(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS,, W, H, \
69                                   BGCOLOR) { \
70         SK_MACRO_CONCAT(NAME,_GM_inner)(GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS); \
71         return skiagm::DrawResult::kOk; \
72     } \
73     void SK_MACRO_CONCAT(NAME,_GM_inner)( \
74             GrRecordingContext* GR_CONTEXT, GrRenderTargetContext* RENDER_TARGET_CONTEXT, \
75             SkCanvas* CANVAS)
76 
77 #define DEF_SIMPLE_GPU_GM_CAN_FAIL(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS, ERR_MSG, W, H) \
78     DEF_SIMPLE_GPU_GM_BG_CAN_FAIL(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS, \
79                                   ERR_MSG, W, H, SK_ColorWHITE)
80 #define DEF_SIMPLE_GPU_GM_BG_CAN_FAIL(NAME, GR_CONTEXT, RENDER_TARGET_CONTEXT, CANVAS, ERR_MSG, W, \
81                                       H, BGCOLOR) \
82     static skiagm::DrawResult SK_MACRO_CONCAT(NAME,_GM)( \
83             GrRecordingContext*, GrRenderTargetContext*, SkCanvas*, SkString*); \
84     DEF_GM(return new skiagm::SimpleGpuGM(BGCOLOR, SkString(#NAME), {W,H}, \
85                                           SK_MACRO_CONCAT(NAME,_GM));) \
86     skiagm::DrawResult SK_MACRO_CONCAT(NAME,_GM)( \
87             GrRecordingContext* GR_CONTEXT, GrRenderTargetContext* RENDER_TARGET_CONTEXT, \
88             SkCanvas* CANVAS, SkString* ERR_MSG)
89 
90 namespace skiagm {
91 
92     enum class DrawResult {
93         kOk,   // Test drew successfully.
94         kFail, // Test failed to draw.
95         kSkip  // Test is not applicable in this context and should be skipped.
96     };
97 
98     class GM {
99     public:
100         using DrawResult = skiagm::DrawResult;
101 
102         GM(SkColor backgroundColor = SK_ColorWHITE);
103         virtual ~GM();
104 
105         enum Mode {
106             kGM_Mode,
107             kSample_Mode,
108             kBench_Mode,
109         };
110 
setMode(Mode mode)111         void setMode(Mode mode) { fMode = mode; }
getMode()112         Mode getMode() const { return fMode; }
113 
114         static constexpr char kErrorMsg_DrawSkippedGpuOnly[] = "This test is for GPU configs only.";
115 
gpuSetup(GrDirectContext * context,SkCanvas * canvas)116         DrawResult gpuSetup(GrDirectContext* context, SkCanvas* canvas) {
117             SkString errorMsg;
118             return this->gpuSetup(context, canvas, &errorMsg);
119         }
120         DrawResult gpuSetup(GrDirectContext*, SkCanvas*, SkString* errorMsg);
121         void gpuTeardown();
122 
onceBeforeDraw()123         void onceBeforeDraw() {
124             if (!fHaveCalledOnceBeforeDraw) {
125                 fHaveCalledOnceBeforeDraw = true;
126                 this->onOnceBeforeDraw();
127             }
128         }
129 
draw(SkCanvas * canvas)130         DrawResult draw(SkCanvas* canvas) {
131             SkString errorMsg;
132             return this->draw(canvas, &errorMsg);
133         }
134         DrawResult draw(SkCanvas*, SkString* errorMsg);
135 
136         void drawBackground(SkCanvas*);
drawContent(SkCanvas * canvas)137         DrawResult drawContent(SkCanvas* canvas) {
138             SkString errorMsg;
139             return this->drawContent(canvas, &errorMsg);
140         }
141         DrawResult drawContent(SkCanvas*, SkString* errorMsg);
142 
getISize()143         SkISize getISize() { return this->onISize(); }
144         const char* getName();
145 
146         virtual bool runAsBench() const;
147 
width()148         SkScalar width() {
149             return SkIntToScalar(this->getISize().width());
150         }
height()151         SkScalar height() {
152             return SkIntToScalar(this->getISize().height());
153         }
154 
getBGColor()155         SkColor getBGColor() const { return fBGColor; }
156         void setBGColor(SkColor);
157 
158         // helper: fill a rect in the specified color based on the GM's getISize bounds.
159         void drawSizeBounds(SkCanvas*, SkColor);
160 
161         bool animate(double /*nanos*/);
162         virtual bool onChar(SkUnichar);
163 
getControls(SkMetaData * controls)164         bool getControls(SkMetaData* controls) { return this->onGetControls(controls); }
setControls(const SkMetaData & controls)165         void setControls(const SkMetaData& controls) { this->onSetControls(controls); }
166 
167         virtual void modifyGrContextOptions(GrContextOptions*);
168 
169         virtual std::unique_ptr<verifiers::VerifierList> getVerifiers() const;
170 
171     protected:
172         // onGpuSetup is called once before any other processing with a direct context.
onGpuSetup(GrDirectContext *,SkString *)173         virtual DrawResult onGpuSetup(GrDirectContext*, SkString*) { return DrawResult::kOk; }
onGpuTeardown()174         virtual void onGpuTeardown() {}
175         virtual void onOnceBeforeDraw();
176         virtual DrawResult onDraw(SkCanvas*, SkString* errorMsg);
177         virtual void onDraw(SkCanvas*);
178 
179         virtual SkISize onISize() = 0;
180         virtual SkString onShortName() = 0;
181 
182         virtual bool onAnimate(double /*nanos*/);
183         virtual bool onGetControls(SkMetaData*);
184         virtual void onSetControls(const SkMetaData&);
185 
186     private:
187         Mode       fMode;
188         SkString   fShortName;
189         SkColor    fBGColor;
190         bool       fHaveCalledOnceBeforeDraw = false;
191         bool       fGpuSetup = false;
192         DrawResult fGpuSetupResult = DrawResult::kOk;
193     };
194 
195     using GMFactory = std::unique_ptr<skiagm::GM> (*)();
196     using GMRegistry = sk_tools::Registry<GMFactory>;
197 
198     // A GpuGM replaces the onDraw method with one that also accepts GPU objects alongside the
199     // SkCanvas. Its onDraw is only invoked on GPU configs; on non-GPU configs it will automatically
200     // draw a GPU-only message and abort.
201     class GpuGM : public GM {
202     public:
GM(backgroundColor)203         GpuGM(SkColor backgroundColor = SK_ColorWHITE) : GM(backgroundColor) {}
204 
205         // TODO(tdenniston): Currently GpuGMs don't have verifiers (because they do not render on
206         //   CPU), but we may want to be able to verify the output images standalone, without
207         //   requiring a gold image for comparison.
getVerifiers()208         std::unique_ptr<verifiers::VerifierList> getVerifiers() const override { return nullptr; }
209 
210     private:
211         using GM::onDraw;
212         DrawResult onDraw(SkCanvas*, SkString* errorMsg) final;
213 
214         virtual DrawResult onDraw(GrRecordingContext*, GrRenderTargetContext*, SkCanvas*,
215                                   SkString* errorMsg);
216         virtual void onDraw(GrRecordingContext*, GrRenderTargetContext*, SkCanvas*);
217     };
218 
219     // SimpleGM is intended for basic GMs that can define their entire implementation inside a
220     // single "draw" function pointer.
221     class SimpleGM : public GM {
222     public:
223         using DrawProc = DrawResult(*)(SkCanvas*, SkString*);
SimpleGM(SkColor bgColor,const SkString & name,const SkISize & size,DrawProc drawProc)224         SimpleGM(SkColor bgColor, const SkString& name, const SkISize& size, DrawProc drawProc)
225                 : GM(bgColor), fName(name), fSize(size), fDrawProc(drawProc) {}
226 
227     private:
228         SkISize onISize() override;
229         SkString onShortName() override;
230         DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override;
231 
232         const SkString fName;
233         const SkISize fSize;
234         const DrawProc fDrawProc;
235     };
236 
237     class SimpleGpuGM : public GpuGM {
238     public:
239         using DrawProc = DrawResult(*)(GrRecordingContext*, GrRenderTargetContext*,
240                                        SkCanvas*, SkString* errorMsg);
SimpleGpuGM(SkColor bgColor,const SkString & name,const SkISize & size,DrawProc drawProc)241         SimpleGpuGM(SkColor bgColor, const SkString& name, const SkISize& size, DrawProc drawProc)
242                 : GpuGM(bgColor), fName(name), fSize(size), fDrawProc(drawProc) {}
243 
244     private:
245         SkISize onISize() override;
246         SkString onShortName() override;
247         DrawResult onDraw(GrRecordingContext* ctx, GrRenderTargetContext* rtc, SkCanvas* canvas,
248                           SkString* errorMsg) override;
249 
250         const SkString fName;
251         const SkISize fSize;
252         const DrawProc fDrawProc;
253     };
254 }  // namespace skiagm
255 
256 void MarkGMGood(SkCanvas*, SkScalar x, SkScalar y);
257 void MarkGMBad (SkCanvas*, SkScalar x, SkScalar y);
258 
259 #endif
260