blob: 5167b770134b6023ea5dbd851a9ddc37a20f2364 [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
15#include "GrContext.h"
16#include "GrPathUtils.h"
17#include "GrTest.h"
18#include "SkColorPriv.h"
19#include "SkDevice.h"
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000020#include "SkGeometry.h"
21
joshualitt2771b562015-08-07 12:46:26 -070022#include "batches/GrTestBatch.h"
23
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000024#include "effects/GrBezierEffect.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000025
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000026static inline SkScalar eval_line(const SkPoint& p, const SkScalar lineEq[3], SkScalar sign) {
27 return sign * (lineEq[0] * p.fX + lineEq[1] * p.fY + lineEq[2]);
28}
29
30namespace skiagm {
joshualitt95964c62015-02-11 13:45:50 -080031
32class BezierCubicOrConicTestBatch : public GrTestBatch {
33public:
reed1b55a962015-09-17 20:16:13 -070034 DEFINE_BATCH_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -080035 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)
reed1b55a962015-09-17 20:16:13 -070049 : INHERITED(ClassID(), gp, geo.fBounds) {
joshualitt95964c62015-02-11 13:45:50 -080050 for (int i = 0; i < 9; i++) {
51 fKlmEqs[i] = klmEqs[i];
52 }
53
54 fGeometry = geo;
55 fSign = sign;
56 }
57
58 struct Vertex {
59 SkPoint fPosition;
60 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
61 };
62
mtklein36352bf2015-03-25 18:17:31 -070063 Geometry* geoData(int index) override {
joshualitt95964c62015-02-11 13:45:50 -080064 SkASSERT(0 == index);
65 return &fGeometry;
66 }
67
joshualitt88c23fc2015-05-13 14:18:07 -070068 const Geometry* geoData(int index) const override {
69 SkASSERT(0 == index);
70 return &fGeometry;
71 }
72
joshualitt144c3c82015-11-30 12:30:13 -080073 void generateGeometry(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -070074 QuadHelper helper;
bsalomoned0bcad2015-05-04 10:36:42 -070075 size_t vertexStride = this->geometryProcessor()->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -070076 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -070077 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -070078 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -080079 return;
80 }
81
joshualitt95964c62015-02-11 13:45:50 -080082 verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop,
83 fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom,
84 sizeof(Vertex));
85 for (int v = 0; v < 4; ++v) {
86 verts[v].fKLM[0] = eval_line(verts[v].fPosition, fKlmEqs + 0, fSign);
87 verts[v].fKLM[1] = eval_line(verts[v].fPosition, fKlmEqs + 3, fSign);
88 verts[v].fKLM[2] = eval_line(verts[v].fPosition, fKlmEqs + 6, 1.f);
89 }
bsalomon75398562015-08-17 12:55:38 -070090 helper.recordDraw(target);
joshualitt95964c62015-02-11 13:45:50 -080091 }
92
93 Geometry fGeometry;
94 SkScalar fKlmEqs[9];
95 SkScalar fSign;
96
97 static const int kVertsPerCubic = 4;
98 static const int kIndicesPerCubic = 6;
99
100 typedef GrTestBatch INHERITED;
101};
102
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000103/**
104 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
105 */
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000106class BezierCubicEffects : public GM {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000107public:
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000108 BezierCubicEffects() {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000109 this->setBGColor(0xFFFFFFFF);
110 }
111
112protected:
mtklein36352bf2015-03-25 18:17:31 -0700113 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000114 return SkString("bezier_cubic_effects");
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000115 }
116
mtklein36352bf2015-03-25 18:17:31 -0700117 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700118 return SkISize::Make(800, 800);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000119 }
120
mtklein36352bf2015-03-25 18:17:31 -0700121 void onDraw(SkCanvas* canvas) override {
reed@google.com9c135db2014-03-12 18:28:35 +0000122 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
halcanary96fcdcc2015-08-27 07:41:13 -0700123 if (nullptr == rt) {
halcanary2a243382015-09-09 08:16:41 -0700124 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000125 return;
126 }
127 GrContext* context = rt->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700128 if (nullptr == context) {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000129 return;
130 }
131
132 struct Vertex {
133 SkPoint fPosition;
134 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
135 };
136
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000137 static const int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000138 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000139
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000140 // Mult by 3 for each edge effect type
141 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
142 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000143 SkScalar w = SkIntToScalar(rt->width()) / numCols;
144 SkScalar h = SkIntToScalar(rt->height()) / numRows;
145 int row = 0;
146 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700147 static const GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000148
149 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000150 SkPoint baseControlPts[] = {
151 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
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)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000155 };
joshualittb0a8a372014-09-23 09:50:21 -0700156 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
157 SkAutoTUnref<GrGeometryProcessor> gp;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000158 { // scope to contain GrTestTarget
159 GrTestTarget tt;
robertphillips504ce5d2015-11-16 11:02:05 -0800160 context->getTestTarget(&tt, rt);
halcanary96fcdcc2015-08-27 07:41:13 -0700161 if (nullptr == tt.target()) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000162 continue;
163 }
joshualittb0a8a372014-09-23 09:50:21 -0700164 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
joshualitt88c23fc2015-05-13 14:18:07 -0700165 gp.reset(GrCubicEffect::Create(color, SkMatrix::I(), et,
joshualitt8059eb92014-12-29 15:10:07 -0800166 *tt.target()->caps()));
joshualittb0a8a372014-09-23 09:50:21 -0700167 if (!gp) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000168 continue;
169 }
170 }
171
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000172 SkScalar x = SkScalarMul(col, w);
173 SkScalar y = SkScalarMul(row, h);
174 SkPoint controlPts[] = {
175 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
176 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
177 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
178 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
179 };
180 SkPoint chopped[10];
181 SkScalar klmEqs[9];
182 SkScalar klmSigns[3];
183 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
184 chopped,
185 klmEqs,
186 klmSigns);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000187
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000188 SkPaint ctrlPtPaint;
189 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000190 for (int i = 0; i < 4; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000191 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000192 }
193
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000194 SkPaint polyPaint;
195 polyPaint.setColor(0xffA0A0A0);
196 polyPaint.setStrokeWidth(0);
197 polyPaint.setStyle(SkPaint::kStroke_Style);
198 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000199
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000200 SkPaint choppedPtPaint;
201 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000202
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000203 for (int c = 0; c < cnt; ++c) {
204 SkPoint* pts = chopped + 3 * c;
205
206 for (int i = 0; i < 4; ++i) {
207 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
208 }
209
210 SkRect bounds;
211 bounds.set(pts, 4);
212
213 SkPaint boundsPaint;
214 boundsPaint.setColor(0xff808080);
215 boundsPaint.setStrokeWidth(0);
216 boundsPaint.setStyle(SkPaint::kStroke_Style);
217 canvas->drawRect(bounds, boundsPaint);
218
joshualitt50408ad2014-11-03 12:31:14 -0800219 GrTestTarget tt;
robertphillips504ce5d2015-11-16 11:02:05 -0800220 context->getTestTarget(&tt, rt);
joshualitt50408ad2014-11-03 12:31:14 -0800221 SkASSERT(tt.target());
222
egdaniel8dd688b2015-01-22 10:16:09 -0800223 GrPipelineBuilder pipelineBuilder;
egdanielc4b72722015-11-23 13:20:41 -0800224 pipelineBuilder.setXPFactory(
225 GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
egdaniel8dd688b2015-01-22 10:16:09 -0800226 pipelineBuilder.setRenderTarget(rt);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000227
joshualitt95964c62015-02-11 13:45:50 -0800228 BezierCubicOrConicTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700229 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800230 geometry.fBounds = bounds;
231
bsalomonabd30f52015-08-13 13:34:48 -0700232 SkAutoTUnref<GrDrawBatch> batch(
joshualitt44701df2015-02-23 14:44:57 -0800233 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, klmSigns[c]));
joshualitt95964c62015-02-11 13:45:50 -0800234
joshualitt1c735482015-07-13 08:08:25 -0700235 tt.target()->drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000236 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000237 ++col;
238 if (numCols == col) {
239 col = 0;
240 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000241 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000242 }
243 }
244 }
245
246private:
247 typedef GM INHERITED;
248};
249
250//////////////////////////////////////////////////////////////////////////////
251
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000252/**
253 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
254 */
255class BezierConicEffects : public GM {
256public:
257 BezierConicEffects() {
258 this->setBGColor(0xFFFFFFFF);
259 }
260
261protected:
mtklein36352bf2015-03-25 18:17:31 -0700262 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000263 return SkString("bezier_conic_effects");
264 }
265
mtklein36352bf2015-03-25 18:17:31 -0700266 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700267 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000268 }
269
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000270
mtklein36352bf2015-03-25 18:17:31 -0700271 void onDraw(SkCanvas* canvas) override {
reed@google.com9c135db2014-03-12 18:28:35 +0000272 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
halcanary96fcdcc2015-08-27 07:41:13 -0700273 if (nullptr == rt) {
halcanary2a243382015-09-09 08:16:41 -0700274 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000275 return;
276 }
277 GrContext* context = rt->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700278 if (nullptr == context) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000279 return;
280 }
281
282 struct Vertex {
283 SkPoint fPosition;
284 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
285 };
286
287 static const int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000288 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000289
290 // Mult by 3 for each edge effect type
291 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
292 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
293 SkScalar w = SkIntToScalar(rt->width()) / numCols;
294 SkScalar h = SkIntToScalar(rt->height()) / numRows;
295 int row = 0;
296 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700297 static const GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000298
299 for (int i = 0; i < kNumConics; ++i) {
300 SkPoint baseControlPts[] = {
301 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
302 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
303 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
304 };
305 SkScalar weight = rand.nextRangeF(0.f, 2.f);
joshualittb0a8a372014-09-23 09:50:21 -0700306 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
307 SkAutoTUnref<GrGeometryProcessor> gp;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000308 { // scope to contain GrTestTarget
309 GrTestTarget tt;
robertphillips504ce5d2015-11-16 11:02:05 -0800310 context->getTestTarget(&tt, rt);
halcanary96fcdcc2015-08-27 07:41:13 -0700311 if (nullptr == tt.target()) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000312 continue;
313 }
joshualittb0a8a372014-09-23 09:50:21 -0700314 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
joshualitt88c23fc2015-05-13 14:18:07 -0700315 gp.reset(GrConicEffect::Create(color, SkMatrix::I(), et,
joshualittb8c241a2015-05-19 08:23:30 -0700316 *tt.target()->caps(), SkMatrix::I(), false));
joshualittb0a8a372014-09-23 09:50:21 -0700317 if (!gp) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000318 continue;
319 }
320 }
321
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000322 SkScalar x = SkScalarMul(col, w);
323 SkScalar y = SkScalarMul(row, h);
324 SkPoint controlPts[] = {
325 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
326 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
327 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
328 };
329 SkConic dst[4];
330 SkScalar klmEqs[9];
331 int cnt = chop_conic(controlPts, dst, weight);
332 GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
333
334 SkPaint ctrlPtPaint;
335 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
336 for (int i = 0; i < 3; ++i) {
337 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
338 }
339
340 SkPaint polyPaint;
341 polyPaint.setColor(0xffA0A0A0);
342 polyPaint.setStrokeWidth(0);
343 polyPaint.setStyle(SkPaint::kStroke_Style);
344 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
345
346 SkPaint choppedPtPaint;
347 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
348
349 for (int c = 0; c < cnt; ++c) {
350 SkPoint* pts = dst[c].fPts;
351 for (int i = 0; i < 3; ++i) {
352 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
353 }
354
355 SkRect bounds;
356 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
357 //bounds.set(bPts, 2);
358 bounds.set(pts, 3);
359
360 SkPaint boundsPaint;
361 boundsPaint.setColor(0xff808080);
362 boundsPaint.setStrokeWidth(0);
363 boundsPaint.setStyle(SkPaint::kStroke_Style);
364 canvas->drawRect(bounds, boundsPaint);
365
joshualitt50408ad2014-11-03 12:31:14 -0800366 GrTestTarget tt;
robertphillips504ce5d2015-11-16 11:02:05 -0800367 context->getTestTarget(&tt, rt);
joshualitt50408ad2014-11-03 12:31:14 -0800368 SkASSERT(tt.target());
369
egdaniel8dd688b2015-01-22 10:16:09 -0800370 GrPipelineBuilder pipelineBuilder;
egdanielc4b72722015-11-23 13:20:41 -0800371 pipelineBuilder.setXPFactory(
372 GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
egdaniel8dd688b2015-01-22 10:16:09 -0800373 pipelineBuilder.setRenderTarget(rt);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000374
joshualitt95964c62015-02-11 13:45:50 -0800375 BezierCubicOrConicTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700376 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800377 geometry.fBounds = bounds;
378
bsalomonabd30f52015-08-13 13:34:48 -0700379 SkAutoTUnref<GrDrawBatch> batch(
joshualitt44701df2015-02-23 14:44:57 -0800380 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, 1.f));
joshualitt95964c62015-02-11 13:45:50 -0800381
joshualitt1c735482015-07-13 08:08:25 -0700382 tt.target()->drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000383 }
384 ++col;
385 if (numCols == col) {
386 col = 0;
387 ++row;
388 }
389 }
390 }
391 }
392
393private:
394 // Uses the max curvature function for quads to estimate
395 // where to chop the conic. If the max curvature is not
396 // found along the curve segment it will return 1 and
397 // dst[0] is the original conic. If it returns 2 the dst[0]
398 // and dst[1] are the two new conics.
399 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
400 SkScalar t = SkFindQuadMaxCurvature(src);
401 if (t == 0) {
402 if (dst) {
403 dst[0].set(src, weight);
404 }
405 return 1;
406 } else {
407 if (dst) {
408 SkConic conic;
409 conic.set(src, weight);
410 conic.chopAt(t, dst);
411 }
412 return 2;
413 }
414 }
415
416 // Calls split_conic on the entire conic and then once more on each subsection.
417 // Most cases will result in either 1 conic (chop point is not within t range)
418 // or 3 points (split once and then one subsection is split again).
419 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
420 SkConic dstTemp[2];
421 int conicCnt = split_conic(src, dstTemp, weight);
422 if (2 == conicCnt) {
423 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
424 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
425 } else {
426 dst[0] = dstTemp[0];
427 }
428 return conicCnt;
429 }
430
431 typedef GM INHERITED;
432};
433
434//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800435
436class BezierQuadTestBatch : public GrTestBatch {
437public:
reed1b55a962015-09-17 20:16:13 -0700438 DEFINE_BATCH_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -0800439 struct Geometry : public GrTestBatch::Geometry {
440 SkRect fBounds;
441 };
442
mtklein36352bf2015-03-25 18:17:31 -0700443 const char* name() const override { return "BezierQuadTestBatch"; }
joshualitt95964c62015-02-11 13:45:50 -0800444
bsalomonabd30f52015-08-13 13:34:48 -0700445 static GrDrawBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo,
446 const GrPathUtils::QuadUVMatrix& devToUV) {
halcanary385fe4d2015-08-26 13:07:48 -0700447 return new BezierQuadTestBatch(gp, geo, devToUV);
joshualitt95964c62015-02-11 13:45:50 -0800448 }
449
450private:
451 BezierQuadTestBatch(const GrGeometryProcessor* gp, const Geometry& geo,
452 const GrPathUtils::QuadUVMatrix& devToUV)
reed1b55a962015-09-17 20:16:13 -0700453 : INHERITED(ClassID(), gp, geo.fBounds)
joshualitt95964c62015-02-11 13:45:50 -0800454 , fGeometry(geo)
455 , fDevToUV(devToUV) {
456 }
457
458 struct Vertex {
459 SkPoint fPosition;
460 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
461 };
462
mtklein36352bf2015-03-25 18:17:31 -0700463 Geometry* geoData(int index) override {
joshualitt95964c62015-02-11 13:45:50 -0800464 SkASSERT(0 == index);
465 return &fGeometry;
466 }
467
joshualitt88c23fc2015-05-13 14:18:07 -0700468 const Geometry* geoData(int index) const override {
469 SkASSERT(0 == index);
470 return &fGeometry;
471 }
472
joshualitt144c3c82015-11-30 12:30:13 -0800473 void generateGeometry(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -0700474 QuadHelper helper;
bsalomoned0bcad2015-05-04 10:36:42 -0700475 size_t vertexStride = this->geometryProcessor()->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700476 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700477 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700478 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800479 return;
480 }
joshualitt95964c62015-02-11 13:45:50 -0800481 verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop,
482 fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom,
483 sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800484 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
bsalomon75398562015-08-17 12:55:38 -0700485 helper.recordDraw(target);
joshualitt95964c62015-02-11 13:45:50 -0800486 }
487
488 Geometry fGeometry;
489 GrPathUtils::QuadUVMatrix fDevToUV;
490
491 static const int kVertsPerCubic = 4;
492 static const int kIndicesPerCubic = 6;
493
494 typedef GrTestBatch INHERITED;
495};
496
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000497/**
498 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
499 */
500class BezierQuadEffects : public GM {
501public:
502 BezierQuadEffects() {
503 this->setBGColor(0xFFFFFFFF);
504 }
505
506protected:
mtklein36352bf2015-03-25 18:17:31 -0700507 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000508 return SkString("bezier_quad_effects");
509 }
510
mtklein36352bf2015-03-25 18:17:31 -0700511 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700512 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000513 }
514
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000515
mtklein36352bf2015-03-25 18:17:31 -0700516 void onDraw(SkCanvas* canvas) override {
reed@google.com9c135db2014-03-12 18:28:35 +0000517 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
halcanary96fcdcc2015-08-27 07:41:13 -0700518 if (nullptr == rt) {
halcanary2a243382015-09-09 08:16:41 -0700519 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000520 return;
521 }
522 GrContext* context = rt->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700523 if (nullptr == context) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000524 return;
525 }
526
527 struct Vertex {
528 SkPoint fPosition;
529 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
530 };
531
532 static const int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000533 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000534
535 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
536 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
537 SkScalar w = SkIntToScalar(rt->width()) / numCols;
538 SkScalar h = SkIntToScalar(rt->height()) / numRows;
539 int row = 0;
540 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700541 static const GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000542
543 for (int i = 0; i < kNumQuads; ++i) {
544 SkPoint baseControlPts[] = {
545 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
546 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
547 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
548 };
joshualittb0a8a372014-09-23 09:50:21 -0700549 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
550 SkAutoTUnref<GrGeometryProcessor> gp;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000551 { // scope to contain GrTestTarget
552 GrTestTarget tt;
robertphillips504ce5d2015-11-16 11:02:05 -0800553 context->getTestTarget(&tt, rt);
halcanary96fcdcc2015-08-27 07:41:13 -0700554 if (nullptr == tt.target()) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000555 continue;
556 }
joshualittb0a8a372014-09-23 09:50:21 -0700557 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
joshualitt88c23fc2015-05-13 14:18:07 -0700558 gp.reset(GrQuadEffect::Create(color, SkMatrix::I(), et,
joshualittb8c241a2015-05-19 08:23:30 -0700559 *tt.target()->caps(), SkMatrix::I(), false));
joshualittb0a8a372014-09-23 09:50:21 -0700560 if (!gp) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000561 continue;
562 }
563 }
564
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000565 SkScalar x = SkScalarMul(col, w);
566 SkScalar y = SkScalarMul(row, h);
567 SkPoint controlPts[] = {
568 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
569 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
570 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
571 };
572 SkPoint chopped[5];
573 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
574
575 SkPaint ctrlPtPaint;
576 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
577 for (int i = 0; i < 3; ++i) {
578 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
579 }
580
581 SkPaint polyPaint;
582 polyPaint.setColor(0xffA0A0A0);
583 polyPaint.setStrokeWidth(0);
584 polyPaint.setStyle(SkPaint::kStroke_Style);
585 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
586
587 SkPaint choppedPtPaint;
588 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
589
590 for (int c = 0; c < cnt; ++c) {
591 SkPoint* pts = chopped + 2 * c;
592
593 for (int i = 0; i < 3; ++i) {
594 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
595 }
596
597 SkRect bounds;
598 bounds.set(pts, 3);
599
600 SkPaint boundsPaint;
601 boundsPaint.setColor(0xff808080);
602 boundsPaint.setStrokeWidth(0);
603 boundsPaint.setStyle(SkPaint::kStroke_Style);
604 canvas->drawRect(bounds, boundsPaint);
605
joshualitt50408ad2014-11-03 12:31:14 -0800606 GrTestTarget tt;
robertphillips504ce5d2015-11-16 11:02:05 -0800607 context->getTestTarget(&tt, rt);
joshualitt50408ad2014-11-03 12:31:14 -0800608 SkASSERT(tt.target());
609
egdaniel8dd688b2015-01-22 10:16:09 -0800610 GrPipelineBuilder pipelineBuilder;
egdanielc4b72722015-11-23 13:20:41 -0800611 pipelineBuilder.setXPFactory(
612 GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
joshualitt94dff152015-02-11 13:03:15 -0800613 pipelineBuilder.setRenderTarget(rt);
joshualitt3f284d72015-02-11 11:34:58 -0800614
joshualitt95964c62015-02-11 13:45:50 -0800615 GrPathUtils::QuadUVMatrix DevToUV(pts);
616
617 BezierQuadTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700618 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800619 geometry.fBounds = bounds;
620
bsalomonabd30f52015-08-13 13:34:48 -0700621 SkAutoTUnref<GrDrawBatch> batch(BezierQuadTestBatch::Create(gp, geometry,
622 DevToUV));
joshualitt95964c62015-02-11 13:45:50 -0800623
joshualitt1c735482015-07-13 08:08:25 -0700624 tt.target()->drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000625 }
626 ++col;
627 if (numCols == col) {
628 col = 0;
629 ++row;
630 }
631 }
632 }
633 }
634
635private:
636 typedef GM INHERITED;
637};
638
halcanary385fe4d2015-08-26 13:07:48 -0700639DEF_GM(return new BezierCubicEffects;)
640DEF_GM(return new BezierConicEffects;)
641DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000642}
643
644#endif