blob: f609ba8aef37cc38f8d602a5df8e01e832ef33b6 [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
robertphillips391395d2016-03-02 09:26:36 -080014#include "GrDrawContextPriv.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"
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
joshualittf5883a62016-01-13 07:47:38 -0800132 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(rt));
133 if (!drawContext) {
134 return;
135 }
136
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000137 struct Vertex {
138 SkPoint fPosition;
139 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
140 };
141
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000142 static const int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000143 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000144
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000145 // Mult by 3 for each edge effect type
146 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
147 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000148 SkScalar w = SkIntToScalar(rt->width()) / numCols;
149 SkScalar h = SkIntToScalar(rt->height()) / numRows;
150 int row = 0;
151 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700152 static const GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000153
154 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000155 SkPoint baseControlPts[] = {
156 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
157 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
158 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
159 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000160 };
joshualittb0a8a372014-09-23 09:50:21 -0700161 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
162 SkAutoTUnref<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800163 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
164 gp.reset(GrCubicEffect::Create(color, SkMatrix::I(), et,
165 *context->caps()));
166 if (!gp) {
167 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000168 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000169 SkScalar x = SkScalarMul(col, w);
170 SkScalar y = SkScalarMul(row, h);
171 SkPoint controlPts[] = {
172 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
173 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
174 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
175 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
176 };
177 SkPoint chopped[10];
178 SkScalar klmEqs[9];
179 SkScalar klmSigns[3];
180 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
181 chopped,
182 klmEqs,
183 klmSigns);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000184
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000185 SkPaint ctrlPtPaint;
186 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000187 for (int i = 0; i < 4; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000188 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000189 }
190
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000191 SkPaint polyPaint;
192 polyPaint.setColor(0xffA0A0A0);
193 polyPaint.setStrokeWidth(0);
194 polyPaint.setStyle(SkPaint::kStroke_Style);
195 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000196
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000197 SkPaint choppedPtPaint;
198 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000199
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000200 for (int c = 0; c < cnt; ++c) {
201 SkPoint* pts = chopped + 3 * c;
202
203 for (int i = 0; i < 4; ++i) {
204 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
205 }
206
207 SkRect bounds;
208 bounds.set(pts, 4);
209
210 SkPaint boundsPaint;
211 boundsPaint.setColor(0xff808080);
212 boundsPaint.setStrokeWidth(0);
213 boundsPaint.setStyle(SkPaint::kStroke_Style);
214 canvas->drawRect(bounds, boundsPaint);
215
egdaniel8dd688b2015-01-22 10:16:09 -0800216 GrPipelineBuilder pipelineBuilder;
egdanielc4b72722015-11-23 13:20:41 -0800217 pipelineBuilder.setXPFactory(
218 GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
egdaniel8dd688b2015-01-22 10:16:09 -0800219 pipelineBuilder.setRenderTarget(rt);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000220
joshualitt95964c62015-02-11 13:45:50 -0800221 BezierCubicOrConicTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700222 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800223 geometry.fBounds = bounds;
224
bsalomonabd30f52015-08-13 13:34:48 -0700225 SkAutoTUnref<GrDrawBatch> batch(
joshualitt44701df2015-02-23 14:44:57 -0800226 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, klmSigns[c]));
joshualitt95964c62015-02-11 13:45:50 -0800227
robertphillips391395d2016-03-02 09:26:36 -0800228 drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000229 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000230 ++col;
231 if (numCols == col) {
232 col = 0;
233 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000234 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000235 }
236 }
237 }
238
239private:
240 typedef GM INHERITED;
241};
242
243//////////////////////////////////////////////////////////////////////////////
244
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000245/**
246 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
247 */
248class BezierConicEffects : public GM {
249public:
250 BezierConicEffects() {
251 this->setBGColor(0xFFFFFFFF);
252 }
253
254protected:
mtklein36352bf2015-03-25 18:17:31 -0700255 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000256 return SkString("bezier_conic_effects");
257 }
258
mtklein36352bf2015-03-25 18:17:31 -0700259 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700260 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000261 }
262
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000263
mtklein36352bf2015-03-25 18:17:31 -0700264 void onDraw(SkCanvas* canvas) override {
reed@google.com9c135db2014-03-12 18:28:35 +0000265 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
halcanary96fcdcc2015-08-27 07:41:13 -0700266 if (nullptr == rt) {
halcanary2a243382015-09-09 08:16:41 -0700267 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000268 return;
269 }
270 GrContext* context = rt->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700271 if (nullptr == context) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000272 return;
273 }
274
joshualittf5883a62016-01-13 07:47:38 -0800275 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(rt));
276 if (!drawContext) {
277 return;
278 }
279
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000280 struct Vertex {
281 SkPoint fPosition;
282 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
283 };
284
285 static const int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000286 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000287
288 // Mult by 3 for each edge effect type
289 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
290 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
291 SkScalar w = SkIntToScalar(rt->width()) / numCols;
292 SkScalar h = SkIntToScalar(rt->height()) / numRows;
293 int row = 0;
294 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700295 static const GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000296
297 for (int i = 0; i < kNumConics; ++i) {
298 SkPoint baseControlPts[] = {
299 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
300 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
301 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
302 };
303 SkScalar weight = rand.nextRangeF(0.f, 2.f);
joshualittb0a8a372014-09-23 09:50:21 -0700304 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
305 SkAutoTUnref<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800306 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
307 gp.reset(GrConicEffect::Create(color, SkMatrix::I(), et,
308 *context->caps(), SkMatrix::I(), false));
309 if (!gp) {
310 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000311 }
312
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000313 SkScalar x = SkScalarMul(col, w);
314 SkScalar y = SkScalarMul(row, h);
315 SkPoint controlPts[] = {
316 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
317 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
318 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
319 };
320 SkConic dst[4];
321 SkScalar klmEqs[9];
322 int cnt = chop_conic(controlPts, dst, weight);
323 GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
324
325 SkPaint ctrlPtPaint;
326 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
327 for (int i = 0; i < 3; ++i) {
328 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
329 }
330
331 SkPaint polyPaint;
332 polyPaint.setColor(0xffA0A0A0);
333 polyPaint.setStrokeWidth(0);
334 polyPaint.setStyle(SkPaint::kStroke_Style);
335 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
336
337 SkPaint choppedPtPaint;
338 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
339
340 for (int c = 0; c < cnt; ++c) {
341 SkPoint* pts = dst[c].fPts;
342 for (int i = 0; i < 3; ++i) {
343 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
344 }
345
346 SkRect bounds;
347 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
348 //bounds.set(bPts, 2);
349 bounds.set(pts, 3);
350
351 SkPaint boundsPaint;
352 boundsPaint.setColor(0xff808080);
353 boundsPaint.setStrokeWidth(0);
354 boundsPaint.setStyle(SkPaint::kStroke_Style);
355 canvas->drawRect(bounds, boundsPaint);
356
egdaniel8dd688b2015-01-22 10:16:09 -0800357 GrPipelineBuilder pipelineBuilder;
egdanielc4b72722015-11-23 13:20:41 -0800358 pipelineBuilder.setXPFactory(
359 GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
egdaniel8dd688b2015-01-22 10:16:09 -0800360 pipelineBuilder.setRenderTarget(rt);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000361
joshualitt95964c62015-02-11 13:45:50 -0800362 BezierCubicOrConicTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700363 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800364 geometry.fBounds = bounds;
365
bsalomonabd30f52015-08-13 13:34:48 -0700366 SkAutoTUnref<GrDrawBatch> batch(
joshualitt44701df2015-02-23 14:44:57 -0800367 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, 1.f));
joshualitt95964c62015-02-11 13:45:50 -0800368
robertphillips391395d2016-03-02 09:26:36 -0800369 drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000370 }
371 ++col;
372 if (numCols == col) {
373 col = 0;
374 ++row;
375 }
376 }
377 }
378 }
379
380private:
381 // Uses the max curvature function for quads to estimate
382 // where to chop the conic. If the max curvature is not
383 // found along the curve segment it will return 1 and
384 // dst[0] is the original conic. If it returns 2 the dst[0]
385 // and dst[1] are the two new conics.
386 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
387 SkScalar t = SkFindQuadMaxCurvature(src);
388 if (t == 0) {
389 if (dst) {
390 dst[0].set(src, weight);
391 }
392 return 1;
393 } else {
394 if (dst) {
395 SkConic conic;
396 conic.set(src, weight);
397 conic.chopAt(t, dst);
398 }
399 return 2;
400 }
401 }
402
403 // Calls split_conic on the entire conic and then once more on each subsection.
404 // Most cases will result in either 1 conic (chop point is not within t range)
405 // or 3 points (split once and then one subsection is split again).
406 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
407 SkConic dstTemp[2];
408 int conicCnt = split_conic(src, dstTemp, weight);
409 if (2 == conicCnt) {
410 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
411 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
412 } else {
413 dst[0] = dstTemp[0];
414 }
415 return conicCnt;
416 }
417
418 typedef GM INHERITED;
419};
420
421//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800422
423class BezierQuadTestBatch : public GrTestBatch {
424public:
reed1b55a962015-09-17 20:16:13 -0700425 DEFINE_BATCH_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -0800426 struct Geometry : public GrTestBatch::Geometry {
427 SkRect fBounds;
428 };
429
mtklein36352bf2015-03-25 18:17:31 -0700430 const char* name() const override { return "BezierQuadTestBatch"; }
joshualitt95964c62015-02-11 13:45:50 -0800431
bsalomonabd30f52015-08-13 13:34:48 -0700432 static GrDrawBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo,
433 const GrPathUtils::QuadUVMatrix& devToUV) {
halcanary385fe4d2015-08-26 13:07:48 -0700434 return new BezierQuadTestBatch(gp, geo, devToUV);
joshualitt95964c62015-02-11 13:45:50 -0800435 }
436
437private:
438 BezierQuadTestBatch(const GrGeometryProcessor* gp, const Geometry& geo,
439 const GrPathUtils::QuadUVMatrix& devToUV)
reed1b55a962015-09-17 20:16:13 -0700440 : INHERITED(ClassID(), gp, geo.fBounds)
joshualitt95964c62015-02-11 13:45:50 -0800441 , fGeometry(geo)
442 , fDevToUV(devToUV) {
443 }
444
445 struct Vertex {
446 SkPoint fPosition;
447 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
448 };
449
mtklein36352bf2015-03-25 18:17:31 -0700450 Geometry* geoData(int index) override {
joshualitt95964c62015-02-11 13:45:50 -0800451 SkASSERT(0 == index);
452 return &fGeometry;
453 }
454
joshualitt88c23fc2015-05-13 14:18:07 -0700455 const Geometry* geoData(int index) const override {
456 SkASSERT(0 == index);
457 return &fGeometry;
458 }
459
joshualitt144c3c82015-11-30 12:30:13 -0800460 void generateGeometry(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -0700461 QuadHelper helper;
bsalomoned0bcad2015-05-04 10:36:42 -0700462 size_t vertexStride = this->geometryProcessor()->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700463 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700464 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700465 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800466 return;
467 }
joshualitt95964c62015-02-11 13:45:50 -0800468 verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop,
469 fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom,
470 sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800471 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
bsalomon75398562015-08-17 12:55:38 -0700472 helper.recordDraw(target);
joshualitt95964c62015-02-11 13:45:50 -0800473 }
474
475 Geometry fGeometry;
476 GrPathUtils::QuadUVMatrix fDevToUV;
477
478 static const int kVertsPerCubic = 4;
479 static const int kIndicesPerCubic = 6;
480
481 typedef GrTestBatch INHERITED;
482};
483
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000484/**
485 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
486 */
487class BezierQuadEffects : public GM {
488public:
489 BezierQuadEffects() {
490 this->setBGColor(0xFFFFFFFF);
491 }
492
493protected:
mtklein36352bf2015-03-25 18:17:31 -0700494 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000495 return SkString("bezier_quad_effects");
496 }
497
mtklein36352bf2015-03-25 18:17:31 -0700498 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700499 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000500 }
501
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000502
mtklein36352bf2015-03-25 18:17:31 -0700503 void onDraw(SkCanvas* canvas) override {
reed@google.com9c135db2014-03-12 18:28:35 +0000504 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
halcanary96fcdcc2015-08-27 07:41:13 -0700505 if (nullptr == rt) {
halcanary2a243382015-09-09 08:16:41 -0700506 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000507 return;
508 }
509 GrContext* context = rt->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700510 if (nullptr == context) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000511 return;
512 }
513
joshualittf5883a62016-01-13 07:47:38 -0800514 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(rt));
515 if (!drawContext) {
516 return;
517 }
518
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000519 struct Vertex {
520 SkPoint fPosition;
521 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
522 };
523
524 static const int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000525 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000526
527 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
528 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
529 SkScalar w = SkIntToScalar(rt->width()) / numCols;
530 SkScalar h = SkIntToScalar(rt->height()) / numRows;
531 int row = 0;
532 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700533 static const GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000534
535 for (int i = 0; i < kNumQuads; ++i) {
536 SkPoint baseControlPts[] = {
537 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
538 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
539 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
540 };
joshualittb0a8a372014-09-23 09:50:21 -0700541 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
542 SkAutoTUnref<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800543 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
544 gp.reset(GrQuadEffect::Create(color, SkMatrix::I(), et,
545 *context->caps(), SkMatrix::I(), false));
546 if (!gp) {
547 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000548 }
549
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000550 SkScalar x = SkScalarMul(col, w);
551 SkScalar y = SkScalarMul(row, h);
552 SkPoint controlPts[] = {
553 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
554 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
555 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
556 };
557 SkPoint chopped[5];
558 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
559
560 SkPaint ctrlPtPaint;
561 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
562 for (int i = 0; i < 3; ++i) {
563 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
564 }
565
566 SkPaint polyPaint;
567 polyPaint.setColor(0xffA0A0A0);
568 polyPaint.setStrokeWidth(0);
569 polyPaint.setStyle(SkPaint::kStroke_Style);
570 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
571
572 SkPaint choppedPtPaint;
573 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
574
575 for (int c = 0; c < cnt; ++c) {
576 SkPoint* pts = chopped + 2 * c;
577
578 for (int i = 0; i < 3; ++i) {
579 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
580 }
581
582 SkRect bounds;
583 bounds.set(pts, 3);
584
585 SkPaint boundsPaint;
586 boundsPaint.setColor(0xff808080);
587 boundsPaint.setStrokeWidth(0);
588 boundsPaint.setStyle(SkPaint::kStroke_Style);
589 canvas->drawRect(bounds, boundsPaint);
590
egdaniel8dd688b2015-01-22 10:16:09 -0800591 GrPipelineBuilder pipelineBuilder;
egdanielc4b72722015-11-23 13:20:41 -0800592 pipelineBuilder.setXPFactory(
593 GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
joshualitt94dff152015-02-11 13:03:15 -0800594 pipelineBuilder.setRenderTarget(rt);
joshualitt3f284d72015-02-11 11:34:58 -0800595
joshualitt95964c62015-02-11 13:45:50 -0800596 GrPathUtils::QuadUVMatrix DevToUV(pts);
597
598 BezierQuadTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700599 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800600 geometry.fBounds = bounds;
601
bsalomonabd30f52015-08-13 13:34:48 -0700602 SkAutoTUnref<GrDrawBatch> batch(BezierQuadTestBatch::Create(gp, geometry,
603 DevToUV));
joshualitt95964c62015-02-11 13:45:50 -0800604
robertphillips391395d2016-03-02 09:26:36 -0800605 drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000606 }
607 ++col;
608 if (numCols == col) {
609 col = 0;
610 ++row;
611 }
612 }
613 }
614 }
615
616private:
617 typedef GM INHERITED;
618};
619
halcanary385fe4d2015-08-26 13:07:48 -0700620DEF_GM(return new BezierCubicEffects;)
621DEF_GM(return new BezierConicEffects;)
622DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000623}
624
625#endif