blob: e529ded76f3b38c16cafa491319b11592f472a7c [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
Brian Salomon89527432016-12-16 09:52:16 -050021#include "ops/GrTestMeshDrawOp.h"
joshualitt2771b562015-08-07 12:46:26 -070022
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
Brian Salomon6b316e92016-12-16 09:35:49 -050031class BezierCubicOrConicTestOp : public GrTestMeshDrawOp {
joshualitt95964c62015-02-11 13:45:50 -080032public:
Brian Salomon25a88092016-12-01 09:36:50 -050033 DEFINE_OP_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -080034
Brian Salomon6b316e92016-12-16 09:35:49 -050035 const char* name() const override { return "BezierCubicOrConicTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -080036
Brian Salomon6b316e92016-12-16 09:35:49 -050037 static sk_sp<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& bounds, GrColor color,
38 const SkScalar klmEqs[9], SkScalar sign) {
39 return sk_sp<GrDrawOp>(new BezierCubicOrConicTestOp(gp, bounds, color, klmEqs, sign));
40 }
41
42private:
43 BezierCubicOrConicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& bounds, GrColor color,
44 const SkScalar klmEqs[9], SkScalar sign)
45 : INHERITED(ClassID(), bounds, color), fGeometryProcessor(std::move(gp)) {
joshualitt95964c62015-02-11 13:45:50 -080046 for (int i = 0; i < 9; i++) {
47 fKlmEqs[i] = klmEqs[i];
48 }
joshualitt95964c62015-02-11 13:45:50 -080049 fSign = sign;
50 }
joshualitt95964c62015-02-11 13:45:50 -080051 struct Vertex {
52 SkPoint fPosition;
53 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
54 };
55
bsalomon342bfc22016-04-01 06:06:20 -070056 void onPrepareDraws(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -070057 QuadHelper helper;
bsalomon342bfc22016-04-01 06:06:20 -070058 size_t vertexStride = fGeometryProcessor->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -070059 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -070060 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -070061 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -080062 return;
63 }
bsalomon342bfc22016-04-01 06:06:20 -070064 const SkRect& bounds = this->bounds();
65 verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom,
joshualitt95964c62015-02-11 13:45:50 -080066 sizeof(Vertex));
67 for (int v = 0; v < 4; ++v) {
68 verts[v].fKLM[0] = eval_line(verts[v].fPosition, fKlmEqs + 0, fSign);
69 verts[v].fKLM[1] = eval_line(verts[v].fPosition, fKlmEqs + 3, fSign);
70 verts[v].fKLM[2] = eval_line(verts[v].fPosition, fKlmEqs + 6, 1.f);
71 }
bungeman06ca8ec2016-06-09 08:01:03 -070072 helper.recordDraw(target, fGeometryProcessor.get());
joshualitt95964c62015-02-11 13:45:50 -080073 }
74
bungeman06ca8ec2016-06-09 08:01:03 -070075 SkScalar fKlmEqs[9];
76 SkScalar fSign;
77 sk_sp<GrGeometryProcessor> fGeometryProcessor;
joshualitt95964c62015-02-11 13:45:50 -080078
mtkleindbfd7ab2016-09-01 11:24:54 -070079 static constexpr int kVertsPerCubic = 4;
80 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -080081
Brian Salomon6b316e92016-12-16 09:35:49 -050082 typedef GrTestMeshDrawOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -080083};
84
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000085/**
86 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
87 */
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000088class BezierCubicEffects : public GM {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000089public:
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000090 BezierCubicEffects() {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000091 this->setBGColor(0xFFFFFFFF);
92 }
93
94protected:
mtklein36352bf2015-03-25 18:17:31 -070095 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000096 return SkString("bezier_cubic_effects");
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000097 }
98
mtklein36352bf2015-03-25 18:17:31 -070099 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700100 return SkISize::Make(800, 800);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000101 }
102
mtklein36352bf2015-03-25 18:17:31 -0700103 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400104 GrRenderTargetContext* renderTargetContext =
105 canvas->internal_private_accessTopLayerRenderTargetContext();
106 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700107 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000108 return;
109 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000110
robertphillips175dd9b2016-04-28 14:32:04 -0700111 GrContext* context = canvas->getGrContext();
112 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800113 return;
114 }
115
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000116 struct Vertex {
117 SkPoint fPosition;
118 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
119 };
120
mtkleindbfd7ab2016-09-01 11:24:54 -0700121 constexpr int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000122 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000123
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000124 // Mult by 3 for each edge effect type
125 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
126 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400127 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
128 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000129 int row = 0;
130 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700131 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000132
133 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000134 SkPoint baseControlPts[] = {
135 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
136 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
137 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
138 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000139 };
joshualittb0a8a372014-09-23 09:50:21 -0700140 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700141 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800142 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700143 gp = GrCubicEffect::Make(color, SkMatrix::I(), et, *context->caps());
joshualittf5883a62016-01-13 07:47:38 -0800144 if (!gp) {
145 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000146 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000147 SkScalar x = SkScalarMul(col, w);
148 SkScalar y = SkScalarMul(row, h);
149 SkPoint controlPts[] = {
150 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
151 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
152 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
153 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
154 };
155 SkPoint chopped[10];
156 SkScalar klmEqs[9];
157 SkScalar klmSigns[3];
158 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
159 chopped,
160 klmEqs,
161 klmSigns);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000162
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000163 SkPaint ctrlPtPaint;
164 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000165 for (int i = 0; i < 4; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000166 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000167 }
168
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000169 SkPaint polyPaint;
170 polyPaint.setColor(0xffA0A0A0);
171 polyPaint.setStrokeWidth(0);
172 polyPaint.setStyle(SkPaint::kStroke_Style);
173 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000174
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000175 SkPaint choppedPtPaint;
176 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000177
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000178 for (int c = 0; c < cnt; ++c) {
179 SkPoint* pts = chopped + 3 * c;
180
181 for (int i = 0; i < 4; ++i) {
182 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
183 }
184
185 SkRect bounds;
186 bounds.set(pts, 4);
187
188 SkPaint boundsPaint;
189 boundsPaint.setColor(0xff808080);
190 boundsPaint.setStrokeWidth(0);
191 boundsPaint.setStyle(SkPaint::kStroke_Style);
192 canvas->drawRect(bounds, boundsPaint);
193
robertphillips28a838e2016-06-23 14:07:00 -0700194 GrPaint grPaint;
Mike Reed7d954ad2016-10-28 15:42:34 -0400195 grPaint.setXPFactory(GrPorterDuffXPFactory::Make(SkBlendMode::kSrc));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000196
Brian Salomon6b316e92016-12-16 09:35:49 -0500197 sk_sp<GrDrawOp> op =
198 BezierCubicOrConicTestOp::Make(gp, bounds, color, klmEqs, klmSigns[c]);
joshualitt95964c62015-02-11 13:45:50 -0800199
Brian Salomon1951f3d2016-12-09 16:07:12 -0500200 renderTargetContext->priv().testingOnly_addDrawOp(grPaint, GrAAType::kNone,
201 std::move(op));
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000202 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000203 ++col;
204 if (numCols == col) {
205 col = 0;
206 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000207 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000208 }
209 }
210 }
211
212private:
213 typedef GM INHERITED;
214};
215
216//////////////////////////////////////////////////////////////////////////////
217
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000218/**
219 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
220 */
221class BezierConicEffects : public GM {
222public:
223 BezierConicEffects() {
224 this->setBGColor(0xFFFFFFFF);
225 }
226
227protected:
mtklein36352bf2015-03-25 18:17:31 -0700228 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000229 return SkString("bezier_conic_effects");
230 }
231
mtklein36352bf2015-03-25 18:17:31 -0700232 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700233 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000234 }
235
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000236
mtklein36352bf2015-03-25 18:17:31 -0700237 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400238 GrRenderTargetContext* renderTargetContext =
239 canvas->internal_private_accessTopLayerRenderTargetContext();
240 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700241 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000242 return;
243 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000244
robertphillips175dd9b2016-04-28 14:32:04 -0700245 GrContext* context = canvas->getGrContext();
246 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800247 return;
248 }
249
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000250 struct Vertex {
251 SkPoint fPosition;
252 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
253 };
254
mtkleindbfd7ab2016-09-01 11:24:54 -0700255 constexpr int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000256 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000257
258 // Mult by 3 for each edge effect type
259 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
260 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400261 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
262 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000263 int row = 0;
264 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700265 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000266
267 for (int i = 0; i < kNumConics; ++i) {
268 SkPoint baseControlPts[] = {
269 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
270 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
271 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
272 };
273 SkScalar weight = rand.nextRangeF(0.f, 2.f);
joshualittb0a8a372014-09-23 09:50:21 -0700274 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700275 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800276 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700277 gp = GrConicEffect::Make(color, SkMatrix::I(), et,
278 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800279 if (!gp) {
280 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000281 }
282
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000283 SkScalar x = SkScalarMul(col, w);
284 SkScalar y = SkScalarMul(row, h);
285 SkPoint controlPts[] = {
286 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
287 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
288 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
289 };
290 SkConic dst[4];
291 SkScalar klmEqs[9];
292 int cnt = chop_conic(controlPts, dst, weight);
293 GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
294
295 SkPaint ctrlPtPaint;
296 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
297 for (int i = 0; i < 3; ++i) {
298 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
299 }
300
301 SkPaint polyPaint;
302 polyPaint.setColor(0xffA0A0A0);
303 polyPaint.setStrokeWidth(0);
304 polyPaint.setStyle(SkPaint::kStroke_Style);
305 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
306
307 SkPaint choppedPtPaint;
308 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
309
310 for (int c = 0; c < cnt; ++c) {
311 SkPoint* pts = dst[c].fPts;
312 for (int i = 0; i < 3; ++i) {
313 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
314 }
315
316 SkRect bounds;
317 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
318 //bounds.set(bPts, 2);
319 bounds.set(pts, 3);
320
321 SkPaint boundsPaint;
322 boundsPaint.setColor(0xff808080);
323 boundsPaint.setStrokeWidth(0);
324 boundsPaint.setStyle(SkPaint::kStroke_Style);
325 canvas->drawRect(bounds, boundsPaint);
326
robertphillips28a838e2016-06-23 14:07:00 -0700327 GrPaint grPaint;
Mike Reed7d954ad2016-10-28 15:42:34 -0400328 grPaint.setXPFactory(GrPorterDuffXPFactory::Make(SkBlendMode::kSrc));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000329
Brian Salomon6b316e92016-12-16 09:35:49 -0500330 sk_sp<GrDrawOp> op =
331 BezierCubicOrConicTestOp::Make(gp, bounds, color, klmEqs, 1.f);
joshualitt95964c62015-02-11 13:45:50 -0800332
Brian Salomon1951f3d2016-12-09 16:07:12 -0500333 renderTargetContext->priv().testingOnly_addDrawOp(grPaint, GrAAType::kNone,
334 std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000335 }
336 ++col;
337 if (numCols == col) {
338 col = 0;
339 ++row;
340 }
341 }
342 }
343 }
344
345private:
346 // Uses the max curvature function for quads to estimate
347 // where to chop the conic. If the max curvature is not
348 // found along the curve segment it will return 1 and
349 // dst[0] is the original conic. If it returns 2 the dst[0]
350 // and dst[1] are the two new conics.
351 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
352 SkScalar t = SkFindQuadMaxCurvature(src);
353 if (t == 0) {
354 if (dst) {
355 dst[0].set(src, weight);
356 }
357 return 1;
358 } else {
359 if (dst) {
360 SkConic conic;
361 conic.set(src, weight);
caryclark414c4292016-09-26 11:03:54 -0700362 if (!conic.chopAt(t, dst)) {
363 dst[0].set(src, weight);
364 return 1;
365 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000366 }
367 return 2;
368 }
369 }
370
371 // Calls split_conic on the entire conic and then once more on each subsection.
372 // Most cases will result in either 1 conic (chop point is not within t range)
373 // or 3 points (split once and then one subsection is split again).
374 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
375 SkConic dstTemp[2];
376 int conicCnt = split_conic(src, dstTemp, weight);
377 if (2 == conicCnt) {
378 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
379 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
380 } else {
381 dst[0] = dstTemp[0];
382 }
383 return conicCnt;
384 }
385
386 typedef GM INHERITED;
387};
388
389//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800390
Brian Salomon6b316e92016-12-16 09:35:49 -0500391class BezierQuadTestOp : public GrTestMeshDrawOp {
joshualitt95964c62015-02-11 13:45:50 -0800392public:
Brian Salomon25a88092016-12-01 09:36:50 -0500393 DEFINE_OP_CLASS_ID
Brian Salomon6b316e92016-12-16 09:35:49 -0500394 const char* name() const override { return "BezierQuadTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -0800395
Brian Salomon6b316e92016-12-16 09:35:49 -0500396 static sk_sp<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& bounds, GrColor color,
397 const GrPathUtils::QuadUVMatrix& devToUV) {
398 return sk_sp<GrDrawOp>(new BezierQuadTestOp(gp, bounds, color, devToUV));
joshualitt95964c62015-02-11 13:45:50 -0800399 }
400
401private:
Brian Salomon6b316e92016-12-16 09:35:49 -0500402 BezierQuadTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& bounds, GrColor color,
403 const GrPathUtils::QuadUVMatrix& devToUV)
404 : INHERITED(ClassID(), bounds, color)
405 , fDevToUV(devToUV)
406 , fGeometryProcessor(std::move(gp)) {}
joshualitt95964c62015-02-11 13:45:50 -0800407
408 struct Vertex {
409 SkPoint fPosition;
410 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
411 };
412
bsalomon342bfc22016-04-01 06:06:20 -0700413 void onPrepareDraws(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -0700414 QuadHelper helper;
bsalomon342bfc22016-04-01 06:06:20 -0700415 size_t vertexStride = fGeometryProcessor->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700416 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700417 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700418 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800419 return;
420 }
bsalomon342bfc22016-04-01 06:06:20 -0700421 const SkRect& bounds = this->bounds();
422 verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom,
joshualitt95964c62015-02-11 13:45:50 -0800423 sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800424 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
bungeman06ca8ec2016-06-09 08:01:03 -0700425 helper.recordDraw(target, fGeometryProcessor.get());
joshualitt95964c62015-02-11 13:45:50 -0800426 }
427
bungeman06ca8ec2016-06-09 08:01:03 -0700428 GrPathUtils::QuadUVMatrix fDevToUV;
429 sk_sp<GrGeometryProcessor> fGeometryProcessor;
joshualitt95964c62015-02-11 13:45:50 -0800430
mtkleindbfd7ab2016-09-01 11:24:54 -0700431 static constexpr int kVertsPerCubic = 4;
432 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800433
Brian Salomon6b316e92016-12-16 09:35:49 -0500434 typedef GrTestMeshDrawOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800435};
436
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000437/**
438 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
439 */
440class BezierQuadEffects : public GM {
441public:
442 BezierQuadEffects() {
443 this->setBGColor(0xFFFFFFFF);
444 }
445
446protected:
mtklein36352bf2015-03-25 18:17:31 -0700447 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000448 return SkString("bezier_quad_effects");
449 }
450
mtklein36352bf2015-03-25 18:17:31 -0700451 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700452 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000453 }
454
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000455
mtklein36352bf2015-03-25 18:17:31 -0700456 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400457 GrRenderTargetContext* renderTargetContext =
458 canvas->internal_private_accessTopLayerRenderTargetContext();
459 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700460 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000461 return;
462 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000463
robertphillips175dd9b2016-04-28 14:32:04 -0700464 GrContext* context = canvas->getGrContext();
465 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800466 return;
467 }
468
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000469 struct Vertex {
470 SkPoint fPosition;
471 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
472 };
473
mtkleindbfd7ab2016-09-01 11:24:54 -0700474 constexpr int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000475 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000476
477 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
478 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400479 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
480 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000481 int row = 0;
482 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700483 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000484
485 for (int i = 0; i < kNumQuads; ++i) {
486 SkPoint baseControlPts[] = {
487 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
488 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
489 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
490 };
joshualittb0a8a372014-09-23 09:50:21 -0700491 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700492 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800493 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700494 gp = GrQuadEffect::Make(color, SkMatrix::I(), et,
495 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800496 if (!gp) {
497 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000498 }
499
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000500 SkScalar x = SkScalarMul(col, w);
501 SkScalar y = SkScalarMul(row, h);
502 SkPoint controlPts[] = {
503 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
504 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
505 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
506 };
507 SkPoint chopped[5];
508 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
509
510 SkPaint ctrlPtPaint;
511 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
512 for (int i = 0; i < 3; ++i) {
513 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
514 }
515
516 SkPaint polyPaint;
517 polyPaint.setColor(0xffA0A0A0);
518 polyPaint.setStrokeWidth(0);
519 polyPaint.setStyle(SkPaint::kStroke_Style);
520 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
521
522 SkPaint choppedPtPaint;
523 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
524
525 for (int c = 0; c < cnt; ++c) {
526 SkPoint* pts = chopped + 2 * c;
527
528 for (int i = 0; i < 3; ++i) {
529 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
530 }
531
532 SkRect bounds;
533 bounds.set(pts, 3);
534
535 SkPaint boundsPaint;
536 boundsPaint.setColor(0xff808080);
537 boundsPaint.setStrokeWidth(0);
538 boundsPaint.setStyle(SkPaint::kStroke_Style);
539 canvas->drawRect(bounds, boundsPaint);
540
robertphillips28a838e2016-06-23 14:07:00 -0700541 GrPaint grPaint;
Mike Reed7d954ad2016-10-28 15:42:34 -0400542 grPaint.setXPFactory(GrPorterDuffXPFactory::Make(SkBlendMode::kSrc));
joshualitt3f284d72015-02-11 11:34:58 -0800543
joshualitt95964c62015-02-11 13:45:50 -0800544 GrPathUtils::QuadUVMatrix DevToUV(pts);
545
Brian Salomon6b316e92016-12-16 09:35:49 -0500546 sk_sp<GrDrawOp> op = BezierQuadTestOp::Make(gp, bounds, color, DevToUV);
joshualitt95964c62015-02-11 13:45:50 -0800547
Brian Salomon1951f3d2016-12-09 16:07:12 -0500548 renderTargetContext->priv().testingOnly_addDrawOp(grPaint, GrAAType::kNone,
549 std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000550 }
551 ++col;
552 if (numCols == col) {
553 col = 0;
554 ++row;
555 }
556 }
557 }
558 }
559
560private:
561 typedef GM INHERITED;
562};
563
halcanary385fe4d2015-08-26 13:07:48 -0700564DEF_GM(return new BezierCubicEffects;)
565DEF_GM(return new BezierConicEffects;)
566DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000567}
568
569#endif