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