blob: 5070eeaf29c639eac923b3d1388dcbf192739e98 [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
joshualitt95964c62015-02-11 13:45:50 -080015#include "GrBatchTarget.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000016#include "GrContext.h"
17#include "GrPathUtils.h"
18#include "GrTest.h"
joshualitt95964c62015-02-11 13:45:50 -080019#include "GrTestBatch.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000020#include "SkColorPriv.h"
21#include "SkDevice.h"
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000022#include "SkGeometry.h"
23
24#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:
34 struct Geometry : public GrTestBatch::Geometry {
35 SkRect fBounds;
36 };
37
mtklein36352bf2015-03-25 18:17:31 -070038 const char* name() const override { return "BezierCubicOrConicTestBatch"; }
joshualitt95964c62015-02-11 13:45:50 -080039
40 static GrBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo,
41 const SkScalar klmEqs[9], SkScalar sign) {
42 return SkNEW_ARGS(BezierCubicOrConicTestBatch, (gp, geo, klmEqs, sign));
43 }
44
45private:
46 BezierCubicOrConicTestBatch(const GrGeometryProcessor* gp, const Geometry& geo,
47 const SkScalar klmEqs[9], SkScalar sign)
joshualitt99c7c072015-05-01 13:43:30 -070048 : INHERITED(gp, geo.fBounds) {
joshualitt95964c62015-02-11 13:45:50 -080049 for (int i = 0; i < 9; i++) {
50 fKlmEqs[i] = klmEqs[i];
51 }
52
53 fGeometry = geo;
54 fSign = sign;
55 }
56
57 struct Vertex {
58 SkPoint fPosition;
59 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
60 };
61
mtklein36352bf2015-03-25 18:17:31 -070062 Geometry* geoData(int index) override {
joshualitt95964c62015-02-11 13:45:50 -080063 SkASSERT(0 == index);
64 return &fGeometry;
65 }
66
joshualitt88c23fc2015-05-13 14:18:07 -070067 const Geometry* geoData(int index) const override {
68 SkASSERT(0 == index);
69 return &fGeometry;
70 }
71
mtklein36352bf2015-03-25 18:17:31 -070072 void onGenerateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
bsalomonb5238a72015-05-05 07:49:49 -070073 QuadHelper helper;
bsalomoned0bcad2015-05-04 10:36:42 -070074 size_t vertexStride = this->geometryProcessor()->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -070075 SkASSERT(vertexStride == sizeof(Vertex));
76 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(batchTarget, vertexStride, 1));
77 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -080078 return;
79 }
80
joshualitt95964c62015-02-11 13:45:50 -080081 verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop,
82 fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom,
83 sizeof(Vertex));
84 for (int v = 0; v < 4; ++v) {
85 verts[v].fKLM[0] = eval_line(verts[v].fPosition, fKlmEqs + 0, fSign);
86 verts[v].fKLM[1] = eval_line(verts[v].fPosition, fKlmEqs + 3, fSign);
87 verts[v].fKLM[2] = eval_line(verts[v].fPosition, fKlmEqs + 6, 1.f);
88 }
bsalomone64eb572015-05-07 11:35:55 -070089 helper.issueDraw(batchTarget);
joshualitt95964c62015-02-11 13:45:50 -080090 }
91
92 Geometry fGeometry;
93 SkScalar fKlmEqs[9];
94 SkScalar fSign;
95
96 static const int kVertsPerCubic = 4;
97 static const int kIndicesPerCubic = 6;
98
99 typedef GrTestBatch INHERITED;
100};
101
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000102/**
103 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
104 */
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000105class BezierCubicEffects : public GM {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000106public:
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000107 BezierCubicEffects() {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000108 this->setBGColor(0xFFFFFFFF);
109 }
110
111protected:
mtklein36352bf2015-03-25 18:17:31 -0700112 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000113 return SkString("bezier_cubic_effects");
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000114 }
115
mtklein36352bf2015-03-25 18:17:31 -0700116 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700117 return SkISize::Make(800, 800);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000118 }
119
mtklein36352bf2015-03-25 18:17:31 -0700120 void onDraw(SkCanvas* canvas) override {
reed@google.com9c135db2014-03-12 18:28:35 +0000121 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000122 if (NULL == rt) {
bsalomonb62da802015-01-31 07:51:14 -0800123 this->drawGpuOnlyMessage(canvas);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000124 return;
125 }
126 GrContext* context = rt->getContext();
127 if (NULL == context) {
128 return;
129 }
130
131 struct Vertex {
132 SkPoint fPosition;
133 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
134 };
135
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000136 static const int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000137 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000138
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000139 // Mult by 3 for each edge effect type
140 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
141 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000142 SkScalar w = SkIntToScalar(rt->width()) / numCols;
143 SkScalar h = SkIntToScalar(rt->height()) / numRows;
144 int row = 0;
145 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700146 static const GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000147
148 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000149 SkPoint baseControlPts[] = {
150 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
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)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000154 };
joshualittb0a8a372014-09-23 09:50:21 -0700155 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
156 SkAutoTUnref<GrGeometryProcessor> gp;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000157 { // scope to contain GrTestTarget
158 GrTestTarget tt;
159 context->getTestTarget(&tt);
160 if (NULL == tt.target()) {
161 continue;
162 }
joshualittb0a8a372014-09-23 09:50:21 -0700163 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
joshualitt88c23fc2015-05-13 14:18:07 -0700164 gp.reset(GrCubicEffect::Create(color, SkMatrix::I(), et,
joshualitt8059eb92014-12-29 15:10:07 -0800165 *tt.target()->caps()));
joshualittb0a8a372014-09-23 09:50:21 -0700166 if (!gp) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000167 continue;
168 }
169 }
170
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000171 SkScalar x = SkScalarMul(col, w);
172 SkScalar y = SkScalarMul(row, h);
173 SkPoint controlPts[] = {
174 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
175 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
176 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
177 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
178 };
179 SkPoint chopped[10];
180 SkScalar klmEqs[9];
181 SkScalar klmSigns[3];
182 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
183 chopped,
184 klmEqs,
185 klmSigns);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000186
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000187 SkPaint ctrlPtPaint;
188 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000189 for (int i = 0; i < 4; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000190 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000191 }
192
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000193 SkPaint polyPaint;
194 polyPaint.setColor(0xffA0A0A0);
195 polyPaint.setStrokeWidth(0);
196 polyPaint.setStyle(SkPaint::kStroke_Style);
197 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000198
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000199 SkPaint choppedPtPaint;
200 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000201
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000202 for (int c = 0; c < cnt; ++c) {
203 SkPoint* pts = chopped + 3 * c;
204
205 for (int i = 0; i < 4; ++i) {
206 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
207 }
208
209 SkRect bounds;
210 bounds.set(pts, 4);
211
212 SkPaint boundsPaint;
213 boundsPaint.setColor(0xff808080);
214 boundsPaint.setStrokeWidth(0);
215 boundsPaint.setStyle(SkPaint::kStroke_Style);
216 canvas->drawRect(bounds, boundsPaint);
217
joshualitt50408ad2014-11-03 12:31:14 -0800218 GrTestTarget tt;
219 context->getTestTarget(&tt);
220 SkASSERT(tt.target());
221
egdaniel8dd688b2015-01-22 10:16:09 -0800222 GrPipelineBuilder pipelineBuilder;
egdaniel8dd688b2015-01-22 10:16:09 -0800223 pipelineBuilder.setRenderTarget(rt);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000224
joshualitt95964c62015-02-11 13:45:50 -0800225 BezierCubicOrConicTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700226 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800227 geometry.fBounds = bounds;
228
joshualitt44701df2015-02-23 14:44:57 -0800229 SkAutoTUnref<GrBatch> batch(
230 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, klmSigns[c]));
joshualitt95964c62015-02-11 13:45:50 -0800231
joshualitt99c7c072015-05-01 13:43:30 -0700232 tt.target()->drawBatch(&pipelineBuilder, batch);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000233 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000234 ++col;
235 if (numCols == col) {
236 col = 0;
237 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000238 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000239 }
240 }
241 }
242
243private:
244 typedef GM INHERITED;
245};
246
247//////////////////////////////////////////////////////////////////////////////
248
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000249/**
250 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
251 */
252class BezierConicEffects : public GM {
253public:
254 BezierConicEffects() {
255 this->setBGColor(0xFFFFFFFF);
256 }
257
258protected:
mtklein36352bf2015-03-25 18:17:31 -0700259 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000260 return SkString("bezier_conic_effects");
261 }
262
mtklein36352bf2015-03-25 18:17:31 -0700263 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700264 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000265 }
266
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000267
mtklein36352bf2015-03-25 18:17:31 -0700268 void onDraw(SkCanvas* canvas) override {
reed@google.com9c135db2014-03-12 18:28:35 +0000269 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000270 if (NULL == rt) {
bsalomonb62da802015-01-31 07:51:14 -0800271 this->drawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000272 return;
273 }
274 GrContext* context = rt->getContext();
275 if (NULL == context) {
276 return;
277 }
278
279 struct Vertex {
280 SkPoint fPosition;
281 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
282 };
283
284 static const int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000285 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000286
287 // Mult by 3 for each edge effect type
288 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
289 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
290 SkScalar w = SkIntToScalar(rt->width()) / numCols;
291 SkScalar h = SkIntToScalar(rt->height()) / numRows;
292 int row = 0;
293 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700294 static const GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000295
296 for (int i = 0; i < kNumConics; ++i) {
297 SkPoint baseControlPts[] = {
298 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
299 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
300 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
301 };
302 SkScalar weight = rand.nextRangeF(0.f, 2.f);
joshualittb0a8a372014-09-23 09:50:21 -0700303 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
304 SkAutoTUnref<GrGeometryProcessor> gp;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000305 { // scope to contain GrTestTarget
306 GrTestTarget tt;
307 context->getTestTarget(&tt);
308 if (NULL == tt.target()) {
309 continue;
310 }
joshualittb0a8a372014-09-23 09:50:21 -0700311 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
joshualitt88c23fc2015-05-13 14:18:07 -0700312 gp.reset(GrConicEffect::Create(color, SkMatrix::I(), et,
joshualitt8059eb92014-12-29 15:10:07 -0800313 *tt.target()->caps(), SkMatrix::I()));
joshualittb0a8a372014-09-23 09:50:21 -0700314 if (!gp) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000315 continue;
316 }
317 }
318
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000319 SkScalar x = SkScalarMul(col, w);
320 SkScalar y = SkScalarMul(row, h);
321 SkPoint controlPts[] = {
322 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
323 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
324 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
325 };
326 SkConic dst[4];
327 SkScalar klmEqs[9];
328 int cnt = chop_conic(controlPts, dst, weight);
329 GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
330
331 SkPaint ctrlPtPaint;
332 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
333 for (int i = 0; i < 3; ++i) {
334 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
335 }
336
337 SkPaint polyPaint;
338 polyPaint.setColor(0xffA0A0A0);
339 polyPaint.setStrokeWidth(0);
340 polyPaint.setStyle(SkPaint::kStroke_Style);
341 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
342
343 SkPaint choppedPtPaint;
344 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
345
346 for (int c = 0; c < cnt; ++c) {
347 SkPoint* pts = dst[c].fPts;
348 for (int i = 0; i < 3; ++i) {
349 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
350 }
351
352 SkRect bounds;
353 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
354 //bounds.set(bPts, 2);
355 bounds.set(pts, 3);
356
357 SkPaint boundsPaint;
358 boundsPaint.setColor(0xff808080);
359 boundsPaint.setStrokeWidth(0);
360 boundsPaint.setStyle(SkPaint::kStroke_Style);
361 canvas->drawRect(bounds, boundsPaint);
362
joshualitt50408ad2014-11-03 12:31:14 -0800363 GrTestTarget tt;
364 context->getTestTarget(&tt);
365 SkASSERT(tt.target());
366
egdaniel8dd688b2015-01-22 10:16:09 -0800367 GrPipelineBuilder pipelineBuilder;
egdaniel8dd688b2015-01-22 10:16:09 -0800368 pipelineBuilder.setRenderTarget(rt);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000369
joshualitt95964c62015-02-11 13:45:50 -0800370 BezierCubicOrConicTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700371 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800372 geometry.fBounds = bounds;
373
joshualitt44701df2015-02-23 14:44:57 -0800374 SkAutoTUnref<GrBatch> batch(
375 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, 1.f));
joshualitt95964c62015-02-11 13:45:50 -0800376
joshualitt99c7c072015-05-01 13:43:30 -0700377 tt.target()->drawBatch(&pipelineBuilder, batch);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000378 }
379 ++col;
380 if (numCols == col) {
381 col = 0;
382 ++row;
383 }
384 }
385 }
386 }
387
388private:
389 // Uses the max curvature function for quads to estimate
390 // where to chop the conic. If the max curvature is not
391 // found along the curve segment it will return 1 and
392 // dst[0] is the original conic. If it returns 2 the dst[0]
393 // and dst[1] are the two new conics.
394 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
395 SkScalar t = SkFindQuadMaxCurvature(src);
396 if (t == 0) {
397 if (dst) {
398 dst[0].set(src, weight);
399 }
400 return 1;
401 } else {
402 if (dst) {
403 SkConic conic;
404 conic.set(src, weight);
405 conic.chopAt(t, dst);
406 }
407 return 2;
408 }
409 }
410
411 // Calls split_conic on the entire conic and then once more on each subsection.
412 // Most cases will result in either 1 conic (chop point is not within t range)
413 // or 3 points (split once and then one subsection is split again).
414 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
415 SkConic dstTemp[2];
416 int conicCnt = split_conic(src, dstTemp, weight);
417 if (2 == conicCnt) {
418 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
419 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
420 } else {
421 dst[0] = dstTemp[0];
422 }
423 return conicCnt;
424 }
425
426 typedef GM INHERITED;
427};
428
429//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800430
431class BezierQuadTestBatch : public GrTestBatch {
432public:
433 struct Geometry : public GrTestBatch::Geometry {
434 SkRect fBounds;
435 };
436
mtklein36352bf2015-03-25 18:17:31 -0700437 const char* name() const override { return "BezierQuadTestBatch"; }
joshualitt95964c62015-02-11 13:45:50 -0800438
439 static GrBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo,
440 const GrPathUtils::QuadUVMatrix& devToUV) {
441 return SkNEW_ARGS(BezierQuadTestBatch, (gp, geo, devToUV));
442 }
443
444private:
445 BezierQuadTestBatch(const GrGeometryProcessor* gp, const Geometry& geo,
446 const GrPathUtils::QuadUVMatrix& devToUV)
joshualitt99c7c072015-05-01 13:43:30 -0700447 : INHERITED(gp, geo.fBounds)
joshualitt95964c62015-02-11 13:45:50 -0800448 , fGeometry(geo)
449 , fDevToUV(devToUV) {
450 }
451
452 struct Vertex {
453 SkPoint fPosition;
454 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
455 };
456
mtklein36352bf2015-03-25 18:17:31 -0700457 Geometry* geoData(int index) override {
joshualitt95964c62015-02-11 13:45:50 -0800458 SkASSERT(0 == index);
459 return &fGeometry;
460 }
461
joshualitt88c23fc2015-05-13 14:18:07 -0700462 const Geometry* geoData(int index) const override {
463 SkASSERT(0 == index);
464 return &fGeometry;
465 }
466
mtklein36352bf2015-03-25 18:17:31 -0700467 void onGenerateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
bsalomonb5238a72015-05-05 07:49:49 -0700468 QuadHelper helper;
bsalomoned0bcad2015-05-04 10:36:42 -0700469 size_t vertexStride = this->geometryProcessor()->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700470 SkASSERT(vertexStride == sizeof(Vertex));
bsalomonb5238a72015-05-05 07:49:49 -0700471 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(batchTarget, vertexStride, 1));
472 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800473 return;
474 }
joshualitt95964c62015-02-11 13:45:50 -0800475 verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop,
476 fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom,
477 sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800478 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
bsalomone64eb572015-05-07 11:35:55 -0700479 helper.issueDraw(batchTarget);
joshualitt95964c62015-02-11 13:45:50 -0800480 }
481
482 Geometry fGeometry;
483 GrPathUtils::QuadUVMatrix fDevToUV;
484
485 static const int kVertsPerCubic = 4;
486 static const int kIndicesPerCubic = 6;
487
488 typedef GrTestBatch INHERITED;
489};
490
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000491/**
492 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
493 */
494class BezierQuadEffects : public GM {
495public:
496 BezierQuadEffects() {
497 this->setBGColor(0xFFFFFFFF);
498 }
499
500protected:
mtklein36352bf2015-03-25 18:17:31 -0700501 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000502 return SkString("bezier_quad_effects");
503 }
504
mtklein36352bf2015-03-25 18:17:31 -0700505 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700506 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000507 }
508
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000509
mtklein36352bf2015-03-25 18:17:31 -0700510 void onDraw(SkCanvas* canvas) override {
reed@google.com9c135db2014-03-12 18:28:35 +0000511 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000512 if (NULL == rt) {
bsalomonb62da802015-01-31 07:51:14 -0800513 this->drawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000514 return;
515 }
516 GrContext* context = rt->getContext();
517 if (NULL == context) {
518 return;
519 }
520
521 struct Vertex {
522 SkPoint fPosition;
523 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
524 };
525
526 static const int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000527 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000528
529 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
530 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
531 SkScalar w = SkIntToScalar(rt->width()) / numCols;
532 SkScalar h = SkIntToScalar(rt->height()) / numRows;
533 int row = 0;
534 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700535 static const GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000536
537 for (int i = 0; i < kNumQuads; ++i) {
538 SkPoint baseControlPts[] = {
539 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
540 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
541 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
542 };
joshualittb0a8a372014-09-23 09:50:21 -0700543 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
544 SkAutoTUnref<GrGeometryProcessor> gp;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000545 { // scope to contain GrTestTarget
546 GrTestTarget tt;
547 context->getTestTarget(&tt);
548 if (NULL == tt.target()) {
549 continue;
550 }
joshualittb0a8a372014-09-23 09:50:21 -0700551 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
joshualitt88c23fc2015-05-13 14:18:07 -0700552 gp.reset(GrQuadEffect::Create(color, SkMatrix::I(), et,
joshualitt8059eb92014-12-29 15:10:07 -0800553 *tt.target()->caps(), SkMatrix::I()));
joshualittb0a8a372014-09-23 09:50:21 -0700554 if (!gp) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000555 continue;
556 }
557 }
558
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000559 SkScalar x = SkScalarMul(col, w);
560 SkScalar y = SkScalarMul(row, h);
561 SkPoint controlPts[] = {
562 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
563 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
564 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
565 };
566 SkPoint chopped[5];
567 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
568
569 SkPaint ctrlPtPaint;
570 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
571 for (int i = 0; i < 3; ++i) {
572 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
573 }
574
575 SkPaint polyPaint;
576 polyPaint.setColor(0xffA0A0A0);
577 polyPaint.setStrokeWidth(0);
578 polyPaint.setStyle(SkPaint::kStroke_Style);
579 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
580
581 SkPaint choppedPtPaint;
582 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
583
584 for (int c = 0; c < cnt; ++c) {
585 SkPoint* pts = chopped + 2 * c;
586
587 for (int i = 0; i < 3; ++i) {
588 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
589 }
590
591 SkRect bounds;
592 bounds.set(pts, 3);
593
594 SkPaint boundsPaint;
595 boundsPaint.setColor(0xff808080);
596 boundsPaint.setStrokeWidth(0);
597 boundsPaint.setStyle(SkPaint::kStroke_Style);
598 canvas->drawRect(bounds, boundsPaint);
599
joshualitt50408ad2014-11-03 12:31:14 -0800600 GrTestTarget tt;
601 context->getTestTarget(&tt);
602 SkASSERT(tt.target());
603
egdaniel8dd688b2015-01-22 10:16:09 -0800604 GrPipelineBuilder pipelineBuilder;
joshualitt94dff152015-02-11 13:03:15 -0800605 pipelineBuilder.setRenderTarget(rt);
joshualitt3f284d72015-02-11 11:34:58 -0800606
joshualitt95964c62015-02-11 13:45:50 -0800607 GrPathUtils::QuadUVMatrix DevToUV(pts);
608
609 BezierQuadTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700610 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800611 geometry.fBounds = bounds;
612
613 SkAutoTUnref<GrBatch> batch(BezierQuadTestBatch::Create(gp, geometry, DevToUV));
614
joshualitt99c7c072015-05-01 13:43:30 -0700615 tt.target()->drawBatch(&pipelineBuilder, batch);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000616 }
617 ++col;
618 if (numCols == col) {
619 col = 0;
620 ++row;
621 }
622 }
623 }
624 }
625
626private:
627 typedef GM INHERITED;
628};
629
630DEF_GM( return SkNEW(BezierCubicEffects); )
631DEF_GM( return SkNEW(BezierConicEffects); )
632DEF_GM( return SkNEW(BezierQuadEffects); )
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000633
634}
635
636#endif