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.h" 9 10 #include "GrContext.h" 11 #include "sk_tool_utils.h" 12 #include "SkShader.h" 13 #include "SkTraceEvent.h" 14 using namespace skiagm; 15 16 constexpr char GM::kErrorMsg_DrawSkippedGpuOnly[]; 17 18 static void draw_failure_message(SkCanvas* canvas, const char format[], ...) { 19 SkString failureMsg; 20 21 va_list argp; 22 va_start(argp, format); 23 failureMsg.appendVAList(format, argp); 24 va_end(argp); 25 26 constexpr SkScalar kOffset = 5.0f; 27 canvas->drawColor(SkColorSetRGB(200,0,0)); 28 SkFont font; 29 SkRect bounds; 30 font.measureText(failureMsg.c_str(), failureMsg.size(), kUTF8_SkTextEncoding, &bounds); 31 SkPaint textPaint; 32 textPaint.setColor(SK_ColorWHITE); 33 canvas->drawString(failureMsg, kOffset, bounds.height() + kOffset, font, textPaint); 34 } 35 36 static void draw_gpu_only_message(SkCanvas* canvas) { 37 SkBitmap bmp; 38 bmp.allocN32Pixels(128, 64); 39 SkCanvas bmpCanvas(bmp); 40 bmpCanvas.drawColor(SK_ColorWHITE); 41 SkFont font(sk_tool_utils::create_portable_typeface(), 20); 42 SkPaint paint; 43 paint.setColor(SK_ColorRED); 44 bmpCanvas.drawString("GPU Only", 20, 40, font, paint); 45 SkMatrix localM; 46 localM.setRotate(35.f); 47 localM.postTranslate(10.f, 0.f); 48 paint.setShader(SkShader::MakeBitmapShader( 49 bmp, SkShader::kMirror_TileMode, SkShader::kMirror_TileMode, &localM)); 50 paint.setFilterQuality(kMedium_SkFilterQuality); 51 canvas->drawPaint(paint); 52 } 53 54 GM::GM(SkColor bgColor) { 55 fMode = kGM_Mode; 56 fBGColor = bgColor; 57 fCanvasIsDeferred = false; 58 fHaveCalledOnceBeforeDraw = false; 59 } 60 61 GM::~GM() {} 62 63 DrawResult GM::draw(SkCanvas* canvas, SkString* errorMsg) { 64 TRACE_EVENT1("GM", TRACE_FUNC, "name", TRACE_STR_COPY(this->getName())); 65 this->drawBackground(canvas); 66 return this->drawContent(canvas, errorMsg); 67 } 68 69 DrawResult GM::drawContent(SkCanvas* canvas, SkString* errorMsg) { 70 TRACE_EVENT0("GM", TRACE_FUNC); 71 if (!fHaveCalledOnceBeforeDraw) { 72 fHaveCalledOnceBeforeDraw = true; 73 this->onOnceBeforeDraw(); 74 } 75 SkAutoCanvasRestore acr(canvas, true); 76 DrawResult drawResult = this->onDraw(canvas, errorMsg); 77 if (DrawResult::kOk != drawResult) { 78 if (DrawResult::kFail == drawResult) { 79 draw_failure_message(canvas, "DRAW FAILED: %s", errorMsg->c_str()); 80 } else if (SkString(kErrorMsg_DrawSkippedGpuOnly) == *errorMsg) { 81 draw_gpu_only_message(canvas); 82 } else { 83 draw_failure_message(canvas, "DRAW SKIPPED: %s", errorMsg->c_str()); 84 } 85 } 86 return drawResult; 87 } 88 89 void GM::drawBackground(SkCanvas* canvas) { 90 TRACE_EVENT0("GM", TRACE_FUNC); 91 if (!fHaveCalledOnceBeforeDraw) { 92 fHaveCalledOnceBeforeDraw = true; 93 this->onOnceBeforeDraw(); 94 } 95 SkAutoCanvasRestore acr(canvas, true); 96 canvas->drawColor(fBGColor, SkBlendMode::kSrc); 97 } 98 99 DrawResult GM::onDraw(SkCanvas* canvas, SkString* errorMsg) { 100 this->onDraw(canvas); 101 return DrawResult::kOk; 102 } 103 void GM::onDraw(SkCanvas*) { SK_ABORT("Not implemented."); } 104 105 106 SkISize SimpleGM::onISize() { return fSize; } 107 SkString SimpleGM::onShortName() { return fName; } 108 DrawResult SimpleGM::onDraw(SkCanvas* canvas, SkString* errorMsg) { 109 return fDrawProc(canvas, errorMsg); 110 } 111 112 SkISize SimpleGpuGM::onISize() { return fSize; } 113 SkString SimpleGpuGM::onShortName() { return fName; } 114 DrawResult SimpleGpuGM::onDraw(GrContext* ctx, GrRenderTargetContext* rtc, SkCanvas* canvas, 115 SkString* errorMsg) { 116 return fDrawProc(ctx, rtc, canvas, errorMsg); 117 } 118 119 const char* GM::getName() { 120 if (fShortName.size() == 0) { 121 fShortName = this->onShortName(); 122 } 123 return fShortName.c_str(); 124 } 125 126 void GM::setBGColor(SkColor color) { 127 fBGColor = color; 128 } 129 130 bool GM::animate(const SkAnimTimer& timer) { 131 return this->onAnimate(timer); 132 } 133 134 bool GM::runAsBench() const { return false; } 135 void GM::modifyGrContextOptions(GrContextOptions* options) {} 136 137 void GM::onOnceBeforeDraw() {} 138 139 bool GM::onAnimate(const SkAnimTimer&) { return false; } 140 bool GM::onHandleKey(SkUnichar uni) { return false; } 141 bool GM::onGetControls(SkMetaData*) { return false; } 142 void GM::onSetControls(const SkMetaData&) {} 143 144 ///////////////////////////////////////////////////////////////////////////////////////////// 145 146 void GM::drawSizeBounds(SkCanvas* canvas, SkColor color) { 147 SkISize size = this->getISize(); 148 SkRect r = SkRect::MakeWH(SkIntToScalar(size.width()), 149 SkIntToScalar(size.height())); 150 SkPaint paint; 151 paint.setColor(color); 152 canvas->drawRect(r, paint); 153 } 154 155 // need to explicitly declare this, or we get some weird infinite loop llist 156 template GMRegistry* GMRegistry::gHead; 157 158 DrawResult GpuGM::onDraw(GrContext* ctx, GrRenderTargetContext* rtc, SkCanvas* canvas, 159 SkString* errorMsg) { 160 this->onDraw(ctx, rtc, canvas); 161 return DrawResult::kOk; 162 } 163 void GpuGM::onDraw(GrContext*, GrRenderTargetContext*, SkCanvas*) { 164 SK_ABORT("Not implemented."); 165 } 166 167 DrawResult GpuGM::onDraw(SkCanvas* canvas, SkString* errorMsg) { 168 GrContext* ctx = canvas->getGrContext(); 169 GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext(); 170 if (!ctx || !rtc) { 171 *errorMsg = kErrorMsg_DrawSkippedGpuOnly; 172 return DrawResult::kSkip; 173 } 174 if (ctx->abandoned()) { 175 *errorMsg = "GrContext abandoned."; 176 return DrawResult::kFail; 177 } 178 return this->onDraw(ctx, rtc, canvas, errorMsg); 179 } 180 181 template <typename Fn> 182 static void mark(SkCanvas* canvas, SkScalar x, SkScalar y, Fn&& fn) { 183 SkPaint alpha; 184 alpha.setAlpha(0x50); 185 canvas->saveLayer(nullptr, &alpha); 186 canvas->translate(x,y); 187 canvas->scale(2,2); 188 fn(); 189 canvas->restore(); 190 } 191 192 void MarkGMGood(SkCanvas* canvas, SkScalar x, SkScalar y) { 193 mark(canvas, x,y, [&]{ 194 SkPaint paint; 195 196 // A green circle. 197 paint.setColor(SkColorSetRGB(27, 158, 119)); 198 canvas->drawCircle(0,0, 12, paint); 199 200 // Cut out a check mark. 201 paint.setBlendMode(SkBlendMode::kSrc); 202 paint.setColor(0x00000000); 203 paint.setStrokeWidth(2); 204 paint.setStyle(SkPaint::kStroke_Style); 205 canvas->drawLine(-6, 0, 206 -1, 5, paint); 207 canvas->drawLine(-1, +5, 208 +7, -5, paint); 209 }); 210 } 211 212 void MarkGMBad(SkCanvas* canvas, SkScalar x, SkScalar y) { 213 mark(canvas, x,y, [&] { 214 SkPaint paint; 215 216 // A red circle. 217 paint.setColor(SkColorSetRGB(231, 41, 138)); 218 canvas->drawCircle(0,0, 12, paint); 219 220 // Cut out an 'X'. 221 paint.setBlendMode(SkBlendMode::kSrc); 222 paint.setColor(0x00000000); 223 paint.setStrokeWidth(2); 224 paint.setStyle(SkPaint::kStroke_Style); 225 canvas->drawLine(-5,-5, 226 +5,+5, paint); 227 canvas->drawLine(+5,-5, 228 -5,+5, paint); 229 }); 230 } 231