blob: 54c28a7e5fdda973d6dd7bc6039741d921642f51 [file] [log] [blame]
commit-bot@chromium.org78a10782013-08-21 19:27:48 +00001/*
2 * Copyright 2013 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// This test only works with the GPU backend.
9
10#include "gm.h"
11
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000012#if SK_SUPPORT_GPU
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000013
Brian Osman11052242016-10-27 14:47:55 -040014#include "GrRenderTargetContextPriv.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000015#include "GrContext.h"
16#include "GrPathUtils.h"
17#include "GrTest.h"
18#include "SkColorPriv.h"
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000019#include "SkGeometry.h"
20
Brian Salomon89527432016-12-16 09:52:16 -050021#include "ops/GrTestMeshDrawOp.h"
joshualitt2771b562015-08-07 12:46:26 -070022
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000023#include "effects/GrBezierEffect.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000024
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000025static inline SkScalar eval_line(const SkPoint& p, const SkScalar lineEq[3], SkScalar sign) {
26 return sign * (lineEq[0] * p.fX + lineEq[1] * p.fY + lineEq[2]);
27}
28
29namespace skiagm {
joshualitt95964c62015-02-11 13:45:50 -080030
Brian Salomon6b316e92016-12-16 09:35:49 -050031class BezierCubicOrConicTestOp : public GrTestMeshDrawOp {
joshualitt95964c62015-02-11 13:45:50 -080032public:
Brian Salomon25a88092016-12-01 09:36:50 -050033 DEFINE_OP_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -080034
Brian Salomon6b316e92016-12-16 09:35:49 -050035 const char* name() const override { return "BezierCubicOrConicTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -080036
Brian Salomon649a3412017-03-09 13:50:43 -050037 static std::unique_ptr<GrMeshDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
38 GrColor color, const SkScalar klmEqs[9],
39 SkScalar sign) {
40 return std::unique_ptr<GrMeshDrawOp>(
Brian Salomon9e50f7b2017-03-06 12:02:34 -050041 new BezierCubicOrConicTestOp(gp, rect, color, klmEqs, sign));
Brian Salomon6b316e92016-12-16 09:35:49 -050042 }
43
44private:
Brian Salomon9e50f7b2017-03-06 12:02:34 -050045 BezierCubicOrConicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
Brian Salomon6b316e92016-12-16 09:35:49 -050046 const SkScalar klmEqs[9], SkScalar sign)
Brian Salomon9e50f7b2017-03-06 12:02:34 -050047 : INHERITED(ClassID(), rect, color), fRect(rect), fGeometryProcessor(std::move(gp)) {
joshualitt95964c62015-02-11 13:45:50 -080048 for (int i = 0; i < 9; i++) {
49 fKlmEqs[i] = klmEqs[i];
50 }
joshualitt95964c62015-02-11 13:45:50 -080051 fSign = sign;
52 }
joshualitt95964c62015-02-11 13:45:50 -080053 struct Vertex {
54 SkPoint fPosition;
55 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
56 };
57
bsalomon342bfc22016-04-01 06:06:20 -070058 void onPrepareDraws(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -070059 QuadHelper helper;
bsalomon342bfc22016-04-01 06:06:20 -070060 size_t vertexStride = fGeometryProcessor->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -070061 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -070062 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -070063 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -080064 return;
65 }
Brian Salomon9e50f7b2017-03-06 12:02:34 -050066 verts[0].fPosition.setRectFan(fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
joshualitt95964c62015-02-11 13:45:50 -080067 sizeof(Vertex));
68 for (int v = 0; v < 4; ++v) {
69 verts[v].fKLM[0] = eval_line(verts[v].fPosition, fKlmEqs + 0, fSign);
70 verts[v].fKLM[1] = eval_line(verts[v].fPosition, fKlmEqs + 3, fSign);
71 verts[v].fKLM[2] = eval_line(verts[v].fPosition, fKlmEqs + 6, 1.f);
72 }
bungeman06ca8ec2016-06-09 08:01:03 -070073 helper.recordDraw(target, fGeometryProcessor.get());
joshualitt95964c62015-02-11 13:45:50 -080074 }
75
Brian Salomon9e50f7b2017-03-06 12:02:34 -050076 SkScalar fKlmEqs[9];
77 SkScalar fSign;
78 SkRect fRect;
bungeman06ca8ec2016-06-09 08:01:03 -070079 sk_sp<GrGeometryProcessor> fGeometryProcessor;
joshualitt95964c62015-02-11 13:45:50 -080080
mtkleindbfd7ab2016-09-01 11:24:54 -070081 static constexpr int kVertsPerCubic = 4;
82 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -080083
Brian Salomon6b316e92016-12-16 09:35:49 -050084 typedef GrTestMeshDrawOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -080085};
86
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000087/**
88 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
89 */
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000090class BezierCubicEffects : public GM {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000091public:
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000092 BezierCubicEffects() {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000093 this->setBGColor(0xFFFFFFFF);
94 }
95
96protected:
mtklein36352bf2015-03-25 18:17:31 -070097 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000098 return SkString("bezier_cubic_effects");
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000099 }
100
mtklein36352bf2015-03-25 18:17:31 -0700101 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700102 return SkISize::Make(800, 800);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000103 }
104
mtklein36352bf2015-03-25 18:17:31 -0700105 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400106 GrRenderTargetContext* renderTargetContext =
107 canvas->internal_private_accessTopLayerRenderTargetContext();
108 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700109 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000110 return;
111 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000112
robertphillips175dd9b2016-04-28 14:32:04 -0700113 GrContext* context = canvas->getGrContext();
114 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800115 return;
116 }
117
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000118 struct Vertex {
119 SkPoint fPosition;
120 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
121 };
122
mtkleindbfd7ab2016-09-01 11:24:54 -0700123 constexpr int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000124 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000125
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000126 // Mult by 3 for each edge effect type
127 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
128 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400129 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
130 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000131 int row = 0;
132 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700133 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000134
135 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000136 SkPoint baseControlPts[] = {
137 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
138 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
139 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
140 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000141 };
joshualittb0a8a372014-09-23 09:50:21 -0700142 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700143 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800144 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700145 gp = GrCubicEffect::Make(color, SkMatrix::I(), et, *context->caps());
joshualittf5883a62016-01-13 07:47:38 -0800146 if (!gp) {
147 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000148 }
Mike Reeddf85c382017-02-14 10:59:19 -0500149 SkScalar x = col * w;
150 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000151 SkPoint controlPts[] = {
152 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
153 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
154 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
155 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
156 };
157 SkPoint chopped[10];
158 SkScalar klmEqs[9];
159 SkScalar klmSigns[3];
160 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
161 chopped,
162 klmEqs,
163 klmSigns);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000164
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000165 SkPaint ctrlPtPaint;
166 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000167 for (int i = 0; i < 4; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000168 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000169 }
170
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000171 SkPaint polyPaint;
172 polyPaint.setColor(0xffA0A0A0);
173 polyPaint.setStrokeWidth(0);
174 polyPaint.setStyle(SkPaint::kStroke_Style);
175 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000176
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000177 SkPaint choppedPtPaint;
178 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000179
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000180 for (int c = 0; c < cnt; ++c) {
181 SkPoint* pts = chopped + 3 * c;
182
183 for (int i = 0; i < 4; ++i) {
184 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
185 }
186
187 SkRect bounds;
188 bounds.set(pts, 4);
189
190 SkPaint boundsPaint;
191 boundsPaint.setColor(0xff808080);
192 boundsPaint.setStrokeWidth(0);
193 boundsPaint.setStyle(SkPaint::kStroke_Style);
194 canvas->drawRect(bounds, boundsPaint);
195
robertphillips28a838e2016-06-23 14:07:00 -0700196 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500197 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000198
Brian Salomon649a3412017-03-09 13:50:43 -0500199 std::unique_ptr<GrMeshDrawOp> op =
Brian Salomon6b316e92016-12-16 09:35:49 -0500200 BezierCubicOrConicTestOp::Make(gp, bounds, color, klmEqs, klmSigns[c]);
joshualitt95964c62015-02-11 13:45:50 -0800201
Brian Salomon649a3412017-03-09 13:50:43 -0500202 renderTargetContext->priv().testingOnly_addMeshDrawOp(
Brian Salomon82f44312017-01-11 13:42:54 -0500203 std::move(grPaint), GrAAType::kNone, std::move(op));
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000204 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000205 ++col;
206 if (numCols == col) {
207 col = 0;
208 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000209 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000210 }
211 }
212 }
213
214private:
215 typedef GM INHERITED;
216};
217
218//////////////////////////////////////////////////////////////////////////////
219
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000220/**
221 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
222 */
223class BezierConicEffects : public GM {
224public:
225 BezierConicEffects() {
226 this->setBGColor(0xFFFFFFFF);
227 }
228
229protected:
mtklein36352bf2015-03-25 18:17:31 -0700230 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000231 return SkString("bezier_conic_effects");
232 }
233
mtklein36352bf2015-03-25 18:17:31 -0700234 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700235 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000236 }
237
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000238
mtklein36352bf2015-03-25 18:17:31 -0700239 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400240 GrRenderTargetContext* renderTargetContext =
241 canvas->internal_private_accessTopLayerRenderTargetContext();
242 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700243 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000244 return;
245 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000246
robertphillips175dd9b2016-04-28 14:32:04 -0700247 GrContext* context = canvas->getGrContext();
248 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800249 return;
250 }
251
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000252 struct Vertex {
253 SkPoint fPosition;
254 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
255 };
256
mtkleindbfd7ab2016-09-01 11:24:54 -0700257 constexpr int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000258 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000259
260 // Mult by 3 for each edge effect type
261 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
262 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400263 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
264 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000265 int row = 0;
266 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700267 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000268
269 for (int i = 0; i < kNumConics; ++i) {
270 SkPoint baseControlPts[] = {
271 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
272 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
273 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
274 };
275 SkScalar weight = rand.nextRangeF(0.f, 2.f);
joshualittb0a8a372014-09-23 09:50:21 -0700276 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700277 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800278 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700279 gp = GrConicEffect::Make(color, SkMatrix::I(), et,
280 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800281 if (!gp) {
282 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000283 }
284
Mike Reeddf85c382017-02-14 10:59:19 -0500285 SkScalar x = col * w;
286 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000287 SkPoint controlPts[] = {
288 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
289 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
290 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
291 };
292 SkConic dst[4];
293 SkScalar klmEqs[9];
294 int cnt = chop_conic(controlPts, dst, weight);
295 GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
296
297 SkPaint ctrlPtPaint;
298 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
299 for (int i = 0; i < 3; ++i) {
300 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
301 }
302
303 SkPaint polyPaint;
304 polyPaint.setColor(0xffA0A0A0);
305 polyPaint.setStrokeWidth(0);
306 polyPaint.setStyle(SkPaint::kStroke_Style);
307 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
308
309 SkPaint choppedPtPaint;
310 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
311
312 for (int c = 0; c < cnt; ++c) {
313 SkPoint* pts = dst[c].fPts;
314 for (int i = 0; i < 3; ++i) {
315 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
316 }
317
318 SkRect bounds;
319 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
320 //bounds.set(bPts, 2);
321 bounds.set(pts, 3);
322
323 SkPaint boundsPaint;
324 boundsPaint.setColor(0xff808080);
325 boundsPaint.setStrokeWidth(0);
326 boundsPaint.setStyle(SkPaint::kStroke_Style);
327 canvas->drawRect(bounds, boundsPaint);
328
robertphillips28a838e2016-06-23 14:07:00 -0700329 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500330 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000331
Brian Salomon649a3412017-03-09 13:50:43 -0500332 std::unique_ptr<GrMeshDrawOp> op =
Brian Salomon6b316e92016-12-16 09:35:49 -0500333 BezierCubicOrConicTestOp::Make(gp, bounds, color, klmEqs, 1.f);
joshualitt95964c62015-02-11 13:45:50 -0800334
Brian Salomon649a3412017-03-09 13:50:43 -0500335 renderTargetContext->priv().testingOnly_addMeshDrawOp(
Brian Salomon82f44312017-01-11 13:42:54 -0500336 std::move(grPaint), GrAAType::kNone, std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000337 }
338 ++col;
339 if (numCols == col) {
340 col = 0;
341 ++row;
342 }
343 }
344 }
345 }
346
347private:
348 // Uses the max curvature function for quads to estimate
349 // where to chop the conic. If the max curvature is not
350 // found along the curve segment it will return 1 and
351 // dst[0] is the original conic. If it returns 2 the dst[0]
352 // and dst[1] are the two new conics.
353 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
354 SkScalar t = SkFindQuadMaxCurvature(src);
355 if (t == 0) {
356 if (dst) {
357 dst[0].set(src, weight);
358 }
359 return 1;
360 } else {
361 if (dst) {
362 SkConic conic;
363 conic.set(src, weight);
caryclark414c4292016-09-26 11:03:54 -0700364 if (!conic.chopAt(t, dst)) {
365 dst[0].set(src, weight);
366 return 1;
367 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000368 }
369 return 2;
370 }
371 }
372
373 // Calls split_conic on the entire conic and then once more on each subsection.
374 // Most cases will result in either 1 conic (chop point is not within t range)
375 // or 3 points (split once and then one subsection is split again).
376 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
377 SkConic dstTemp[2];
378 int conicCnt = split_conic(src, dstTemp, weight);
379 if (2 == conicCnt) {
380 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
381 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
382 } else {
383 dst[0] = dstTemp[0];
384 }
385 return conicCnt;
386 }
387
388 typedef GM INHERITED;
389};
390
391//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800392
Brian Salomon6b316e92016-12-16 09:35:49 -0500393class BezierQuadTestOp : public GrTestMeshDrawOp {
joshualitt95964c62015-02-11 13:45:50 -0800394public:
Brian Salomon25a88092016-12-01 09:36:50 -0500395 DEFINE_OP_CLASS_ID
Brian Salomon6b316e92016-12-16 09:35:49 -0500396 const char* name() const override { return "BezierQuadTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -0800397
Brian Salomon649a3412017-03-09 13:50:43 -0500398 static std::unique_ptr<GrMeshDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
399 GrColor color,
400 const GrPathUtils::QuadUVMatrix& devToUV) {
401 return std::unique_ptr<GrMeshDrawOp>(new BezierQuadTestOp(gp, rect, color, devToUV));
joshualitt95964c62015-02-11 13:45:50 -0800402 }
403
404private:
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500405 BezierQuadTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
Brian Salomon6b316e92016-12-16 09:35:49 -0500406 const GrPathUtils::QuadUVMatrix& devToUV)
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500407 : INHERITED(ClassID(), rect, color)
Brian Salomon6b316e92016-12-16 09:35:49 -0500408 , fDevToUV(devToUV)
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500409 , fRect(rect)
Brian Salomon6b316e92016-12-16 09:35:49 -0500410 , fGeometryProcessor(std::move(gp)) {}
joshualitt95964c62015-02-11 13:45:50 -0800411
412 struct Vertex {
413 SkPoint fPosition;
414 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
415 };
416
bsalomon342bfc22016-04-01 06:06:20 -0700417 void onPrepareDraws(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -0700418 QuadHelper helper;
bsalomon342bfc22016-04-01 06:06:20 -0700419 size_t vertexStride = fGeometryProcessor->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700420 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700421 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700422 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800423 return;
424 }
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500425 verts[0].fPosition.setRectFan(fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
joshualitt95964c62015-02-11 13:45:50 -0800426 sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800427 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
bungeman06ca8ec2016-06-09 08:01:03 -0700428 helper.recordDraw(target, fGeometryProcessor.get());
joshualitt95964c62015-02-11 13:45:50 -0800429 }
430
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500431 GrPathUtils::QuadUVMatrix fDevToUV;
432 SkRect fRect;
bungeman06ca8ec2016-06-09 08:01:03 -0700433 sk_sp<GrGeometryProcessor> fGeometryProcessor;
joshualitt95964c62015-02-11 13:45:50 -0800434
mtkleindbfd7ab2016-09-01 11:24:54 -0700435 static constexpr int kVertsPerCubic = 4;
436 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800437
Brian Salomon6b316e92016-12-16 09:35:49 -0500438 typedef GrTestMeshDrawOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800439};
440
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000441/**
442 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
443 */
444class BezierQuadEffects : public GM {
445public:
446 BezierQuadEffects() {
447 this->setBGColor(0xFFFFFFFF);
448 }
449
450protected:
mtklein36352bf2015-03-25 18:17:31 -0700451 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000452 return SkString("bezier_quad_effects");
453 }
454
mtklein36352bf2015-03-25 18:17:31 -0700455 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700456 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000457 }
458
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000459
mtklein36352bf2015-03-25 18:17:31 -0700460 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400461 GrRenderTargetContext* renderTargetContext =
462 canvas->internal_private_accessTopLayerRenderTargetContext();
463 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700464 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000465 return;
466 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000467
robertphillips175dd9b2016-04-28 14:32:04 -0700468 GrContext* context = canvas->getGrContext();
469 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800470 return;
471 }
472
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000473 struct Vertex {
474 SkPoint fPosition;
475 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
476 };
477
mtkleindbfd7ab2016-09-01 11:24:54 -0700478 constexpr int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000479 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000480
481 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
482 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400483 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
484 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000485 int row = 0;
486 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700487 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000488
489 for (int i = 0; i < kNumQuads; ++i) {
490 SkPoint baseControlPts[] = {
491 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
492 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
493 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
494 };
joshualittb0a8a372014-09-23 09:50:21 -0700495 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700496 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800497 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700498 gp = GrQuadEffect::Make(color, SkMatrix::I(), et,
499 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800500 if (!gp) {
501 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000502 }
503
Mike Reeddf85c382017-02-14 10:59:19 -0500504 SkScalar x = col * w;
505 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000506 SkPoint controlPts[] = {
507 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
508 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
509 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
510 };
511 SkPoint chopped[5];
512 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
513
514 SkPaint ctrlPtPaint;
515 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
516 for (int i = 0; i < 3; ++i) {
517 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
518 }
519
520 SkPaint polyPaint;
521 polyPaint.setColor(0xffA0A0A0);
522 polyPaint.setStrokeWidth(0);
523 polyPaint.setStyle(SkPaint::kStroke_Style);
524 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
525
526 SkPaint choppedPtPaint;
527 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
528
529 for (int c = 0; c < cnt; ++c) {
530 SkPoint* pts = chopped + 2 * c;
531
532 for (int i = 0; i < 3; ++i) {
533 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
534 }
535
536 SkRect bounds;
537 bounds.set(pts, 3);
538
539 SkPaint boundsPaint;
540 boundsPaint.setColor(0xff808080);
541 boundsPaint.setStrokeWidth(0);
542 boundsPaint.setStyle(SkPaint::kStroke_Style);
543 canvas->drawRect(bounds, boundsPaint);
544
robertphillips28a838e2016-06-23 14:07:00 -0700545 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500546 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
joshualitt3f284d72015-02-11 11:34:58 -0800547
joshualitt95964c62015-02-11 13:45:50 -0800548 GrPathUtils::QuadUVMatrix DevToUV(pts);
549
Brian Salomon649a3412017-03-09 13:50:43 -0500550 std::unique_ptr<GrMeshDrawOp> op =
Brian Salomonf8334782017-01-03 09:42:58 -0500551 BezierQuadTestOp::Make(gp, bounds, color, DevToUV);
joshualitt95964c62015-02-11 13:45:50 -0800552
Brian Salomon649a3412017-03-09 13:50:43 -0500553 renderTargetContext->priv().testingOnly_addMeshDrawOp(
Brian Salomon82f44312017-01-11 13:42:54 -0500554 std::move(grPaint), GrAAType::kNone, std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000555 }
556 ++col;
557 if (numCols == col) {
558 col = 0;
559 ++row;
560 }
561 }
562 }
563 }
564
565private:
566 typedef GM INHERITED;
567};
568
halcanary385fe4d2015-08-26 13:07:48 -0700569DEF_GM(return new BezierCubicEffects;)
570DEF_GM(return new BezierConicEffects;)
571DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000572}
573
574#endif