blob: 1886a4a2b0ae811503045fc42a389dadd4736838 [file] [log] [blame]
commit-bot@chromium.org78a10782013-08-21 19:27:48 +00001
2/*
3 * Copyright 2013 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9// This test only works with the GPU backend.
10
11#include "gm.h"
12
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000013#if SK_SUPPORT_GPU
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000014
bsalomon75398562015-08-17 12:55:38 -070015#include "GrBatchFlushState.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000016#include "GrContext.h"
17#include "GrPathUtils.h"
18#include "GrTest.h"
19#include "SkColorPriv.h"
20#include "SkDevice.h"
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000021#include "SkGeometry.h"
22
joshualitt2771b562015-08-07 12:46:26 -070023#include "batches/GrTestBatch.h"
24
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000025#include "effects/GrBezierEffect.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000026
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000027static inline SkScalar eval_line(const SkPoint& p, const SkScalar lineEq[3], SkScalar sign) {
28 return sign * (lineEq[0] * p.fX + lineEq[1] * p.fY + lineEq[2]);
29}
30
31namespace skiagm {
joshualitt95964c62015-02-11 13:45:50 -080032
33class BezierCubicOrConicTestBatch : public GrTestBatch {
34public:
35 struct Geometry : public GrTestBatch::Geometry {
36 SkRect fBounds;
37 };
38
mtklein36352bf2015-03-25 18:17:31 -070039 const char* name() const override { return "BezierCubicOrConicTestBatch"; }
joshualitt95964c62015-02-11 13:45:50 -080040
bsalomonabd30f52015-08-13 13:34:48 -070041 static GrDrawBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo,
42 const SkScalar klmEqs[9], SkScalar sign) {
halcanary385fe4d2015-08-26 13:07:48 -070043 return new BezierCubicOrConicTestBatch(gp, geo, klmEqs, sign);
joshualitt95964c62015-02-11 13:45:50 -080044 }
45
46private:
47 BezierCubicOrConicTestBatch(const GrGeometryProcessor* gp, const Geometry& geo,
48 const SkScalar klmEqs[9], SkScalar sign)
joshualitt99c7c072015-05-01 13:43:30 -070049 : INHERITED(gp, geo.fBounds) {
joshualittdbe1e6f2015-07-16 08:12:45 -070050 this->initClassID<BezierCubicOrConicTestBatch>();
joshualitt95964c62015-02-11 13:45:50 -080051 for (int i = 0; i < 9; i++) {
52 fKlmEqs[i] = klmEqs[i];
53 }
54
55 fGeometry = geo;
56 fSign = sign;
57 }
58
59 struct Vertex {
60 SkPoint fPosition;
61 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
62 };
63
mtklein36352bf2015-03-25 18:17:31 -070064 Geometry* geoData(int index) override {
joshualitt95964c62015-02-11 13:45:50 -080065 SkASSERT(0 == index);
66 return &fGeometry;
67 }
68
joshualitt88c23fc2015-05-13 14:18:07 -070069 const Geometry* geoData(int index) const override {
70 SkASSERT(0 == index);
71 return &fGeometry;
72 }
73
bsalomon75398562015-08-17 12:55:38 -070074 void generateGeometry(Target* target) override {
bsalomonb5238a72015-05-05 07:49:49 -070075 QuadHelper helper;
bsalomoned0bcad2015-05-04 10:36:42 -070076 size_t vertexStride = this->geometryProcessor()->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -070077 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -070078 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -070079 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -080080 return;
81 }
82
joshualitt95964c62015-02-11 13:45:50 -080083 verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop,
84 fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom,
85 sizeof(Vertex));
86 for (int v = 0; v < 4; ++v) {
87 verts[v].fKLM[0] = eval_line(verts[v].fPosition, fKlmEqs + 0, fSign);
88 verts[v].fKLM[1] = eval_line(verts[v].fPosition, fKlmEqs + 3, fSign);
89 verts[v].fKLM[2] = eval_line(verts[v].fPosition, fKlmEqs + 6, 1.f);
90 }
bsalomon75398562015-08-17 12:55:38 -070091 helper.recordDraw(target);
joshualitt95964c62015-02-11 13:45:50 -080092 }
93
94 Geometry fGeometry;
95 SkScalar fKlmEqs[9];
96 SkScalar fSign;
97
98 static const int kVertsPerCubic = 4;
99 static const int kIndicesPerCubic = 6;
100
101 typedef GrTestBatch INHERITED;
102};
103
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000104/**
105 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
106 */
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000107class BezierCubicEffects : public GM {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000108public:
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000109 BezierCubicEffects() {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000110 this->setBGColor(0xFFFFFFFF);
111 }
112
113protected:
mtklein36352bf2015-03-25 18:17:31 -0700114 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000115 return SkString("bezier_cubic_effects");
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000116 }
117
mtklein36352bf2015-03-25 18:17:31 -0700118 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700119 return SkISize::Make(800, 800);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000120 }
121
mtklein36352bf2015-03-25 18:17:31 -0700122 void onDraw(SkCanvas* canvas) override {
reed@google.com9c135db2014-03-12 18:28:35 +0000123 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
halcanary96fcdcc2015-08-27 07:41:13 -0700124 if (nullptr == rt) {
halcanary2a243382015-09-09 08:16:41 -0700125 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000126 return;
127 }
128 GrContext* context = rt->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700129 if (nullptr == context) {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000130 return;
131 }
132
133 struct Vertex {
134 SkPoint fPosition;
135 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
136 };
137
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000138 static const int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000139 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000140
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000141 // Mult by 3 for each edge effect type
142 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
143 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000144 SkScalar w = SkIntToScalar(rt->width()) / numCols;
145 SkScalar h = SkIntToScalar(rt->height()) / numRows;
146 int row = 0;
147 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700148 static const GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000149
150 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000151 SkPoint baseControlPts[] = {
152 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
153 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
154 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
155 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000156 };
joshualittb0a8a372014-09-23 09:50:21 -0700157 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
158 SkAutoTUnref<GrGeometryProcessor> gp;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000159 { // scope to contain GrTestTarget
160 GrTestTarget tt;
161 context->getTestTarget(&tt);
halcanary96fcdcc2015-08-27 07:41:13 -0700162 if (nullptr == tt.target()) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000163 continue;
164 }
joshualittb0a8a372014-09-23 09:50:21 -0700165 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
joshualitt88c23fc2015-05-13 14:18:07 -0700166 gp.reset(GrCubicEffect::Create(color, SkMatrix::I(), et,
joshualitt8059eb92014-12-29 15:10:07 -0800167 *tt.target()->caps()));
joshualittb0a8a372014-09-23 09:50:21 -0700168 if (!gp) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000169 continue;
170 }
171 }
172
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000173 SkScalar x = SkScalarMul(col, w);
174 SkScalar y = SkScalarMul(row, h);
175 SkPoint controlPts[] = {
176 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
177 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
178 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
179 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
180 };
181 SkPoint chopped[10];
182 SkScalar klmEqs[9];
183 SkScalar klmSigns[3];
184 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
185 chopped,
186 klmEqs,
187 klmSigns);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000188
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000189 SkPaint ctrlPtPaint;
190 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000191 for (int i = 0; i < 4; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000192 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000193 }
194
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000195 SkPaint polyPaint;
196 polyPaint.setColor(0xffA0A0A0);
197 polyPaint.setStrokeWidth(0);
198 polyPaint.setStyle(SkPaint::kStroke_Style);
199 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000200
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000201 SkPaint choppedPtPaint;
202 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000203
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000204 for (int c = 0; c < cnt; ++c) {
205 SkPoint* pts = chopped + 3 * c;
206
207 for (int i = 0; i < 4; ++i) {
208 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
209 }
210
211 SkRect bounds;
212 bounds.set(pts, 4);
213
214 SkPaint boundsPaint;
215 boundsPaint.setColor(0xff808080);
216 boundsPaint.setStrokeWidth(0);
217 boundsPaint.setStyle(SkPaint::kStroke_Style);
218 canvas->drawRect(bounds, boundsPaint);
219
joshualitt50408ad2014-11-03 12:31:14 -0800220 GrTestTarget tt;
221 context->getTestTarget(&tt);
222 SkASSERT(tt.target());
223
egdaniel8dd688b2015-01-22 10:16:09 -0800224 GrPipelineBuilder pipelineBuilder;
egdaniel8dd688b2015-01-22 10:16:09 -0800225 pipelineBuilder.setRenderTarget(rt);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000226
joshualitt95964c62015-02-11 13:45:50 -0800227 BezierCubicOrConicTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700228 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800229 geometry.fBounds = bounds;
230
bsalomonabd30f52015-08-13 13:34:48 -0700231 SkAutoTUnref<GrDrawBatch> batch(
joshualitt44701df2015-02-23 14:44:57 -0800232 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, klmSigns[c]));
joshualitt95964c62015-02-11 13:45:50 -0800233
joshualitt1c735482015-07-13 08:08:25 -0700234 tt.target()->drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000235 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000236 ++col;
237 if (numCols == col) {
238 col = 0;
239 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000240 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000241 }
242 }
243 }
244
245private:
246 typedef GM INHERITED;
247};
248
249//////////////////////////////////////////////////////////////////////////////
250
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000251/**
252 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
253 */
254class BezierConicEffects : public GM {
255public:
256 BezierConicEffects() {
257 this->setBGColor(0xFFFFFFFF);
258 }
259
260protected:
mtklein36352bf2015-03-25 18:17:31 -0700261 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000262 return SkString("bezier_conic_effects");
263 }
264
mtklein36352bf2015-03-25 18:17:31 -0700265 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700266 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000267 }
268
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000269
mtklein36352bf2015-03-25 18:17:31 -0700270 void onDraw(SkCanvas* canvas) override {
reed@google.com9c135db2014-03-12 18:28:35 +0000271 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
halcanary96fcdcc2015-08-27 07:41:13 -0700272 if (nullptr == rt) {
halcanary2a243382015-09-09 08:16:41 -0700273 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000274 return;
275 }
276 GrContext* context = rt->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700277 if (nullptr == context) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000278 return;
279 }
280
281 struct Vertex {
282 SkPoint fPosition;
283 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
284 };
285
286 static const int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000287 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000288
289 // Mult by 3 for each edge effect type
290 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
291 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
292 SkScalar w = SkIntToScalar(rt->width()) / numCols;
293 SkScalar h = SkIntToScalar(rt->height()) / numRows;
294 int row = 0;
295 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700296 static const GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000297
298 for (int i = 0; i < kNumConics; ++i) {
299 SkPoint baseControlPts[] = {
300 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
301 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
302 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
303 };
304 SkScalar weight = rand.nextRangeF(0.f, 2.f);
joshualittb0a8a372014-09-23 09:50:21 -0700305 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
306 SkAutoTUnref<GrGeometryProcessor> gp;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000307 { // scope to contain GrTestTarget
308 GrTestTarget tt;
309 context->getTestTarget(&tt);
halcanary96fcdcc2015-08-27 07:41:13 -0700310 if (nullptr == tt.target()) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000311 continue;
312 }
joshualittb0a8a372014-09-23 09:50:21 -0700313 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
joshualitt88c23fc2015-05-13 14:18:07 -0700314 gp.reset(GrConicEffect::Create(color, SkMatrix::I(), et,
joshualittb8c241a2015-05-19 08:23:30 -0700315 *tt.target()->caps(), SkMatrix::I(), false));
joshualittb0a8a372014-09-23 09:50:21 -0700316 if (!gp) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000317 continue;
318 }
319 }
320
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000321 SkScalar x = SkScalarMul(col, w);
322 SkScalar y = SkScalarMul(row, h);
323 SkPoint controlPts[] = {
324 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
325 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
326 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
327 };
328 SkConic dst[4];
329 SkScalar klmEqs[9];
330 int cnt = chop_conic(controlPts, dst, weight);
331 GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
332
333 SkPaint ctrlPtPaint;
334 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
335 for (int i = 0; i < 3; ++i) {
336 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
337 }
338
339 SkPaint polyPaint;
340 polyPaint.setColor(0xffA0A0A0);
341 polyPaint.setStrokeWidth(0);
342 polyPaint.setStyle(SkPaint::kStroke_Style);
343 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
344
345 SkPaint choppedPtPaint;
346 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
347
348 for (int c = 0; c < cnt; ++c) {
349 SkPoint* pts = dst[c].fPts;
350 for (int i = 0; i < 3; ++i) {
351 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
352 }
353
354 SkRect bounds;
355 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
356 //bounds.set(bPts, 2);
357 bounds.set(pts, 3);
358
359 SkPaint boundsPaint;
360 boundsPaint.setColor(0xff808080);
361 boundsPaint.setStrokeWidth(0);
362 boundsPaint.setStyle(SkPaint::kStroke_Style);
363 canvas->drawRect(bounds, boundsPaint);
364
joshualitt50408ad2014-11-03 12:31:14 -0800365 GrTestTarget tt;
366 context->getTestTarget(&tt);
367 SkASSERT(tt.target());
368
egdaniel8dd688b2015-01-22 10:16:09 -0800369 GrPipelineBuilder pipelineBuilder;
egdaniel8dd688b2015-01-22 10:16:09 -0800370 pipelineBuilder.setRenderTarget(rt);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000371
joshualitt95964c62015-02-11 13:45:50 -0800372 BezierCubicOrConicTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700373 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800374 geometry.fBounds = bounds;
375
bsalomonabd30f52015-08-13 13:34:48 -0700376 SkAutoTUnref<GrDrawBatch> batch(
joshualitt44701df2015-02-23 14:44:57 -0800377 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, 1.f));
joshualitt95964c62015-02-11 13:45:50 -0800378
joshualitt1c735482015-07-13 08:08:25 -0700379 tt.target()->drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000380 }
381 ++col;
382 if (numCols == col) {
383 col = 0;
384 ++row;
385 }
386 }
387 }
388 }
389
390private:
391 // Uses the max curvature function for quads to estimate
392 // where to chop the conic. If the max curvature is not
393 // found along the curve segment it will return 1 and
394 // dst[0] is the original conic. If it returns 2 the dst[0]
395 // and dst[1] are the two new conics.
396 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
397 SkScalar t = SkFindQuadMaxCurvature(src);
398 if (t == 0) {
399 if (dst) {
400 dst[0].set(src, weight);
401 }
402 return 1;
403 } else {
404 if (dst) {
405 SkConic conic;
406 conic.set(src, weight);
407 conic.chopAt(t, dst);
408 }
409 return 2;
410 }
411 }
412
413 // Calls split_conic on the entire conic and then once more on each subsection.
414 // Most cases will result in either 1 conic (chop point is not within t range)
415 // or 3 points (split once and then one subsection is split again).
416 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
417 SkConic dstTemp[2];
418 int conicCnt = split_conic(src, dstTemp, weight);
419 if (2 == conicCnt) {
420 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
421 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
422 } else {
423 dst[0] = dstTemp[0];
424 }
425 return conicCnt;
426 }
427
428 typedef GM INHERITED;
429};
430
431//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800432
433class BezierQuadTestBatch : public GrTestBatch {
434public:
435 struct Geometry : public GrTestBatch::Geometry {
436 SkRect fBounds;
437 };
438
mtklein36352bf2015-03-25 18:17:31 -0700439 const char* name() const override { return "BezierQuadTestBatch"; }
joshualitt95964c62015-02-11 13:45:50 -0800440
bsalomonabd30f52015-08-13 13:34:48 -0700441 static GrDrawBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo,
442 const GrPathUtils::QuadUVMatrix& devToUV) {
halcanary385fe4d2015-08-26 13:07:48 -0700443 return new BezierQuadTestBatch(gp, geo, devToUV);
joshualitt95964c62015-02-11 13:45:50 -0800444 }
445
446private:
447 BezierQuadTestBatch(const GrGeometryProcessor* gp, const Geometry& geo,
448 const GrPathUtils::QuadUVMatrix& devToUV)
joshualitt99c7c072015-05-01 13:43:30 -0700449 : INHERITED(gp, geo.fBounds)
joshualitt95964c62015-02-11 13:45:50 -0800450 , fGeometry(geo)
451 , fDevToUV(devToUV) {
joshualittdbe1e6f2015-07-16 08:12:45 -0700452 this->initClassID<BezierQuadTestBatch>();
joshualitt95964c62015-02-11 13:45:50 -0800453 }
454
455 struct Vertex {
456 SkPoint fPosition;
457 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
458 };
459
mtklein36352bf2015-03-25 18:17:31 -0700460 Geometry* geoData(int index) override {
joshualitt95964c62015-02-11 13:45:50 -0800461 SkASSERT(0 == index);
462 return &fGeometry;
463 }
464
joshualitt88c23fc2015-05-13 14:18:07 -0700465 const Geometry* geoData(int index) const override {
466 SkASSERT(0 == index);
467 return &fGeometry;
468 }
469
bsalomon75398562015-08-17 12:55:38 -0700470 void generateGeometry(Target* target) override {
bsalomonb5238a72015-05-05 07:49:49 -0700471 QuadHelper helper;
bsalomoned0bcad2015-05-04 10:36:42 -0700472 size_t vertexStride = this->geometryProcessor()->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700473 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700474 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700475 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800476 return;
477 }
joshualitt95964c62015-02-11 13:45:50 -0800478 verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop,
479 fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom,
480 sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800481 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
bsalomon75398562015-08-17 12:55:38 -0700482 helper.recordDraw(target);
joshualitt95964c62015-02-11 13:45:50 -0800483 }
484
485 Geometry fGeometry;
486 GrPathUtils::QuadUVMatrix fDevToUV;
487
488 static const int kVertsPerCubic = 4;
489 static const int kIndicesPerCubic = 6;
490
491 typedef GrTestBatch INHERITED;
492};
493
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000494/**
495 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
496 */
497class BezierQuadEffects : public GM {
498public:
499 BezierQuadEffects() {
500 this->setBGColor(0xFFFFFFFF);
501 }
502
503protected:
mtklein36352bf2015-03-25 18:17:31 -0700504 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000505 return SkString("bezier_quad_effects");
506 }
507
mtklein36352bf2015-03-25 18:17:31 -0700508 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700509 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000510 }
511
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000512
mtklein36352bf2015-03-25 18:17:31 -0700513 void onDraw(SkCanvas* canvas) override {
reed@google.com9c135db2014-03-12 18:28:35 +0000514 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
halcanary96fcdcc2015-08-27 07:41:13 -0700515 if (nullptr == rt) {
halcanary2a243382015-09-09 08:16:41 -0700516 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000517 return;
518 }
519 GrContext* context = rt->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700520 if (nullptr == context) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000521 return;
522 }
523
524 struct Vertex {
525 SkPoint fPosition;
526 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
527 };
528
529 static const int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000530 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000531
532 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
533 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
534 SkScalar w = SkIntToScalar(rt->width()) / numCols;
535 SkScalar h = SkIntToScalar(rt->height()) / numRows;
536 int row = 0;
537 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700538 static const GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000539
540 for (int i = 0; i < kNumQuads; ++i) {
541 SkPoint baseControlPts[] = {
542 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
543 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
544 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
545 };
joshualittb0a8a372014-09-23 09:50:21 -0700546 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
547 SkAutoTUnref<GrGeometryProcessor> gp;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000548 { // scope to contain GrTestTarget
549 GrTestTarget tt;
550 context->getTestTarget(&tt);
halcanary96fcdcc2015-08-27 07:41:13 -0700551 if (nullptr == tt.target()) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000552 continue;
553 }
joshualittb0a8a372014-09-23 09:50:21 -0700554 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
joshualitt88c23fc2015-05-13 14:18:07 -0700555 gp.reset(GrQuadEffect::Create(color, SkMatrix::I(), et,
joshualittb8c241a2015-05-19 08:23:30 -0700556 *tt.target()->caps(), SkMatrix::I(), false));
joshualittb0a8a372014-09-23 09:50:21 -0700557 if (!gp) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000558 continue;
559 }
560 }
561
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000562 SkScalar x = SkScalarMul(col, w);
563 SkScalar y = SkScalarMul(row, h);
564 SkPoint controlPts[] = {
565 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
566 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
567 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
568 };
569 SkPoint chopped[5];
570 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
571
572 SkPaint ctrlPtPaint;
573 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
574 for (int i = 0; i < 3; ++i) {
575 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
576 }
577
578 SkPaint polyPaint;
579 polyPaint.setColor(0xffA0A0A0);
580 polyPaint.setStrokeWidth(0);
581 polyPaint.setStyle(SkPaint::kStroke_Style);
582 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
583
584 SkPaint choppedPtPaint;
585 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
586
587 for (int c = 0; c < cnt; ++c) {
588 SkPoint* pts = chopped + 2 * c;
589
590 for (int i = 0; i < 3; ++i) {
591 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
592 }
593
594 SkRect bounds;
595 bounds.set(pts, 3);
596
597 SkPaint boundsPaint;
598 boundsPaint.setColor(0xff808080);
599 boundsPaint.setStrokeWidth(0);
600 boundsPaint.setStyle(SkPaint::kStroke_Style);
601 canvas->drawRect(bounds, boundsPaint);
602
joshualitt50408ad2014-11-03 12:31:14 -0800603 GrTestTarget tt;
604 context->getTestTarget(&tt);
605 SkASSERT(tt.target());
606
egdaniel8dd688b2015-01-22 10:16:09 -0800607 GrPipelineBuilder pipelineBuilder;
joshualitt94dff152015-02-11 13:03:15 -0800608 pipelineBuilder.setRenderTarget(rt);
joshualitt3f284d72015-02-11 11:34:58 -0800609
joshualitt95964c62015-02-11 13:45:50 -0800610 GrPathUtils::QuadUVMatrix DevToUV(pts);
611
612 BezierQuadTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700613 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800614 geometry.fBounds = bounds;
615
bsalomonabd30f52015-08-13 13:34:48 -0700616 SkAutoTUnref<GrDrawBatch> batch(BezierQuadTestBatch::Create(gp, geometry,
617 DevToUV));
joshualitt95964c62015-02-11 13:45:50 -0800618
joshualitt1c735482015-07-13 08:08:25 -0700619 tt.target()->drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000620 }
621 ++col;
622 if (numCols == col) {
623 col = 0;
624 ++row;
625 }
626 }
627 }
628 }
629
630private:
631 typedef GM INHERITED;
632};
633
halcanary385fe4d2015-08-26 13:07:48 -0700634DEF_GM(return new BezierCubicEffects;)
635DEF_GM(return new BezierConicEffects;)
636DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000637}
638
639#endif