blob: 9167410e9f3c67c2b90cdafd417c3e0ecbd6395b [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];
Greg Daniel8199d942017-03-14 10:20:24 -0400159 int loopIndex;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000160 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
161 chopped,
162 klmEqs,
Greg Daniel8199d942017-03-14 10:20:24 -0400163 &loopIndex);
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);
Greg Daniel8199d942017-03-14 10:20:24 -0400167 canvas->drawCircle(controlPts[0].fX, controlPts[0].fY, 8.f, ctrlPtPaint);
168 for (int i = 1; i < 4; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000169 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000170 }
171
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000172 SkPaint polyPaint;
173 polyPaint.setColor(0xffA0A0A0);
174 polyPaint.setStrokeWidth(0);
175 polyPaint.setStyle(SkPaint::kStroke_Style);
176 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000177
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000178 SkPaint choppedPtPaint;
179 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000180
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000181 for (int c = 0; c < cnt; ++c) {
182 SkPoint* pts = chopped + 3 * c;
183
184 for (int i = 0; i < 4; ++i) {
185 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
186 }
187
188 SkRect bounds;
189 bounds.set(pts, 4);
190
191 SkPaint boundsPaint;
192 boundsPaint.setColor(0xff808080);
193 boundsPaint.setStrokeWidth(0);
194 boundsPaint.setStyle(SkPaint::kStroke_Style);
195 canvas->drawRect(bounds, boundsPaint);
196
robertphillips28a838e2016-06-23 14:07:00 -0700197 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500198 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000199
Greg Daniel8199d942017-03-14 10:20:24 -0400200 SkScalar sign = 1.0f;
201 if (c == loopIndex && cnt != 3) {
202 sign = -1.0f;
203 }
204
Brian Salomon649a3412017-03-09 13:50:43 -0500205 std::unique_ptr<GrMeshDrawOp> op =
Greg Daniel8199d942017-03-14 10:20:24 -0400206 BezierCubicOrConicTestOp::Make(gp, bounds, color, klmEqs, sign);
joshualitt95964c62015-02-11 13:45:50 -0800207
Brian Salomon649a3412017-03-09 13:50:43 -0500208 renderTargetContext->priv().testingOnly_addMeshDrawOp(
Brian Salomon82f44312017-01-11 13:42:54 -0500209 std::move(grPaint), GrAAType::kNone, std::move(op));
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000210 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000211 ++col;
212 if (numCols == col) {
213 col = 0;
214 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000215 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000216 }
217 }
218 }
219
220private:
221 typedef GM INHERITED;
222};
223
224//////////////////////////////////////////////////////////////////////////////
225
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000226/**
227 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
228 */
229class BezierConicEffects : public GM {
230public:
231 BezierConicEffects() {
232 this->setBGColor(0xFFFFFFFF);
233 }
234
235protected:
mtklein36352bf2015-03-25 18:17:31 -0700236 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000237 return SkString("bezier_conic_effects");
238 }
239
mtklein36352bf2015-03-25 18:17:31 -0700240 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700241 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000242 }
243
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000244
mtklein36352bf2015-03-25 18:17:31 -0700245 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400246 GrRenderTargetContext* renderTargetContext =
247 canvas->internal_private_accessTopLayerRenderTargetContext();
248 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700249 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000250 return;
251 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000252
robertphillips175dd9b2016-04-28 14:32:04 -0700253 GrContext* context = canvas->getGrContext();
254 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800255 return;
256 }
257
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000258 struct Vertex {
259 SkPoint fPosition;
260 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
261 };
262
mtkleindbfd7ab2016-09-01 11:24:54 -0700263 constexpr int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000264 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000265
266 // Mult by 3 for each edge effect type
267 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
268 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400269 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
270 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000271 int row = 0;
272 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700273 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000274
275 for (int i = 0; i < kNumConics; ++i) {
276 SkPoint baseControlPts[] = {
277 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
278 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
279 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
280 };
281 SkScalar weight = rand.nextRangeF(0.f, 2.f);
joshualittb0a8a372014-09-23 09:50:21 -0700282 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700283 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800284 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700285 gp = GrConicEffect::Make(color, SkMatrix::I(), et,
286 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800287 if (!gp) {
288 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000289 }
290
Mike Reeddf85c382017-02-14 10:59:19 -0500291 SkScalar x = col * w;
292 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000293 SkPoint controlPts[] = {
294 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
295 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
296 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
297 };
298 SkConic dst[4];
299 SkScalar klmEqs[9];
300 int cnt = chop_conic(controlPts, dst, weight);
301 GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
302
303 SkPaint ctrlPtPaint;
304 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
305 for (int i = 0; i < 3; ++i) {
306 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
307 }
308
309 SkPaint polyPaint;
310 polyPaint.setColor(0xffA0A0A0);
311 polyPaint.setStrokeWidth(0);
312 polyPaint.setStyle(SkPaint::kStroke_Style);
313 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
314
315 SkPaint choppedPtPaint;
316 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
317
318 for (int c = 0; c < cnt; ++c) {
319 SkPoint* pts = dst[c].fPts;
320 for (int i = 0; i < 3; ++i) {
321 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
322 }
323
324 SkRect bounds;
325 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
326 //bounds.set(bPts, 2);
327 bounds.set(pts, 3);
328
329 SkPaint boundsPaint;
330 boundsPaint.setColor(0xff808080);
331 boundsPaint.setStrokeWidth(0);
332 boundsPaint.setStyle(SkPaint::kStroke_Style);
333 canvas->drawRect(bounds, boundsPaint);
334
robertphillips28a838e2016-06-23 14:07:00 -0700335 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500336 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000337
Brian Salomon649a3412017-03-09 13:50:43 -0500338 std::unique_ptr<GrMeshDrawOp> op =
Brian Salomon6b316e92016-12-16 09:35:49 -0500339 BezierCubicOrConicTestOp::Make(gp, bounds, color, klmEqs, 1.f);
joshualitt95964c62015-02-11 13:45:50 -0800340
Brian Salomon649a3412017-03-09 13:50:43 -0500341 renderTargetContext->priv().testingOnly_addMeshDrawOp(
Brian Salomon82f44312017-01-11 13:42:54 -0500342 std::move(grPaint), GrAAType::kNone, std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000343 }
344 ++col;
345 if (numCols == col) {
346 col = 0;
347 ++row;
348 }
349 }
350 }
351 }
352
353private:
354 // Uses the max curvature function for quads to estimate
355 // where to chop the conic. If the max curvature is not
356 // found along the curve segment it will return 1 and
357 // dst[0] is the original conic. If it returns 2 the dst[0]
358 // and dst[1] are the two new conics.
359 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
360 SkScalar t = SkFindQuadMaxCurvature(src);
361 if (t == 0) {
362 if (dst) {
363 dst[0].set(src, weight);
364 }
365 return 1;
366 } else {
367 if (dst) {
368 SkConic conic;
369 conic.set(src, weight);
caryclark414c4292016-09-26 11:03:54 -0700370 if (!conic.chopAt(t, dst)) {
371 dst[0].set(src, weight);
372 return 1;
373 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000374 }
375 return 2;
376 }
377 }
378
379 // Calls split_conic on the entire conic and then once more on each subsection.
380 // Most cases will result in either 1 conic (chop point is not within t range)
381 // or 3 points (split once and then one subsection is split again).
382 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
383 SkConic dstTemp[2];
384 int conicCnt = split_conic(src, dstTemp, weight);
385 if (2 == conicCnt) {
386 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
387 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
388 } else {
389 dst[0] = dstTemp[0];
390 }
391 return conicCnt;
392 }
393
394 typedef GM INHERITED;
395};
396
397//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800398
Brian Salomon6b316e92016-12-16 09:35:49 -0500399class BezierQuadTestOp : public GrTestMeshDrawOp {
joshualitt95964c62015-02-11 13:45:50 -0800400public:
Brian Salomon25a88092016-12-01 09:36:50 -0500401 DEFINE_OP_CLASS_ID
Brian Salomon6b316e92016-12-16 09:35:49 -0500402 const char* name() const override { return "BezierQuadTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -0800403
Brian Salomon649a3412017-03-09 13:50:43 -0500404 static std::unique_ptr<GrMeshDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
405 GrColor color,
406 const GrPathUtils::QuadUVMatrix& devToUV) {
407 return std::unique_ptr<GrMeshDrawOp>(new BezierQuadTestOp(gp, rect, color, devToUV));
joshualitt95964c62015-02-11 13:45:50 -0800408 }
409
410private:
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500411 BezierQuadTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
Brian Salomon6b316e92016-12-16 09:35:49 -0500412 const GrPathUtils::QuadUVMatrix& devToUV)
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500413 : INHERITED(ClassID(), rect, color)
Brian Salomon6b316e92016-12-16 09:35:49 -0500414 , fDevToUV(devToUV)
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500415 , fRect(rect)
Brian Salomon6b316e92016-12-16 09:35:49 -0500416 , fGeometryProcessor(std::move(gp)) {}
joshualitt95964c62015-02-11 13:45:50 -0800417
418 struct Vertex {
419 SkPoint fPosition;
420 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
421 };
422
bsalomon342bfc22016-04-01 06:06:20 -0700423 void onPrepareDraws(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -0700424 QuadHelper helper;
bsalomon342bfc22016-04-01 06:06:20 -0700425 size_t vertexStride = fGeometryProcessor->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700426 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700427 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700428 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800429 return;
430 }
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500431 verts[0].fPosition.setRectFan(fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
joshualitt95964c62015-02-11 13:45:50 -0800432 sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800433 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
bungeman06ca8ec2016-06-09 08:01:03 -0700434 helper.recordDraw(target, fGeometryProcessor.get());
joshualitt95964c62015-02-11 13:45:50 -0800435 }
436
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500437 GrPathUtils::QuadUVMatrix fDevToUV;
438 SkRect fRect;
bungeman06ca8ec2016-06-09 08:01:03 -0700439 sk_sp<GrGeometryProcessor> fGeometryProcessor;
joshualitt95964c62015-02-11 13:45:50 -0800440
mtkleindbfd7ab2016-09-01 11:24:54 -0700441 static constexpr int kVertsPerCubic = 4;
442 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800443
Brian Salomon6b316e92016-12-16 09:35:49 -0500444 typedef GrTestMeshDrawOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800445};
446
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000447/**
448 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
449 */
450class BezierQuadEffects : public GM {
451public:
452 BezierQuadEffects() {
453 this->setBGColor(0xFFFFFFFF);
454 }
455
456protected:
mtklein36352bf2015-03-25 18:17:31 -0700457 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000458 return SkString("bezier_quad_effects");
459 }
460
mtklein36352bf2015-03-25 18:17:31 -0700461 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700462 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000463 }
464
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000465
mtklein36352bf2015-03-25 18:17:31 -0700466 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400467 GrRenderTargetContext* renderTargetContext =
468 canvas->internal_private_accessTopLayerRenderTargetContext();
469 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700470 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000471 return;
472 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000473
robertphillips175dd9b2016-04-28 14:32:04 -0700474 GrContext* context = canvas->getGrContext();
475 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800476 return;
477 }
478
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000479 struct Vertex {
480 SkPoint fPosition;
481 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
482 };
483
mtkleindbfd7ab2016-09-01 11:24:54 -0700484 constexpr int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000485 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000486
487 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
488 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400489 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
490 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000491 int row = 0;
492 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700493 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000494
495 for (int i = 0; i < kNumQuads; ++i) {
496 SkPoint baseControlPts[] = {
497 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
498 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
499 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
500 };
joshualittb0a8a372014-09-23 09:50:21 -0700501 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700502 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800503 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700504 gp = GrQuadEffect::Make(color, SkMatrix::I(), et,
505 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800506 if (!gp) {
507 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000508 }
509
Mike Reeddf85c382017-02-14 10:59:19 -0500510 SkScalar x = col * w;
511 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000512 SkPoint controlPts[] = {
513 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
514 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
515 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
516 };
517 SkPoint chopped[5];
518 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
519
520 SkPaint ctrlPtPaint;
521 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
522 for (int i = 0; i < 3; ++i) {
523 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
524 }
525
526 SkPaint polyPaint;
527 polyPaint.setColor(0xffA0A0A0);
528 polyPaint.setStrokeWidth(0);
529 polyPaint.setStyle(SkPaint::kStroke_Style);
530 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
531
532 SkPaint choppedPtPaint;
533 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
534
535 for (int c = 0; c < cnt; ++c) {
536 SkPoint* pts = chopped + 2 * c;
537
538 for (int i = 0; i < 3; ++i) {
539 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
540 }
541
542 SkRect bounds;
543 bounds.set(pts, 3);
544
545 SkPaint boundsPaint;
546 boundsPaint.setColor(0xff808080);
547 boundsPaint.setStrokeWidth(0);
548 boundsPaint.setStyle(SkPaint::kStroke_Style);
549 canvas->drawRect(bounds, boundsPaint);
550
robertphillips28a838e2016-06-23 14:07:00 -0700551 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500552 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
joshualitt3f284d72015-02-11 11:34:58 -0800553
joshualitt95964c62015-02-11 13:45:50 -0800554 GrPathUtils::QuadUVMatrix DevToUV(pts);
555
Brian Salomon649a3412017-03-09 13:50:43 -0500556 std::unique_ptr<GrMeshDrawOp> op =
Brian Salomonf8334782017-01-03 09:42:58 -0500557 BezierQuadTestOp::Make(gp, bounds, color, DevToUV);
joshualitt95964c62015-02-11 13:45:50 -0800558
Brian Salomon649a3412017-03-09 13:50:43 -0500559 renderTargetContext->priv().testingOnly_addMeshDrawOp(
Brian Salomon82f44312017-01-11 13:42:54 -0500560 std::move(grPaint), GrAAType::kNone, std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000561 }
562 ++col;
563 if (numCols == col) {
564 col = 0;
565 ++row;
566 }
567 }
568 }
569 }
570
571private:
572 typedef GM INHERITED;
573};
574
halcanary385fe4d2015-08-26 13:07:48 -0700575DEF_GM(return new BezierCubicEffects;)
576DEF_GM(return new BezierConicEffects;)
577DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000578}
579
580#endif