blob: 2511dec6e025a9f9d7afe2ea79256e2e54a92e1e [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
joshualittf5883a62016-01-13 07:47:38 -080015#include "GrDrawContext.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:
reed1b55a962015-09-17 20:16:13 -070035 DEFINE_BATCH_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -080036 struct Geometry : public GrTestBatch::Geometry {
37 SkRect fBounds;
38 };
39
mtklein36352bf2015-03-25 18:17:31 -070040 const char* name() const override { return "BezierCubicOrConicTestBatch"; }
joshualitt95964c62015-02-11 13:45:50 -080041
bsalomonabd30f52015-08-13 13:34:48 -070042 static GrDrawBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo,
43 const SkScalar klmEqs[9], SkScalar sign) {
halcanary385fe4d2015-08-26 13:07:48 -070044 return new BezierCubicOrConicTestBatch(gp, geo, klmEqs, sign);
joshualitt95964c62015-02-11 13:45:50 -080045 }
46
47private:
48 BezierCubicOrConicTestBatch(const GrGeometryProcessor* gp, const Geometry& geo,
49 const SkScalar klmEqs[9], SkScalar sign)
reed1b55a962015-09-17 20:16:13 -070050 : INHERITED(ClassID(), gp, geo.fBounds) {
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
joshualitt144c3c82015-11-30 12:30:13 -080074 void generateGeometry(Target* target) const 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
joshualittf5883a62016-01-13 07:47:38 -0800133 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(rt));
134 if (!drawContext) {
135 return;
136 }
137
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000138 struct Vertex {
139 SkPoint fPosition;
140 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
141 };
142
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000143 static const int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000144 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000145
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000146 // Mult by 3 for each edge effect type
147 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
148 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000149 SkScalar w = SkIntToScalar(rt->width()) / numCols;
150 SkScalar h = SkIntToScalar(rt->height()) / numRows;
151 int row = 0;
152 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700153 static const GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000154
155 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000156 SkPoint baseControlPts[] = {
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)},
160 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000161 };
joshualittb0a8a372014-09-23 09:50:21 -0700162 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
163 SkAutoTUnref<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800164 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
165 gp.reset(GrCubicEffect::Create(color, SkMatrix::I(), et,
166 *context->caps()));
167 if (!gp) {
168 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000169 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000170 SkScalar x = SkScalarMul(col, w);
171 SkScalar y = SkScalarMul(row, h);
172 SkPoint controlPts[] = {
173 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
174 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
175 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
176 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
177 };
178 SkPoint chopped[10];
179 SkScalar klmEqs[9];
180 SkScalar klmSigns[3];
181 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
182 chopped,
183 klmEqs,
184 klmSigns);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000185
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000186 SkPaint ctrlPtPaint;
187 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000188 for (int i = 0; i < 4; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000189 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000190 }
191
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000192 SkPaint polyPaint;
193 polyPaint.setColor(0xffA0A0A0);
194 polyPaint.setStrokeWidth(0);
195 polyPaint.setStyle(SkPaint::kStroke_Style);
196 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000197
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000198 SkPaint choppedPtPaint;
199 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000200
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000201 for (int c = 0; c < cnt; ++c) {
202 SkPoint* pts = chopped + 3 * c;
203
204 for (int i = 0; i < 4; ++i) {
205 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
206 }
207
208 SkRect bounds;
209 bounds.set(pts, 4);
210
211 SkPaint boundsPaint;
212 boundsPaint.setColor(0xff808080);
213 boundsPaint.setStrokeWidth(0);
214 boundsPaint.setStyle(SkPaint::kStroke_Style);
215 canvas->drawRect(bounds, boundsPaint);
216
egdaniel8dd688b2015-01-22 10:16:09 -0800217 GrPipelineBuilder pipelineBuilder;
egdanielc4b72722015-11-23 13:20:41 -0800218 pipelineBuilder.setXPFactory(
219 GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
egdaniel8dd688b2015-01-22 10:16:09 -0800220 pipelineBuilder.setRenderTarget(rt);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000221
joshualitt95964c62015-02-11 13:45:50 -0800222 BezierCubicOrConicTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700223 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800224 geometry.fBounds = bounds;
225
bsalomonabd30f52015-08-13 13:34:48 -0700226 SkAutoTUnref<GrDrawBatch> batch(
joshualitt44701df2015-02-23 14:44:57 -0800227 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, klmSigns[c]));
joshualitt95964c62015-02-11 13:45:50 -0800228
joshualittf5883a62016-01-13 07:47:38 -0800229 drawContext->internal_drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000230 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000231 ++col;
232 if (numCols == col) {
233 col = 0;
234 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000235 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000236 }
237 }
238 }
239
240private:
241 typedef GM INHERITED;
242};
243
244//////////////////////////////////////////////////////////////////////////////
245
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000246/**
247 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
248 */
249class BezierConicEffects : public GM {
250public:
251 BezierConicEffects() {
252 this->setBGColor(0xFFFFFFFF);
253 }
254
255protected:
mtklein36352bf2015-03-25 18:17:31 -0700256 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000257 return SkString("bezier_conic_effects");
258 }
259
mtklein36352bf2015-03-25 18:17:31 -0700260 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700261 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000262 }
263
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000264
mtklein36352bf2015-03-25 18:17:31 -0700265 void onDraw(SkCanvas* canvas) override {
reed@google.com9c135db2014-03-12 18:28:35 +0000266 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
halcanary96fcdcc2015-08-27 07:41:13 -0700267 if (nullptr == rt) {
halcanary2a243382015-09-09 08:16:41 -0700268 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000269 return;
270 }
271 GrContext* context = rt->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700272 if (nullptr == context) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000273 return;
274 }
275
joshualittf5883a62016-01-13 07:47:38 -0800276 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(rt));
277 if (!drawContext) {
278 return;
279 }
280
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000281 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;
joshualittf5883a62016-01-13 07:47:38 -0800307 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
308 gp.reset(GrConicEffect::Create(color, SkMatrix::I(), et,
309 *context->caps(), SkMatrix::I(), false));
310 if (!gp) {
311 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000312 }
313
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000314 SkScalar x = SkScalarMul(col, w);
315 SkScalar y = SkScalarMul(row, h);
316 SkPoint controlPts[] = {
317 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
318 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
319 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
320 };
321 SkConic dst[4];
322 SkScalar klmEqs[9];
323 int cnt = chop_conic(controlPts, dst, weight);
324 GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
325
326 SkPaint ctrlPtPaint;
327 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
328 for (int i = 0; i < 3; ++i) {
329 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
330 }
331
332 SkPaint polyPaint;
333 polyPaint.setColor(0xffA0A0A0);
334 polyPaint.setStrokeWidth(0);
335 polyPaint.setStyle(SkPaint::kStroke_Style);
336 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
337
338 SkPaint choppedPtPaint;
339 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
340
341 for (int c = 0; c < cnt; ++c) {
342 SkPoint* pts = dst[c].fPts;
343 for (int i = 0; i < 3; ++i) {
344 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
345 }
346
347 SkRect bounds;
348 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
349 //bounds.set(bPts, 2);
350 bounds.set(pts, 3);
351
352 SkPaint boundsPaint;
353 boundsPaint.setColor(0xff808080);
354 boundsPaint.setStrokeWidth(0);
355 boundsPaint.setStyle(SkPaint::kStroke_Style);
356 canvas->drawRect(bounds, boundsPaint);
357
egdaniel8dd688b2015-01-22 10:16:09 -0800358 GrPipelineBuilder pipelineBuilder;
egdanielc4b72722015-11-23 13:20:41 -0800359 pipelineBuilder.setXPFactory(
360 GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
egdaniel8dd688b2015-01-22 10:16:09 -0800361 pipelineBuilder.setRenderTarget(rt);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000362
joshualitt95964c62015-02-11 13:45:50 -0800363 BezierCubicOrConicTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700364 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800365 geometry.fBounds = bounds;
366
bsalomonabd30f52015-08-13 13:34:48 -0700367 SkAutoTUnref<GrDrawBatch> batch(
joshualitt44701df2015-02-23 14:44:57 -0800368 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, 1.f));
joshualitt95964c62015-02-11 13:45:50 -0800369
joshualittf5883a62016-01-13 07:47:38 -0800370 drawContext->internal_drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000371 }
372 ++col;
373 if (numCols == col) {
374 col = 0;
375 ++row;
376 }
377 }
378 }
379 }
380
381private:
382 // Uses the max curvature function for quads to estimate
383 // where to chop the conic. If the max curvature is not
384 // found along the curve segment it will return 1 and
385 // dst[0] is the original conic. If it returns 2 the dst[0]
386 // and dst[1] are the two new conics.
387 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
388 SkScalar t = SkFindQuadMaxCurvature(src);
389 if (t == 0) {
390 if (dst) {
391 dst[0].set(src, weight);
392 }
393 return 1;
394 } else {
395 if (dst) {
396 SkConic conic;
397 conic.set(src, weight);
398 conic.chopAt(t, dst);
399 }
400 return 2;
401 }
402 }
403
404 // Calls split_conic on the entire conic and then once more on each subsection.
405 // Most cases will result in either 1 conic (chop point is not within t range)
406 // or 3 points (split once and then one subsection is split again).
407 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
408 SkConic dstTemp[2];
409 int conicCnt = split_conic(src, dstTemp, weight);
410 if (2 == conicCnt) {
411 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
412 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
413 } else {
414 dst[0] = dstTemp[0];
415 }
416 return conicCnt;
417 }
418
419 typedef GM INHERITED;
420};
421
422//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800423
424class BezierQuadTestBatch : public GrTestBatch {
425public:
reed1b55a962015-09-17 20:16:13 -0700426 DEFINE_BATCH_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -0800427 struct Geometry : public GrTestBatch::Geometry {
428 SkRect fBounds;
429 };
430
mtklein36352bf2015-03-25 18:17:31 -0700431 const char* name() const override { return "BezierQuadTestBatch"; }
joshualitt95964c62015-02-11 13:45:50 -0800432
bsalomonabd30f52015-08-13 13:34:48 -0700433 static GrDrawBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo,
434 const GrPathUtils::QuadUVMatrix& devToUV) {
halcanary385fe4d2015-08-26 13:07:48 -0700435 return new BezierQuadTestBatch(gp, geo, devToUV);
joshualitt95964c62015-02-11 13:45:50 -0800436 }
437
438private:
439 BezierQuadTestBatch(const GrGeometryProcessor* gp, const Geometry& geo,
440 const GrPathUtils::QuadUVMatrix& devToUV)
reed1b55a962015-09-17 20:16:13 -0700441 : INHERITED(ClassID(), gp, geo.fBounds)
joshualitt95964c62015-02-11 13:45:50 -0800442 , fGeometry(geo)
443 , fDevToUV(devToUV) {
444 }
445
446 struct Vertex {
447 SkPoint fPosition;
448 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
449 };
450
mtklein36352bf2015-03-25 18:17:31 -0700451 Geometry* geoData(int index) override {
joshualitt95964c62015-02-11 13:45:50 -0800452 SkASSERT(0 == index);
453 return &fGeometry;
454 }
455
joshualitt88c23fc2015-05-13 14:18:07 -0700456 const Geometry* geoData(int index) const override {
457 SkASSERT(0 == index);
458 return &fGeometry;
459 }
460
joshualitt144c3c82015-11-30 12:30:13 -0800461 void generateGeometry(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -0700462 QuadHelper helper;
bsalomoned0bcad2015-05-04 10:36:42 -0700463 size_t vertexStride = this->geometryProcessor()->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700464 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700465 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700466 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800467 return;
468 }
joshualitt95964c62015-02-11 13:45:50 -0800469 verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop,
470 fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom,
471 sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800472 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
bsalomon75398562015-08-17 12:55:38 -0700473 helper.recordDraw(target);
joshualitt95964c62015-02-11 13:45:50 -0800474 }
475
476 Geometry fGeometry;
477 GrPathUtils::QuadUVMatrix fDevToUV;
478
479 static const int kVertsPerCubic = 4;
480 static const int kIndicesPerCubic = 6;
481
482 typedef GrTestBatch INHERITED;
483};
484
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000485/**
486 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
487 */
488class BezierQuadEffects : public GM {
489public:
490 BezierQuadEffects() {
491 this->setBGColor(0xFFFFFFFF);
492 }
493
494protected:
mtklein36352bf2015-03-25 18:17:31 -0700495 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000496 return SkString("bezier_quad_effects");
497 }
498
mtklein36352bf2015-03-25 18:17:31 -0700499 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700500 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000501 }
502
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000503
mtklein36352bf2015-03-25 18:17:31 -0700504 void onDraw(SkCanvas* canvas) override {
reed@google.com9c135db2014-03-12 18:28:35 +0000505 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
halcanary96fcdcc2015-08-27 07:41:13 -0700506 if (nullptr == rt) {
halcanary2a243382015-09-09 08:16:41 -0700507 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000508 return;
509 }
510 GrContext* context = rt->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700511 if (nullptr == context) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000512 return;
513 }
514
joshualittf5883a62016-01-13 07:47:38 -0800515 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(rt));
516 if (!drawContext) {
517 return;
518 }
519
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000520 struct Vertex {
521 SkPoint fPosition;
522 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
523 };
524
525 static const int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000526 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000527
528 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
529 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
530 SkScalar w = SkIntToScalar(rt->width()) / numCols;
531 SkScalar h = SkIntToScalar(rt->height()) / numRows;
532 int row = 0;
533 int col = 0;
joshualitt88c23fc2015-05-13 14:18:07 -0700534 static const GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000535
536 for (int i = 0; i < kNumQuads; ++i) {
537 SkPoint baseControlPts[] = {
538 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
539 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
540 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
541 };
joshualittb0a8a372014-09-23 09:50:21 -0700542 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
543 SkAutoTUnref<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800544 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
545 gp.reset(GrQuadEffect::Create(color, SkMatrix::I(), et,
546 *context->caps(), SkMatrix::I(), false));
547 if (!gp) {
548 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000549 }
550
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000551 SkScalar x = SkScalarMul(col, w);
552 SkScalar y = SkScalarMul(row, h);
553 SkPoint controlPts[] = {
554 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
555 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
556 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
557 };
558 SkPoint chopped[5];
559 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
560
561 SkPaint ctrlPtPaint;
562 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
563 for (int i = 0; i < 3; ++i) {
564 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
565 }
566
567 SkPaint polyPaint;
568 polyPaint.setColor(0xffA0A0A0);
569 polyPaint.setStrokeWidth(0);
570 polyPaint.setStyle(SkPaint::kStroke_Style);
571 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
572
573 SkPaint choppedPtPaint;
574 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
575
576 for (int c = 0; c < cnt; ++c) {
577 SkPoint* pts = chopped + 2 * c;
578
579 for (int i = 0; i < 3; ++i) {
580 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
581 }
582
583 SkRect bounds;
584 bounds.set(pts, 3);
585
586 SkPaint boundsPaint;
587 boundsPaint.setColor(0xff808080);
588 boundsPaint.setStrokeWidth(0);
589 boundsPaint.setStyle(SkPaint::kStroke_Style);
590 canvas->drawRect(bounds, boundsPaint);
591
egdaniel8dd688b2015-01-22 10:16:09 -0800592 GrPipelineBuilder pipelineBuilder;
egdanielc4b72722015-11-23 13:20:41 -0800593 pipelineBuilder.setXPFactory(
594 GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
joshualitt94dff152015-02-11 13:03:15 -0800595 pipelineBuilder.setRenderTarget(rt);
joshualitt3f284d72015-02-11 11:34:58 -0800596
joshualitt95964c62015-02-11 13:45:50 -0800597 GrPathUtils::QuadUVMatrix DevToUV(pts);
598
599 BezierQuadTestBatch::Geometry geometry;
joshualitt88c23fc2015-05-13 14:18:07 -0700600 geometry.fColor = color;
joshualitt95964c62015-02-11 13:45:50 -0800601 geometry.fBounds = bounds;
602
bsalomonabd30f52015-08-13 13:34:48 -0700603 SkAutoTUnref<GrDrawBatch> batch(BezierQuadTestBatch::Create(gp, geometry,
604 DevToUV));
joshualitt95964c62015-02-11 13:45:50 -0800605
joshualittf5883a62016-01-13 07:47:38 -0800606 drawContext->internal_drawBatch(pipelineBuilder, batch);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000607 }
608 ++col;
609 if (numCols == col) {
610 col = 0;
611 ++row;
612 }
613 }
614 }
615 }
616
617private:
618 typedef GM INHERITED;
619};
620
halcanary385fe4d2015-08-26 13:07:48 -0700621DEF_GM(return new BezierCubicEffects;)
622DEF_GM(return new BezierConicEffects;)
623DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000624}
625
626#endif