blob: d58e5910b0f72d2d5237f58ad22aca55d7882bdd [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
Brian Osman11052242016-10-27 14:47:55 -040014#include "GrRenderTargetContextPriv.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"
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000019#include "SkGeometry.h"
20
joshualitt2771b562015-08-07 12:46:26 -070021#include "batches/GrTestBatch.h"
22
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000023#include "effects/GrBezierEffect.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000024
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000025static inline SkScalar eval_line(const SkPoint& p, const SkScalar lineEq[3], SkScalar sign) {
26 return sign * (lineEq[0] * p.fX + lineEq[1] * p.fY + lineEq[2]);
27}
28
29namespace skiagm {
joshualitt95964c62015-02-11 13:45:50 -080030
31class BezierCubicOrConicTestBatch : public GrTestBatch {
32public:
Brian Salomon25a88092016-12-01 09:36:50 -050033 DEFINE_OP_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -080034
mtklein36352bf2015-03-25 18:17:31 -070035 const char* name() const override { return "BezierCubicOrConicTestBatch"; }
joshualitt95964c62015-02-11 13:45:50 -080036
bungeman06ca8ec2016-06-09 08:01:03 -070037 BezierCubicOrConicTestBatch(sk_sp<GrGeometryProcessor> gp, const SkRect& bounds,
bsalomon342bfc22016-04-01 06:06:20 -070038 GrColor color, const SkScalar klmEqs[9], SkScalar sign)
39 : INHERITED(ClassID(), bounds, color)
bungeman06ca8ec2016-06-09 08:01:03 -070040 , fGeometryProcessor(std::move(gp)) {
joshualitt95964c62015-02-11 13:45:50 -080041 for (int i = 0; i < 9; i++) {
42 fKlmEqs[i] = klmEqs[i];
43 }
joshualitt95964c62015-02-11 13:45:50 -080044 fSign = sign;
45 }
46
bsalomon342bfc22016-04-01 06:06:20 -070047private:
48
joshualitt95964c62015-02-11 13:45:50 -080049 struct Vertex {
50 SkPoint fPosition;
51 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
52 };
53
bsalomon342bfc22016-04-01 06:06:20 -070054 void onPrepareDraws(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -070055 QuadHelper helper;
bsalomon342bfc22016-04-01 06:06:20 -070056 size_t vertexStride = fGeometryProcessor->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -070057 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -070058 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -070059 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -080060 return;
61 }
bsalomon342bfc22016-04-01 06:06:20 -070062 const SkRect& bounds = this->bounds();
63 verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom,
joshualitt95964c62015-02-11 13:45:50 -080064 sizeof(Vertex));
65 for (int v = 0; v < 4; ++v) {
66 verts[v].fKLM[0] = eval_line(verts[v].fPosition, fKlmEqs + 0, fSign);
67 verts[v].fKLM[1] = eval_line(verts[v].fPosition, fKlmEqs + 3, fSign);
68 verts[v].fKLM[2] = eval_line(verts[v].fPosition, fKlmEqs + 6, 1.f);
69 }
bungeman06ca8ec2016-06-09 08:01:03 -070070 helper.recordDraw(target, fGeometryProcessor.get());
joshualitt95964c62015-02-11 13:45:50 -080071 }
72
bungeman06ca8ec2016-06-09 08:01:03 -070073 SkScalar fKlmEqs[9];
74 SkScalar fSign;
75 sk_sp<GrGeometryProcessor> fGeometryProcessor;
joshualitt95964c62015-02-11 13:45:50 -080076
mtkleindbfd7ab2016-09-01 11:24:54 -070077 static constexpr int kVertsPerCubic = 4;
78 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -080079
80 typedef GrTestBatch INHERITED;
81};
82
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000083/**
84 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
85 */
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000086class BezierCubicEffects : public GM {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000087public:
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000088 BezierCubicEffects() {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000089 this->setBGColor(0xFFFFFFFF);
90 }
91
92protected:
mtklein36352bf2015-03-25 18:17:31 -070093 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000094 return SkString("bezier_cubic_effects");
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000095 }
96
mtklein36352bf2015-03-25 18:17:31 -070097 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -070098 return SkISize::Make(800, 800);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000099 }
100
mtklein36352bf2015-03-25 18:17:31 -0700101 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400102 GrRenderTargetContext* renderTargetContext =
103 canvas->internal_private_accessTopLayerRenderTargetContext();
104 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700105 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000106 return;
107 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000108
robertphillips175dd9b2016-04-28 14:32:04 -0700109 GrContext* context = canvas->getGrContext();
110 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800111 return;
112 }
113
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000114 struct Vertex {
115 SkPoint fPosition;
116 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
117 };
118
mtkleindbfd7ab2016-09-01 11:24:54 -0700119 constexpr int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000120 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000121
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000122 // Mult by 3 for each edge effect type
123 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
124 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400125 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
126 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000127 int row = 0;
128 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700129 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000130
131 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000132 SkPoint baseControlPts[] = {
133 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
134 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
135 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
136 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000137 };
joshualittb0a8a372014-09-23 09:50:21 -0700138 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700139 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800140 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700141 gp = GrCubicEffect::Make(color, SkMatrix::I(), et, *context->caps());
joshualittf5883a62016-01-13 07:47:38 -0800142 if (!gp) {
143 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000144 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000145 SkScalar x = SkScalarMul(col, w);
146 SkScalar y = SkScalarMul(row, h);
147 SkPoint controlPts[] = {
148 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
149 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
150 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
151 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
152 };
153 SkPoint chopped[10];
154 SkScalar klmEqs[9];
155 SkScalar klmSigns[3];
156 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
157 chopped,
158 klmEqs,
159 klmSigns);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000160
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000161 SkPaint ctrlPtPaint;
162 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000163 for (int i = 0; i < 4; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000164 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000165 }
166
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000167 SkPaint polyPaint;
168 polyPaint.setColor(0xffA0A0A0);
169 polyPaint.setStrokeWidth(0);
170 polyPaint.setStyle(SkPaint::kStroke_Style);
171 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000172
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000173 SkPaint choppedPtPaint;
174 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000175
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000176 for (int c = 0; c < cnt; ++c) {
177 SkPoint* pts = chopped + 3 * c;
178
179 for (int i = 0; i < 4; ++i) {
180 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
181 }
182
183 SkRect bounds;
184 bounds.set(pts, 4);
185
186 SkPaint boundsPaint;
187 boundsPaint.setColor(0xff808080);
188 boundsPaint.setStrokeWidth(0);
189 boundsPaint.setStyle(SkPaint::kStroke_Style);
190 canvas->drawRect(bounds, boundsPaint);
191
robertphillips28a838e2016-06-23 14:07:00 -0700192 GrPaint grPaint;
Mike Reed7d954ad2016-10-28 15:42:34 -0400193 grPaint.setXPFactory(GrPorterDuffXPFactory::Make(SkBlendMode::kSrc));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000194
Hal Canarycefc4312016-11-04 16:26:16 -0400195 sk_sp<GrDrawBatch> batch = sk_make_sp<BezierCubicOrConicTestBatch>(
196 gp, bounds, color, klmEqs, klmSigns[c]);
joshualitt95964c62015-02-11 13:45:50 -0800197
Hal Canarycefc4312016-11-04 16:26:16 -0400198 renderTargetContext->priv().testingOnly_drawBatch(grPaint, batch.get());
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000199 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000200 ++col;
201 if (numCols == col) {
202 col = 0;
203 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000204 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000205 }
206 }
207 }
208
209private:
210 typedef GM INHERITED;
211};
212
213//////////////////////////////////////////////////////////////////////////////
214
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000215/**
216 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
217 */
218class BezierConicEffects : public GM {
219public:
220 BezierConicEffects() {
221 this->setBGColor(0xFFFFFFFF);
222 }
223
224protected:
mtklein36352bf2015-03-25 18:17:31 -0700225 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000226 return SkString("bezier_conic_effects");
227 }
228
mtklein36352bf2015-03-25 18:17:31 -0700229 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700230 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000231 }
232
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000233
mtklein36352bf2015-03-25 18:17:31 -0700234 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400235 GrRenderTargetContext* renderTargetContext =
236 canvas->internal_private_accessTopLayerRenderTargetContext();
237 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700238 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000239 return;
240 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000241
robertphillips175dd9b2016-04-28 14:32:04 -0700242 GrContext* context = canvas->getGrContext();
243 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800244 return;
245 }
246
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000247 struct Vertex {
248 SkPoint fPosition;
249 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
250 };
251
mtkleindbfd7ab2016-09-01 11:24:54 -0700252 constexpr int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000253 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000254
255 // Mult by 3 for each edge effect type
256 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
257 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400258 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
259 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000260 int row = 0;
261 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700262 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000263
264 for (int i = 0; i < kNumConics; ++i) {
265 SkPoint baseControlPts[] = {
266 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
267 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
268 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
269 };
270 SkScalar weight = rand.nextRangeF(0.f, 2.f);
joshualittb0a8a372014-09-23 09:50:21 -0700271 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700272 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800273 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700274 gp = GrConicEffect::Make(color, SkMatrix::I(), et,
275 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800276 if (!gp) {
277 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000278 }
279
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000280 SkScalar x = SkScalarMul(col, w);
281 SkScalar y = SkScalarMul(row, h);
282 SkPoint controlPts[] = {
283 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
284 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
285 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
286 };
287 SkConic dst[4];
288 SkScalar klmEqs[9];
289 int cnt = chop_conic(controlPts, dst, weight);
290 GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
291
292 SkPaint ctrlPtPaint;
293 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
294 for (int i = 0; i < 3; ++i) {
295 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
296 }
297
298 SkPaint polyPaint;
299 polyPaint.setColor(0xffA0A0A0);
300 polyPaint.setStrokeWidth(0);
301 polyPaint.setStyle(SkPaint::kStroke_Style);
302 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
303
304 SkPaint choppedPtPaint;
305 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
306
307 for (int c = 0; c < cnt; ++c) {
308 SkPoint* pts = dst[c].fPts;
309 for (int i = 0; i < 3; ++i) {
310 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
311 }
312
313 SkRect bounds;
314 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
315 //bounds.set(bPts, 2);
316 bounds.set(pts, 3);
317
318 SkPaint boundsPaint;
319 boundsPaint.setColor(0xff808080);
320 boundsPaint.setStrokeWidth(0);
321 boundsPaint.setStyle(SkPaint::kStroke_Style);
322 canvas->drawRect(bounds, boundsPaint);
323
robertphillips28a838e2016-06-23 14:07:00 -0700324 GrPaint grPaint;
Mike Reed7d954ad2016-10-28 15:42:34 -0400325 grPaint.setXPFactory(GrPorterDuffXPFactory::Make(SkBlendMode::kSrc));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000326
Hal Canarycefc4312016-11-04 16:26:16 -0400327 sk_sp<GrDrawBatch> batch(
bsalomon342bfc22016-04-01 06:06:20 -0700328 new BezierCubicOrConicTestBatch(gp, bounds, color, klmEqs, 1.f));
joshualitt95964c62015-02-11 13:45:50 -0800329
Hal Canarycefc4312016-11-04 16:26:16 -0400330 renderTargetContext->priv().testingOnly_drawBatch(grPaint, batch.get());
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000331 }
332 ++col;
333 if (numCols == col) {
334 col = 0;
335 ++row;
336 }
337 }
338 }
339 }
340
341private:
342 // Uses the max curvature function for quads to estimate
343 // where to chop the conic. If the max curvature is not
344 // found along the curve segment it will return 1 and
345 // dst[0] is the original conic. If it returns 2 the dst[0]
346 // and dst[1] are the two new conics.
347 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
348 SkScalar t = SkFindQuadMaxCurvature(src);
349 if (t == 0) {
350 if (dst) {
351 dst[0].set(src, weight);
352 }
353 return 1;
354 } else {
355 if (dst) {
356 SkConic conic;
357 conic.set(src, weight);
caryclark414c4292016-09-26 11:03:54 -0700358 if (!conic.chopAt(t, dst)) {
359 dst[0].set(src, weight);
360 return 1;
361 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000362 }
363 return 2;
364 }
365 }
366
367 // Calls split_conic on the entire conic and then once more on each subsection.
368 // Most cases will result in either 1 conic (chop point is not within t range)
369 // or 3 points (split once and then one subsection is split again).
370 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
371 SkConic dstTemp[2];
372 int conicCnt = split_conic(src, dstTemp, weight);
373 if (2 == conicCnt) {
374 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
375 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
376 } else {
377 dst[0] = dstTemp[0];
378 }
379 return conicCnt;
380 }
381
382 typedef GM INHERITED;
383};
384
385//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800386
387class BezierQuadTestBatch : public GrTestBatch {
388public:
Brian Salomon25a88092016-12-01 09:36:50 -0500389 DEFINE_OP_CLASS_ID
mtklein36352bf2015-03-25 18:17:31 -0700390 const char* name() const override { return "BezierQuadTestBatch"; }
joshualitt95964c62015-02-11 13:45:50 -0800391
bungeman06ca8ec2016-06-09 08:01:03 -0700392 BezierQuadTestBatch(sk_sp<GrGeometryProcessor> gp, const SkRect& bounds, GrColor color,
bsalomon342bfc22016-04-01 06:06:20 -0700393 const GrPathUtils::QuadUVMatrix& devToUV)
394 : INHERITED(ClassID(), bounds, color)
395 , fDevToUV(devToUV)
bungeman06ca8ec2016-06-09 08:01:03 -0700396 , fGeometryProcessor(std::move(gp)) {
joshualitt95964c62015-02-11 13:45:50 -0800397 }
398
399private:
joshualitt95964c62015-02-11 13:45:50 -0800400
401 struct Vertex {
402 SkPoint fPosition;
403 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
404 };
405
bsalomon342bfc22016-04-01 06:06:20 -0700406 void onPrepareDraws(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -0700407 QuadHelper helper;
bsalomon342bfc22016-04-01 06:06:20 -0700408 size_t vertexStride = fGeometryProcessor->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700409 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700410 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700411 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800412 return;
413 }
bsalomon342bfc22016-04-01 06:06:20 -0700414 const SkRect& bounds = this->bounds();
415 verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom,
joshualitt95964c62015-02-11 13:45:50 -0800416 sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800417 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
bungeman06ca8ec2016-06-09 08:01:03 -0700418 helper.recordDraw(target, fGeometryProcessor.get());
joshualitt95964c62015-02-11 13:45:50 -0800419 }
420
bungeman06ca8ec2016-06-09 08:01:03 -0700421 GrPathUtils::QuadUVMatrix fDevToUV;
422 sk_sp<GrGeometryProcessor> fGeometryProcessor;
joshualitt95964c62015-02-11 13:45:50 -0800423
mtkleindbfd7ab2016-09-01 11:24:54 -0700424 static constexpr int kVertsPerCubic = 4;
425 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800426
427 typedef GrTestBatch INHERITED;
428};
429
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000430/**
431 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
432 */
433class BezierQuadEffects : public GM {
434public:
435 BezierQuadEffects() {
436 this->setBGColor(0xFFFFFFFF);
437 }
438
439protected:
mtklein36352bf2015-03-25 18:17:31 -0700440 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000441 return SkString("bezier_quad_effects");
442 }
443
mtklein36352bf2015-03-25 18:17:31 -0700444 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700445 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000446 }
447
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000448
mtklein36352bf2015-03-25 18:17:31 -0700449 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400450 GrRenderTargetContext* renderTargetContext =
451 canvas->internal_private_accessTopLayerRenderTargetContext();
452 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700453 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000454 return;
455 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000456
robertphillips175dd9b2016-04-28 14:32:04 -0700457 GrContext* context = canvas->getGrContext();
458 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800459 return;
460 }
461
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000462 struct Vertex {
463 SkPoint fPosition;
464 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
465 };
466
mtkleindbfd7ab2016-09-01 11:24:54 -0700467 constexpr int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000468 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000469
470 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
471 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400472 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
473 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000474 int row = 0;
475 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700476 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000477
478 for (int i = 0; i < kNumQuads; ++i) {
479 SkPoint baseControlPts[] = {
480 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
481 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
482 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
483 };
joshualittb0a8a372014-09-23 09:50:21 -0700484 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700485 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800486 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700487 gp = GrQuadEffect::Make(color, SkMatrix::I(), et,
488 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800489 if (!gp) {
490 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000491 }
492
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000493 SkScalar x = SkScalarMul(col, w);
494 SkScalar y = SkScalarMul(row, h);
495 SkPoint controlPts[] = {
496 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
497 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
498 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
499 };
500 SkPoint chopped[5];
501 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
502
503 SkPaint ctrlPtPaint;
504 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
505 for (int i = 0; i < 3; ++i) {
506 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
507 }
508
509 SkPaint polyPaint;
510 polyPaint.setColor(0xffA0A0A0);
511 polyPaint.setStrokeWidth(0);
512 polyPaint.setStyle(SkPaint::kStroke_Style);
513 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
514
515 SkPaint choppedPtPaint;
516 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
517
518 for (int c = 0; c < cnt; ++c) {
519 SkPoint* pts = chopped + 2 * c;
520
521 for (int i = 0; i < 3; ++i) {
522 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
523 }
524
525 SkRect bounds;
526 bounds.set(pts, 3);
527
528 SkPaint boundsPaint;
529 boundsPaint.setColor(0xff808080);
530 boundsPaint.setStrokeWidth(0);
531 boundsPaint.setStyle(SkPaint::kStroke_Style);
532 canvas->drawRect(bounds, boundsPaint);
533
robertphillips28a838e2016-06-23 14:07:00 -0700534 GrPaint grPaint;
Mike Reed7d954ad2016-10-28 15:42:34 -0400535 grPaint.setXPFactory(GrPorterDuffXPFactory::Make(SkBlendMode::kSrc));
joshualitt3f284d72015-02-11 11:34:58 -0800536
joshualitt95964c62015-02-11 13:45:50 -0800537 GrPathUtils::QuadUVMatrix DevToUV(pts);
538
Hal Canarycefc4312016-11-04 16:26:16 -0400539 sk_sp<GrDrawBatch> batch(new BezierQuadTestBatch(gp, bounds, color, DevToUV));
joshualitt95964c62015-02-11 13:45:50 -0800540
Hal Canarycefc4312016-11-04 16:26:16 -0400541 renderTargetContext->priv().testingOnly_drawBatch(grPaint, batch.get());
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000542 }
543 ++col;
544 if (numCols == col) {
545 col = 0;
546 ++row;
547 }
548 }
549 }
550 }
551
552private:
553 typedef GM INHERITED;
554};
555
halcanary385fe4d2015-08-26 13:07:48 -0700556DEF_GM(return new BezierCubicEffects;)
557DEF_GM(return new BezierConicEffects;)
558DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000559}
560
561#endif