blob: 77f86c5ea49f63a3c4166bd171b5ab1f69ebc769 [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
14#include "GrContext.h"
Brian Salomon477d0ef2017-07-14 10:12:26 -040015#include "GrOpFlushState.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000016#include "GrPathUtils.h"
Brian Salomon477d0ef2017-07-14 10:12:26 -040017#include "GrRenderTargetContextPriv.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000018#include "GrTest.h"
19#include "SkColorPriv.h"
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000020#include "SkGeometry.h"
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000021#include "effects/GrBezierEffect.h"
Brian Salomon477d0ef2017-07-14 10:12:26 -040022#include "ops/GrMeshDrawOp.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000023
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000024namespace skiagm {
joshualitt95964c62015-02-11 13:45:50 -080025
Brian Salomon477d0ef2017-07-14 10:12:26 -040026class BezierTestOp : public GrMeshDrawOp {
27public:
28 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
29
30 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
31 auto analysis = fProcessorSet.finalize(fColor, GrProcessorAnalysisCoverage::kSingleChannel,
32 clip, false, caps, &fColor);
33 return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo;
34 }
35
36protected:
37 BezierTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color, int32_t classID)
38 : INHERITED(classID)
39 , fRect(rect)
40 , fColor(color)
41 , fGeometryProcessor(std::move(gp))
42 , fProcessorSet(SkBlendMode::kSrc) {
43 this->setBounds(rect, HasAABloat::kYes, IsZeroArea::kNo);
44 }
45
46 const GrPipeline* makePipeline(Target* target) const {
47 return target->makePipeline(0, &fProcessorSet);
48 }
49
50 const GrGeometryProcessor* gp() const { return fGeometryProcessor.get(); }
51
52 const SkRect& rect() const { return fRect; }
53 GrColor color() const { return fColor; }
54
55private:
56 bool onCombineIfPossible(GrOp* op, const GrCaps& caps) override { return false; }
57
58 SkRect fRect;
59 GrColor fColor;
60 sk_sp<GrGeometryProcessor> fGeometryProcessor;
61 GrProcessorSet fProcessorSet;
62
63 typedef GrMeshDrawOp INHERITED;
64};
65
66class BezierCubicTestOp : public BezierTestOp {
joshualitt95964c62015-02-11 13:45:50 -080067public:
Brian Salomon25a88092016-12-01 09:36:50 -050068 DEFINE_OP_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -080069
Chris Daltonfebbffa2017-06-08 13:12:02 -060070 const char* name() const override { return "BezierCubicTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -080071
Brian Salomon477d0ef2017-07-14 10:12:26 -040072 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
73 GrColor color) {
74 return std::unique_ptr<GrDrawOp>(new BezierCubicTestOp(std::move(gp), rect, color));
Brian Salomon6b316e92016-12-16 09:35:49 -050075 }
76
77private:
Chris Daltonfebbffa2017-06-08 13:12:02 -060078 BezierCubicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color)
Brian Salomon477d0ef2017-07-14 10:12:26 -040079 : INHERITED(std::move(gp), rect, color, ClassID()) {}
joshualitt95964c62015-02-11 13:45:50 -080080
bsalomon342bfc22016-04-01 06:06:20 -070081 void onPrepareDraws(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -070082 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -040083 size_t vertexStride = this->gp()->getVertexStride();
Chris Daltonfebbffa2017-06-08 13:12:02 -060084 SkASSERT(vertexStride == sizeof(SkPoint));
85 SkPoint* pts = reinterpret_cast<SkPoint*>(helper.init(target, vertexStride, 1));
86 if (!pts) {
joshualitt4b31de82015-03-05 14:33:41 -080087 return;
88 }
Brian Salomon477d0ef2017-07-14 10:12:26 -040089 SkRect rect = this->rect();
90 pts[0].setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
91 helper.recordDraw(target, this->gp(), this->makePipeline(target));
joshualitt95964c62015-02-11 13:45:50 -080092 }
93
mtkleindbfd7ab2016-09-01 11:24:54 -070094 static constexpr int kVertsPerCubic = 4;
95 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -080096
Brian Salomon477d0ef2017-07-14 10:12:26 -040097 typedef BezierTestOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -080098};
99
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000100/**
101 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
102 */
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000103class BezierCubicEffects : public GM {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000104public:
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000105 BezierCubicEffects() {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000106 this->setBGColor(0xFFFFFFFF);
107 }
108
109protected:
mtklein36352bf2015-03-25 18:17:31 -0700110 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000111 return SkString("bezier_cubic_effects");
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000112 }
113
mtklein36352bf2015-03-25 18:17:31 -0700114 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700115 return SkISize::Make(800, 800);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000116 }
117
mtklein36352bf2015-03-25 18:17:31 -0700118 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400119 GrRenderTargetContext* renderTargetContext =
120 canvas->internal_private_accessTopLayerRenderTargetContext();
121 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700122 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000123 return;
124 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000125
robertphillips175dd9b2016-04-28 14:32:04 -0700126 GrContext* context = canvas->getGrContext();
127 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800128 return;
129 }
130
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000131 struct Vertex {
132 SkPoint fPosition;
133 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
134 };
135
mtkleindbfd7ab2016-09-01 11:24:54 -0700136 constexpr int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000137 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000138
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000139 // Mult by 3 for each edge effect type
140 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
141 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400142 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
143 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000144 int row = 0;
145 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700146 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000147
148 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000149 SkPoint baseControlPts[] = {
150 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
151 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
152 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
153 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000154 };
Chris Daltonfebbffa2017-06-08 13:12:02 -0600155 for(GrPrimitiveEdgeType edgeType : {kFillBW_GrProcessorEdgeType,
156 kFillAA_GrProcessorEdgeType,
157 kHairlineAA_GrProcessorEdgeType}) {
Mike Reeddf85c382017-02-14 10:59:19 -0500158 SkScalar x = col * w;
159 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000160 SkPoint controlPts[] = {
161 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
162 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
163 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
164 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
165 };
166 SkPoint chopped[10];
csmartdaltoncc261272017-03-23 13:38:45 -0600167 SkMatrix klm;
Greg Daniel8199d942017-03-14 10:20:24 -0400168 int loopIndex;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000169 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
170 chopped,
csmartdaltoncc261272017-03-23 13:38:45 -0600171 &klm,
Greg Daniel8199d942017-03-14 10:20:24 -0400172 &loopIndex);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000173
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000174 SkPaint ctrlPtPaint;
175 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
Hal Canary23e474c2017-05-15 13:35:35 -0400176 canvas->drawCircle(controlPts[0], 8.f, ctrlPtPaint);
Greg Daniel8199d942017-03-14 10:20:24 -0400177 for (int i = 1; i < 4; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400178 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000179 }
180
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000181 SkPaint polyPaint;
182 polyPaint.setColor(0xffA0A0A0);
183 polyPaint.setStrokeWidth(0);
184 polyPaint.setStyle(SkPaint::kStroke_Style);
185 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000186
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000187 SkPaint choppedPtPaint;
188 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000189
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000190 for (int c = 0; c < cnt; ++c) {
191 SkPoint* pts = chopped + 3 * c;
192
193 for (int i = 0; i < 4; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400194 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000195 }
196
197 SkRect bounds;
198 bounds.set(pts, 4);
199
200 SkPaint boundsPaint;
201 boundsPaint.setColor(0xff808080);
202 boundsPaint.setStrokeWidth(0);
203 boundsPaint.setStyle(SkPaint::kStroke_Style);
204 canvas->drawRect(bounds, boundsPaint);
205
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000206
Chris Daltonfebbffa2017-06-08 13:12:02 -0600207 bool flipKL = (c == loopIndex && cnt != 3);
208 sk_sp<GrGeometryProcessor> gp = GrCubicEffect::Make(color, SkMatrix::I(), klm,
209 flipKL, edgeType,
210 *context->caps());
211 if (!gp) {
212 break;
Greg Daniel8199d942017-03-14 10:20:24 -0400213 }
214
Brian Salomon477d0ef2017-07-14 10:12:26 -0400215 std::unique_ptr<GrDrawOp> op =
Chris Daltonfebbffa2017-06-08 13:12:02 -0600216 BezierCubicTestOp::Make(std::move(gp), bounds, color);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400217 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000218 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000219 ++col;
220 if (numCols == col) {
221 col = 0;
222 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000223 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000224 }
225 }
226 }
227
228private:
229 typedef GM INHERITED;
230};
231
232//////////////////////////////////////////////////////////////////////////////
233
Brian Salomon477d0ef2017-07-14 10:12:26 -0400234class BezierConicTestOp : public BezierTestOp {
Chris Daltonfebbffa2017-06-08 13:12:02 -0600235public:
236 DEFINE_OP_CLASS_ID
237
238 const char* name() const override { return "BezierConicTestOp"; }
239
Brian Salomon477d0ef2017-07-14 10:12:26 -0400240 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
241 GrColor color, const SkMatrix& klm) {
242 return std::unique_ptr<GrMeshDrawOp>(
243 new BezierConicTestOp(std::move(gp), rect, color, klm));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600244 }
245
246private:
247 BezierConicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
248 const SkMatrix& klm)
Brian Salomon477d0ef2017-07-14 10:12:26 -0400249 : INHERITED(std::move(gp), rect, color, ClassID()), fKLM(klm) {}
250
Chris Daltonfebbffa2017-06-08 13:12:02 -0600251 struct Vertex {
252 SkPoint fPosition;
253 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
254 };
255
256 void onPrepareDraws(Target* target) const override {
257 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -0400258 size_t vertexStride = this->gp()->getVertexStride();
Chris Daltonfebbffa2017-06-08 13:12:02 -0600259 SkASSERT(vertexStride == sizeof(Vertex));
260 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
261 if (!verts) {
262 return;
263 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400264 SkRect rect = this->rect();
265 verts[0].fPosition.setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
Chris Daltonfebbffa2017-06-08 13:12:02 -0600266 sizeof(Vertex));
267 for (int v = 0; v < 4; ++v) {
268 SkScalar pt3[3] = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
269 fKLM.mapHomogeneousPoints(verts[v].fKLM, pt3, 1);
270 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400271 helper.recordDraw(target, this->gp(), this->makePipeline(target));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600272 }
273
274 SkMatrix fKLM;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600275
276 static constexpr int kVertsPerCubic = 4;
277 static constexpr int kIndicesPerCubic = 6;
278
Brian Salomon477d0ef2017-07-14 10:12:26 -0400279 typedef BezierTestOp INHERITED;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600280};
281
282
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000283/**
284 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
285 */
286class BezierConicEffects : public GM {
287public:
288 BezierConicEffects() {
289 this->setBGColor(0xFFFFFFFF);
290 }
291
292protected:
mtklein36352bf2015-03-25 18:17:31 -0700293 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000294 return SkString("bezier_conic_effects");
295 }
296
mtklein36352bf2015-03-25 18:17:31 -0700297 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700298 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000299 }
300
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000301
mtklein36352bf2015-03-25 18:17:31 -0700302 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400303 GrRenderTargetContext* renderTargetContext =
304 canvas->internal_private_accessTopLayerRenderTargetContext();
305 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700306 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000307 return;
308 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000309
robertphillips175dd9b2016-04-28 14:32:04 -0700310 GrContext* context = canvas->getGrContext();
311 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800312 return;
313 }
314
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000315 struct Vertex {
316 SkPoint fPosition;
317 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
318 };
319
mtkleindbfd7ab2016-09-01 11:24:54 -0700320 constexpr int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000321 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000322
323 // Mult by 3 for each edge effect type
324 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
325 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400326 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
327 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000328 int row = 0;
329 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700330 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000331
332 for (int i = 0; i < kNumConics; ++i) {
333 SkPoint baseControlPts[] = {
334 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
335 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
336 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
337 };
338 SkScalar weight = rand.nextRangeF(0.f, 2.f);
joshualittb0a8a372014-09-23 09:50:21 -0700339 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700340 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800341 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700342 gp = GrConicEffect::Make(color, SkMatrix::I(), et,
343 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800344 if (!gp) {
345 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000346 }
347
Mike Reeddf85c382017-02-14 10:59:19 -0500348 SkScalar x = col * w;
349 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000350 SkPoint controlPts[] = {
351 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
352 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
353 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
354 };
355 SkConic dst[4];
csmartdaltoncc261272017-03-23 13:38:45 -0600356 SkMatrix klm;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000357 int cnt = chop_conic(controlPts, dst, weight);
csmartdaltoncc261272017-03-23 13:38:45 -0600358 GrPathUtils::getConicKLM(controlPts, weight, &klm);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000359
360 SkPaint ctrlPtPaint;
361 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
362 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400363 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000364 }
365
366 SkPaint polyPaint;
367 polyPaint.setColor(0xffA0A0A0);
368 polyPaint.setStrokeWidth(0);
369 polyPaint.setStyle(SkPaint::kStroke_Style);
370 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
371
372 SkPaint choppedPtPaint;
373 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
374
375 for (int c = 0; c < cnt; ++c) {
376 SkPoint* pts = dst[c].fPts;
377 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400378 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000379 }
380
381 SkRect bounds;
382 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
383 //bounds.set(bPts, 2);
384 bounds.set(pts, 3);
385
386 SkPaint boundsPaint;
387 boundsPaint.setColor(0xff808080);
388 boundsPaint.setStrokeWidth(0);
389 boundsPaint.setStyle(SkPaint::kStroke_Style);
390 canvas->drawRect(bounds, boundsPaint);
391
Brian Salomon477d0ef2017-07-14 10:12:26 -0400392 std::unique_ptr<GrDrawOp> op = BezierConicTestOp::Make(gp, bounds, color, klm);
393 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000394 }
395 ++col;
396 if (numCols == col) {
397 col = 0;
398 ++row;
399 }
400 }
401 }
402 }
403
404private:
405 // Uses the max curvature function for quads to estimate
406 // where to chop the conic. If the max curvature is not
407 // found along the curve segment it will return 1 and
408 // dst[0] is the original conic. If it returns 2 the dst[0]
409 // and dst[1] are the two new conics.
410 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
411 SkScalar t = SkFindQuadMaxCurvature(src);
412 if (t == 0) {
413 if (dst) {
414 dst[0].set(src, weight);
415 }
416 return 1;
417 } else {
418 if (dst) {
419 SkConic conic;
420 conic.set(src, weight);
caryclark414c4292016-09-26 11:03:54 -0700421 if (!conic.chopAt(t, dst)) {
422 dst[0].set(src, weight);
423 return 1;
424 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000425 }
426 return 2;
427 }
428 }
429
430 // Calls split_conic on the entire conic and then once more on each subsection.
431 // Most cases will result in either 1 conic (chop point is not within t range)
432 // or 3 points (split once and then one subsection is split again).
433 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
434 SkConic dstTemp[2];
435 int conicCnt = split_conic(src, dstTemp, weight);
436 if (2 == conicCnt) {
437 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
438 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
439 } else {
440 dst[0] = dstTemp[0];
441 }
442 return conicCnt;
443 }
444
445 typedef GM INHERITED;
446};
447
448//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800449
Brian Salomon477d0ef2017-07-14 10:12:26 -0400450class BezierQuadTestOp : public BezierTestOp {
joshualitt95964c62015-02-11 13:45:50 -0800451public:
Brian Salomon25a88092016-12-01 09:36:50 -0500452 DEFINE_OP_CLASS_ID
Brian Salomon6b316e92016-12-16 09:35:49 -0500453 const char* name() const override { return "BezierQuadTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -0800454
Brian Salomon477d0ef2017-07-14 10:12:26 -0400455 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
456 GrColor color, const GrPathUtils::QuadUVMatrix& devToUV) {
457 return std::unique_ptr<GrDrawOp>(new BezierQuadTestOp(std::move(gp), rect, color, devToUV));
joshualitt95964c62015-02-11 13:45:50 -0800458 }
459
460private:
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500461 BezierQuadTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
Brian Salomon6b316e92016-12-16 09:35:49 -0500462 const GrPathUtils::QuadUVMatrix& devToUV)
Brian Salomon477d0ef2017-07-14 10:12:26 -0400463 : INHERITED(std::move(gp), rect, color, ClassID()), fDevToUV(devToUV) {}
joshualitt95964c62015-02-11 13:45:50 -0800464
465 struct Vertex {
466 SkPoint fPosition;
467 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
468 };
469
bsalomon342bfc22016-04-01 06:06:20 -0700470 void onPrepareDraws(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -0700471 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -0400472 size_t vertexStride = this->gp()->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700473 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700474 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700475 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800476 return;
477 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400478 SkRect rect = this->rect();
479 verts[0].fPosition.setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
joshualitt95964c62015-02-11 13:45:50 -0800480 sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800481 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400482 helper.recordDraw(target, this->gp(), this->makePipeline(target));
joshualitt95964c62015-02-11 13:45:50 -0800483 }
484
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500485 GrPathUtils::QuadUVMatrix fDevToUV;
joshualitt95964c62015-02-11 13:45:50 -0800486
mtkleindbfd7ab2016-09-01 11:24:54 -0700487 static constexpr int kVertsPerCubic = 4;
488 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800489
Brian Salomon477d0ef2017-07-14 10:12:26 -0400490 typedef BezierTestOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800491};
492
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000493/**
494 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
495 */
496class BezierQuadEffects : public GM {
497public:
498 BezierQuadEffects() {
499 this->setBGColor(0xFFFFFFFF);
500 }
501
502protected:
mtklein36352bf2015-03-25 18:17:31 -0700503 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000504 return SkString("bezier_quad_effects");
505 }
506
mtklein36352bf2015-03-25 18:17:31 -0700507 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700508 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000509 }
510
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000511
mtklein36352bf2015-03-25 18:17:31 -0700512 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400513 GrRenderTargetContext* renderTargetContext =
514 canvas->internal_private_accessTopLayerRenderTargetContext();
515 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700516 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000517 return;
518 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000519
robertphillips175dd9b2016-04-28 14:32:04 -0700520 GrContext* context = canvas->getGrContext();
521 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800522 return;
523 }
524
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000525 struct Vertex {
526 SkPoint fPosition;
527 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
528 };
529
mtkleindbfd7ab2016-09-01 11:24:54 -0700530 constexpr int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000531 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000532
533 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
534 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400535 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
536 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000537 int row = 0;
538 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700539 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000540
541 for (int i = 0; i < kNumQuads; ++i) {
542 SkPoint baseControlPts[] = {
543 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
544 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
545 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
546 };
joshualittb0a8a372014-09-23 09:50:21 -0700547 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700548 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800549 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700550 gp = GrQuadEffect::Make(color, SkMatrix::I(), et,
551 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800552 if (!gp) {
553 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000554 }
555
Mike Reeddf85c382017-02-14 10:59:19 -0500556 SkScalar x = col * w;
557 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000558 SkPoint controlPts[] = {
559 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
560 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
561 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
562 };
563 SkPoint chopped[5];
564 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
565
566 SkPaint ctrlPtPaint;
567 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
568 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400569 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000570 }
571
572 SkPaint polyPaint;
573 polyPaint.setColor(0xffA0A0A0);
574 polyPaint.setStrokeWidth(0);
575 polyPaint.setStyle(SkPaint::kStroke_Style);
576 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
577
578 SkPaint choppedPtPaint;
579 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
580
581 for (int c = 0; c < cnt; ++c) {
582 SkPoint* pts = chopped + 2 * c;
583
584 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400585 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000586 }
587
588 SkRect bounds;
589 bounds.set(pts, 3);
590
591 SkPaint boundsPaint;
592 boundsPaint.setColor(0xff808080);
593 boundsPaint.setStrokeWidth(0);
594 boundsPaint.setStyle(SkPaint::kStroke_Style);
595 canvas->drawRect(bounds, boundsPaint);
596
robertphillips28a838e2016-06-23 14:07:00 -0700597 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500598 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
joshualitt3f284d72015-02-11 11:34:58 -0800599
joshualitt95964c62015-02-11 13:45:50 -0800600 GrPathUtils::QuadUVMatrix DevToUV(pts);
601
Brian Salomon477d0ef2017-07-14 10:12:26 -0400602 std::unique_ptr<GrDrawOp> op =
Brian Salomonf8334782017-01-03 09:42:58 -0500603 BezierQuadTestOp::Make(gp, bounds, color, DevToUV);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400604 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000605 }
606 ++col;
607 if (numCols == col) {
608 col = 0;
609 ++row;
610 }
611 }
612 }
613 }
614
615private:
616 typedef GM INHERITED;
617};
618
halcanary385fe4d2015-08-26 13:07:48 -0700619DEF_GM(return new BezierCubicEffects;)
620DEF_GM(return new BezierConicEffects;)
621DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000622}
623
624#endif