blob: 9481643273563ad4d6e446f24042cc13f658b05a [file] [log] [blame]
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +00001/*
2 * Copyright 2012 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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#include "include/core/SkBlendMode.h"
10#include "include/core/SkCanvas.h"
11#include "include/core/SkMatrix.h"
12#include "include/core/SkPaint.h"
13#include "include/core/SkPoint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/core/SkRRect.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040015#include "include/core/SkRect.h"
16#include "include/core/SkScalar.h"
17#include "include/core/SkSize.h"
18#include "include/core/SkString.h"
19#include "include/core/SkTypes.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040020#include "include/private/GrSharedEnums.h"
21#include "include/private/GrTypesPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/gpu/GrCaps.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040023#include "src/gpu/GrFragmentProcessor.h"
24#include "src/gpu/GrPaint.h"
25#include "src/gpu/GrRenderTargetContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "src/gpu/GrRenderTargetContextPriv.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040027#include "src/gpu/effects/GrPorterDuffXferProcessor.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050028#include "src/gpu/effects/GrRRectEffect.h"
29#include "src/gpu/ops/GrDrawOp.h"
30#include "src/gpu/ops/GrFillRectOp.h"
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +000031
Ben Wagner7fde8e12019-05-01 17:28:53 -040032#include <memory>
33#include <utility>
34
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +000035namespace skiagm {
36
37///////////////////////////////////////////////////////////////////////////////
38
39class RRectGM : public GM {
40public:
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +000041 enum Type {
42 kBW_Draw_Type,
43 kAA_Draw_Type,
44 kBW_Clip_Type,
45 kAA_Clip_Type,
46 kEffect_Type,
47 };
herbb10fe492016-01-08 13:48:43 -080048 RRectGM(Type type) : fType(type) { }
49
50protected:
51
52 void onOnceBeforeDraw() override {
Mike Kleind46dce32018-08-16 10:17:03 -040053 this->setBGColor(0xFFDDDDDD);
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +000054 this->setUpRRects();
55 }
56
mtklein36352bf2015-03-25 18:17:31 -070057 SkString onShortName() override {
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +000058 SkString name("rrect");
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +000059 switch (fType) {
60 case kBW_Draw_Type:
61 name.append("_draw_bw");
62 break;
63 case kAA_Draw_Type:
64 name.append("_draw_aa");
65 break;
66 case kBW_Clip_Type:
67 name.append("_clip_bw");
68 break;
69 case kAA_Clip_Type:
70 name.append("_clip_aa");
71 break;
72 case kEffect_Type:
73 name.append("_effect");
74 break;
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +000075 }
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +000076 return name;
77 }
78
mtklein36352bf2015-03-25 18:17:31 -070079 SkISize onISize() override { return SkISize::Make(kImageWidth, kImageHeight); }
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +000080
Chris Dalton50e24d72019-02-07 16:20:09 -070081 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
Brian Osman11052242016-10-27 14:47:55 -040082 GrRenderTargetContext* renderTargetContext =
83 canvas->internal_private_accessTopLayerRenderTargetContext();
Robert Phillips95c250c2020-06-29 15:36:12 -040084 auto context = canvas->recordingContext();
Chris Dalton50e24d72019-02-07 16:20:09 -070085 if (kEffect_Type == fType && (!renderTargetContext || !context)) {
86 *errorMsg = kErrorMsg_DrawSkippedGpuOnly;
87 return DrawResult::kSkip;
Robert Phillips7c525e62018-06-12 10:11:12 -040088 }
89
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +000090 SkPaint paint;
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +000091 if (kAA_Draw_Type == fType) {
92 paint.setAntiAlias(true);
93 }
skia.committer@gmail.comf1f66c02014-03-05 03:02:06 +000094
mtkleindbfd7ab2016-09-01 11:24:54 -070095 const SkRect kMaxTileBound = SkRect::MakeWH(SkIntToScalar(kTileX),
96 SkIntToScalar(kTileY));
commit-bot@chromium.orgbfce48e2014-03-10 19:33:16 +000097#ifdef SK_DEBUG
mtkleindbfd7ab2016-09-01 11:24:54 -070098 const SkRect kMaxImageBound = SkRect::MakeWH(SkIntToScalar(kImageWidth),
99 SkIntToScalar(kImageHeight));
commit-bot@chromium.orgbfce48e2014-03-10 19:33:16 +0000100#endif
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000101
Ethan Nicholas1706f842017-11-10 11:58:19 -0500102 int lastEdgeType = (kEffect_Type == fType) ? (int) GrClipEdgeType::kLast: 0;
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000103
commit-bot@chromium.orgbfce48e2014-03-10 19:33:16 +0000104 int y = 1;
bsalomon@google.comb0ba39d2014-03-10 19:51:46 +0000105 for (int et = 0; et <= lastEdgeType; ++et) {
commit-bot@chromium.orgbfce48e2014-03-10 19:33:16 +0000106 int x = 1;
107 for (int curRRect = 0; curRRect < kNumRRects; ++curRRect) {
108 bool drew = true;
109#ifdef SK_DEBUG
110 SkASSERT(kMaxTileBound.contains(fRRects[curRRect].getBounds()));
111 SkRect imageSpaceBounds = fRRects[curRRect].getBounds();
112 imageSpaceBounds.offset(SkIntToScalar(x), SkIntToScalar(y));
113 SkASSERT(kMaxImageBound.contains(imageSpaceBounds));
114#endif
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000115 canvas->save();
116 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +0000117 if (kEffect_Type == fType) {
commit-bot@chromium.orgbfce48e2014-03-10 19:33:16 +0000118 SkRRect rrect = fRRects[curRRect];
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +0000119 rrect.offset(SkIntToScalar(x), SkIntToScalar(y));
Ethan Nicholas0f3c7322017-11-09 14:51:17 -0500120 GrClipEdgeType edgeType = (GrClipEdgeType) et;
Ethan Nicholaseace9352018-10-15 20:09:54 +0000121 const auto& caps = *renderTargetContext->caps()->shaderCaps();
John Stiles851b90e2020-06-17 13:53:37 -0400122 auto [success, fp] = GrRRectEffect::Make(/*inputFP=*/nullptr,
123 edgeType, rrect, caps);
124 if (success) {
Brian Salomon82f44312017-01-11 13:42:54 -0500125 GrPaint grPaint;
126 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
John Stiles41d91b62020-07-21 14:39:40 -0400127 grPaint.setCoverageFragmentProcessor(std::move(fp));
Brian Osmancb3d0872018-10-16 15:19:28 -0400128 grPaint.setColor4f({ 0, 0, 0, 1.f });
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +0000129
130 SkRect bounds = rrect.getBounds();
131 bounds.outset(2.f, 2.f);
skia.committer@gmail.comf1f66c02014-03-05 03:02:06 +0000132
Brian Salomonac70f842017-05-08 10:43:33 -0400133 renderTargetContext->priv().testingOnly_addDrawOp(
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400134 GrFillRectOp::MakeNonAARect(context, std::move(grPaint),
135 SkMatrix::I(), bounds));
commit-bot@chromium.orgbfce48e2014-03-10 19:33:16 +0000136 } else {
137 drew = false;
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +0000138 }
139 } else if (kBW_Clip_Type == fType || kAA_Clip_Type == fType) {
140 bool aaClip = (kAA_Clip_Type == fType);
reed66998382016-09-21 11:15:07 -0700141 canvas->clipRRect(fRRects[curRRect], aaClip);
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000142 canvas->drawRect(kMaxTileBound, paint);
143 } else {
commit-bot@chromium.orgbfce48e2014-03-10 19:33:16 +0000144 canvas->drawRRect(fRRects[curRRect], paint);
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000145 }
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000146 canvas->restore();
commit-bot@chromium.orgbfce48e2014-03-10 19:33:16 +0000147 if (drew) {
148 x = x + kTileX;
149 if (x > kImageWidth) {
150 x = 1;
151 y += kTileY;
152 }
153 }
154 }
155 if (x != 1) {
156 y += kTileY;
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000157 }
158 }
Chris Dalton50e24d72019-02-07 16:20:09 -0700159 return DrawResult::kOk;
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000160 }
161
162 void setUpRRects() {
skia.committer@gmail.com7a03d862012-12-18 02:03:03 +0000163 // each RRect must fit in a 0x0 -> (kTileX-2)x(kTileY-2) block. These will be tiled across
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000164 // the screen in kTileX x kTileY tiles. The extra empty pixels on each side are for AA.
165
166 // simple cases
167 fRRects[0].setRect(SkRect::MakeWH(kTileX-2, kTileY-2));
168 fRRects[1].setOval(SkRect::MakeWH(kTileX-2, kTileY-2));
169 fRRects[2].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 10);
commit-bot@chromium.orgc2f78242014-02-19 15:18:05 +0000170 fRRects[3].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 5);
171 // small circular corners are an interesting test case for gpu clipping
172 fRRects[4].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 1, 1);
173 fRRects[5].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 0.5f, 0.5f);
174 fRRects[6].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 0.2f, 0.2f);
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000175
176 // The first complex case needs special handling since it is a square
177 fRRects[kNumSimpleCases].setRectRadii(SkRect::MakeWH(kTileY-2, kTileY-2), gRadii[0]);
mike@reedtribe.orgf6100c82012-12-24 13:56:17 +0000178 for (size_t i = 1; i < SK_ARRAY_COUNT(gRadii); ++i) {
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000179 fRRects[kNumSimpleCases+i].setRectRadii(SkRect::MakeWH(kTileX-2, kTileY-2), gRadii[i]);
180 }
181 }
182
183private:
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +0000184 Type fType;
skia.committer@gmail.comf1f66c02014-03-05 03:02:06 +0000185
mtkleindbfd7ab2016-09-01 11:24:54 -0700186 static constexpr int kImageWidth = 640;
187 static constexpr int kImageHeight = 480;
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000188
mtkleindbfd7ab2016-09-01 11:24:54 -0700189 static constexpr int kTileX = 80;
190 static constexpr int kTileY = 40;
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000191
mtkleindbfd7ab2016-09-01 11:24:54 -0700192 static constexpr int kNumSimpleCases = 7;
193 static constexpr int kNumComplexCases = 35;
robertphillips@google.com5683d422012-12-17 21:58:02 +0000194 static const SkVector gRadii[kNumComplexCases][4];
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000195
mtkleindbfd7ab2016-09-01 11:24:54 -0700196 static constexpr int kNumRRects = kNumSimpleCases + kNumComplexCases;
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000197 SkRRect fRRects[kNumRRects];
198
John Stiles7571f9e2020-09-02 22:42:33 -0400199 using INHERITED = GM;
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000200};
201
202// Radii for the various test cases. Order is UL, UR, LR, LL
203const SkVector RRectGM::gRadii[kNumComplexCases][4] = {
204 // a circle
205 { { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY } },
206
207 // odd ball cases
208 { { 8, 8 }, { 32, 32 }, { 8, 8 }, { 32, 32 } },
209 { { 16, 8 }, { 8, 16 }, { 16, 8 }, { 8, 16 } },
210 { { 0, 0 }, { 16, 16 }, { 8, 8 }, { 32, 32 } },
211
212 // UL
213 { { 30, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
214 { { 30, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
215 { { 15, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
216
217 // UR
218 { { 0, 0 }, { 30, 30 }, { 0, 0 }, { 0, 0 } },
219 { { 0, 0 }, { 30, 15 }, { 0, 0 }, { 0, 0 } },
220 { { 0, 0 }, { 15, 30 }, { 0, 0 }, { 0, 0 } },
221
222 // LR
223 { { 0, 0 }, { 0, 0 }, { 30, 30 }, { 0, 0 } },
224 { { 0, 0 }, { 0, 0 }, { 30, 15 }, { 0, 0 } },
225 { { 0, 0 }, { 0, 0 }, { 15, 30 }, { 0, 0 } },
226
227 // LL
228 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 30 } },
229 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 15 } },
230 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 30 } },
231
232 // over-sized radii
233 { { 0, 0 }, { 100, 400 }, { 0, 0 }, { 0, 0 } },
234 { { 0, 0 }, { 400, 400 }, { 0, 0 }, { 0, 0 } },
235 { { 400, 400 }, { 400, 400 }, { 400, 400 }, { 400, 400 } },
commit-bot@chromium.orgcb3672e2014-02-21 22:41:56 +0000236
237 // circular corner tabs
238 { { 0, 0 }, { 20, 20 }, { 20, 20 }, { 0, 0 } },
239 { { 20, 20 }, { 20, 20 }, { 0, 0 }, { 0, 0 } },
240 { { 0, 0 }, { 0, 0 }, { 20, 20 }, { 20, 20 } },
241 { { 20, 20 }, { 0, 0 }, { 0, 0 }, { 20, 20 } },
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000242
commit-bot@chromium.org04eff722014-03-24 14:53:09 +0000243 // small radius circular corner tabs
244 { { 0, 0 }, { 0.2f, 0.2f }, { 0.2f, 0.2f }, { 0, 0 } },
245 { { 0.3f, 0.3f }, { 0.3f, .3f }, { 0, 0 }, { 0, 0 } },
246
commit-bot@chromium.orgc5c748c2014-03-11 15:54:51 +0000247 // single circular corner cases
248 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 15 } },
249 { { 0, 0 }, { 0, 0 }, { 15, 15 }, { 0, 0 } },
250 { { 0, 0 }, { 15, 15 }, { 0, 0 }, { 0, 0 } },
251 { { 15, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
commit-bot@chromium.orgfa5edbe2014-03-13 18:01:05 +0000252
253 // nine patch elliptical
254 { { 5, 7 }, { 8, 7 }, { 8, 12 }, { 5, 12 } },
255 { { 0, 7 }, { 8, 7 }, { 8, 12 }, { 0, 12 } },
commit-bot@chromium.org04eff722014-03-24 14:53:09 +0000256
257 // nine patch elliptical, small radii
258 { { 0.4f, 7 }, { 8, 7 }, { 8, 12 }, { 0.4f, 12 } },
259 { { 0.4f, 0.4f }, { 8, 0.4f }, { 8, 12 }, { 0.4f, 12 } },
260 { { 20, 0.4f }, { 18, 0.4f }, { 18, 0.4f }, { 20, 0.4f } },
261 { { 0.3f, 0.4f }, { 0.3f, 0.4f }, { 0.3f, 0.4f }, { 0.3f, 0.4f } },
262
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000263};
264
265///////////////////////////////////////////////////////////////////////////////
266
commit-bot@chromium.orgfbde87f2014-03-04 16:25:34 +0000267DEF_GM( return new RRectGM(RRectGM::kAA_Draw_Type); )
268DEF_GM( return new RRectGM(RRectGM::kBW_Draw_Type); )
269DEF_GM( return new RRectGM(RRectGM::kAA_Clip_Type); )
270DEF_GM( return new RRectGM(RRectGM::kBW_Clip_Type); )
271DEF_GM( return new RRectGM(RRectGM::kEffect_Type); )
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000272
John Stilesa6841be2020-08-06 14:11:56 -0400273} // namespace skiagm