blob: b66ea42acf5e2d29d3d066d89e738944c51ae8c3 [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
Robert Phillipsf1748f52017-09-14 14:11:24 -040036 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -040037 fProcessorSet.visitProxies(func);
38 }
39
Brian Salomon477d0ef2017-07-14 10:12:26 -040040protected:
41 BezierTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color, int32_t classID)
42 : INHERITED(classID)
43 , fRect(rect)
44 , fColor(color)
45 , fGeometryProcessor(std::move(gp))
46 , fProcessorSet(SkBlendMode::kSrc) {
47 this->setBounds(rect, HasAABloat::kYes, IsZeroArea::kNo);
48 }
49
Brian Salomon91326c32017-08-09 16:02:19 -040050 const GrPipeline* makePipeline(Target* target) {
Brian Salomonbfd18cd2017-08-09 16:27:09 -040051 return target->makePipeline(0, std::move(fProcessorSet), target->detachAppliedClip());
Brian Salomon477d0ef2017-07-14 10:12:26 -040052 }
53
54 const GrGeometryProcessor* gp() const { return fGeometryProcessor.get(); }
55
56 const SkRect& rect() const { return fRect; }
57 GrColor color() const { return fColor; }
58
59private:
60 bool onCombineIfPossible(GrOp* op, const GrCaps& caps) override { return false; }
61
62 SkRect fRect;
63 GrColor fColor;
64 sk_sp<GrGeometryProcessor> fGeometryProcessor;
65 GrProcessorSet fProcessorSet;
66
67 typedef GrMeshDrawOp INHERITED;
68};
69
70class BezierCubicTestOp : public BezierTestOp {
joshualitt95964c62015-02-11 13:45:50 -080071public:
Brian Salomon25a88092016-12-01 09:36:50 -050072 DEFINE_OP_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -080073
Chris Daltonfebbffa2017-06-08 13:12:02 -060074 const char* name() const override { return "BezierCubicTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -080075
Brian Salomon477d0ef2017-07-14 10:12:26 -040076 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
77 GrColor color) {
78 return std::unique_ptr<GrDrawOp>(new BezierCubicTestOp(std::move(gp), rect, color));
Brian Salomon6b316e92016-12-16 09:35:49 -050079 }
80
81private:
Chris Daltonfebbffa2017-06-08 13:12:02 -060082 BezierCubicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color)
Brian Salomon477d0ef2017-07-14 10:12:26 -040083 : INHERITED(std::move(gp), rect, color, ClassID()) {}
joshualitt95964c62015-02-11 13:45:50 -080084
Brian Salomon91326c32017-08-09 16:02:19 -040085 void onPrepareDraws(Target* target) override {
bsalomonb5238a72015-05-05 07:49:49 -070086 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -040087 size_t vertexStride = this->gp()->getVertexStride();
Chris Daltonfebbffa2017-06-08 13:12:02 -060088 SkASSERT(vertexStride == sizeof(SkPoint));
89 SkPoint* pts = reinterpret_cast<SkPoint*>(helper.init(target, vertexStride, 1));
90 if (!pts) {
joshualitt4b31de82015-03-05 14:33:41 -080091 return;
92 }
Brian Salomon477d0ef2017-07-14 10:12:26 -040093 SkRect rect = this->rect();
94 pts[0].setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
95 helper.recordDraw(target, this->gp(), this->makePipeline(target));
joshualitt95964c62015-02-11 13:45:50 -080096 }
97
mtkleindbfd7ab2016-09-01 11:24:54 -070098 static constexpr int kVertsPerCubic = 4;
99 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800100
Brian Salomon477d0ef2017-07-14 10:12:26 -0400101 typedef BezierTestOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800102};
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 {
Brian Osman11052242016-10-27 14:47:55 -0400123 GrRenderTargetContext* renderTargetContext =
124 canvas->internal_private_accessTopLayerRenderTargetContext();
125 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700126 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000127 return;
128 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000129
robertphillips175dd9b2016-04-28 14:32:04 -0700130 GrContext* context = canvas->getGrContext();
131 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800132 return;
133 }
134
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000135 struct Vertex {
136 SkPoint fPosition;
137 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
138 };
139
mtkleindbfd7ab2016-09-01 11:24:54 -0700140 constexpr int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000141 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000142
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000143 // Mult by 3 for each edge effect type
144 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
145 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400146 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
147 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000148 int row = 0;
149 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700150 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000151
152 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000153 SkPoint baseControlPts[] = {
154 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
155 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
156 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
157 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000158 };
Chris Daltonfebbffa2017-06-08 13:12:02 -0600159 for(GrPrimitiveEdgeType edgeType : {kFillBW_GrProcessorEdgeType,
160 kFillAA_GrProcessorEdgeType,
161 kHairlineAA_GrProcessorEdgeType}) {
Mike Reeddf85c382017-02-14 10:59:19 -0500162 SkScalar x = col * w;
163 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000164 SkPoint controlPts[] = {
165 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
166 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
167 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
168 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
169 };
170 SkPoint chopped[10];
csmartdaltoncc261272017-03-23 13:38:45 -0600171 SkMatrix klm;
Greg Daniel8199d942017-03-14 10:20:24 -0400172 int loopIndex;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000173 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
174 chopped,
csmartdaltoncc261272017-03-23 13:38:45 -0600175 &klm,
Greg Daniel8199d942017-03-14 10:20:24 -0400176 &loopIndex);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000177
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000178 SkPaint ctrlPtPaint;
179 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
Hal Canary23e474c2017-05-15 13:35:35 -0400180 canvas->drawCircle(controlPts[0], 8.f, ctrlPtPaint);
Greg Daniel8199d942017-03-14 10:20:24 -0400181 for (int i = 1; i < 4; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400182 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000183 }
184
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000185 SkPaint polyPaint;
186 polyPaint.setColor(0xffA0A0A0);
187 polyPaint.setStrokeWidth(0);
188 polyPaint.setStyle(SkPaint::kStroke_Style);
189 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000190
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000191 SkPaint choppedPtPaint;
192 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000193
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000194 for (int c = 0; c < cnt; ++c) {
195 SkPoint* pts = chopped + 3 * c;
196
197 for (int i = 0; i < 4; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400198 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000199 }
200
201 SkRect bounds;
202 bounds.set(pts, 4);
203
204 SkPaint boundsPaint;
205 boundsPaint.setColor(0xff808080);
206 boundsPaint.setStrokeWidth(0);
207 boundsPaint.setStyle(SkPaint::kStroke_Style);
208 canvas->drawRect(bounds, boundsPaint);
209
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000210
Chris Daltonfebbffa2017-06-08 13:12:02 -0600211 bool flipKL = (c == loopIndex && cnt != 3);
212 sk_sp<GrGeometryProcessor> gp = GrCubicEffect::Make(color, SkMatrix::I(), klm,
213 flipKL, edgeType,
214 *context->caps());
215 if (!gp) {
216 break;
Greg Daniel8199d942017-03-14 10:20:24 -0400217 }
218
Brian Salomon477d0ef2017-07-14 10:12:26 -0400219 std::unique_ptr<GrDrawOp> op =
Chris Daltonfebbffa2017-06-08 13:12:02 -0600220 BezierCubicTestOp::Make(std::move(gp), bounds, color);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400221 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000222 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000223 ++col;
224 if (numCols == col) {
225 col = 0;
226 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000227 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000228 }
229 }
230 }
231
232private:
233 typedef GM INHERITED;
234};
235
236//////////////////////////////////////////////////////////////////////////////
237
Brian Salomon477d0ef2017-07-14 10:12:26 -0400238class BezierConicTestOp : public BezierTestOp {
Chris Daltonfebbffa2017-06-08 13:12:02 -0600239public:
240 DEFINE_OP_CLASS_ID
241
242 const char* name() const override { return "BezierConicTestOp"; }
243
Brian Salomon477d0ef2017-07-14 10:12:26 -0400244 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
245 GrColor color, const SkMatrix& klm) {
246 return std::unique_ptr<GrMeshDrawOp>(
247 new BezierConicTestOp(std::move(gp), rect, color, klm));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600248 }
249
250private:
251 BezierConicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
252 const SkMatrix& klm)
Brian Salomon477d0ef2017-07-14 10:12:26 -0400253 : INHERITED(std::move(gp), rect, color, ClassID()), fKLM(klm) {}
254
Chris Daltonfebbffa2017-06-08 13:12:02 -0600255 struct Vertex {
256 SkPoint fPosition;
257 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
258 };
259
Brian Salomon91326c32017-08-09 16:02:19 -0400260 void onPrepareDraws(Target* target) override {
Chris Daltonfebbffa2017-06-08 13:12:02 -0600261 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -0400262 size_t vertexStride = this->gp()->getVertexStride();
Chris Daltonfebbffa2017-06-08 13:12:02 -0600263 SkASSERT(vertexStride == sizeof(Vertex));
264 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
265 if (!verts) {
266 return;
267 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400268 SkRect rect = this->rect();
269 verts[0].fPosition.setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
Chris Daltonfebbffa2017-06-08 13:12:02 -0600270 sizeof(Vertex));
271 for (int v = 0; v < 4; ++v) {
272 SkScalar pt3[3] = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
273 fKLM.mapHomogeneousPoints(verts[v].fKLM, pt3, 1);
274 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400275 helper.recordDraw(target, this->gp(), this->makePipeline(target));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600276 }
277
278 SkMatrix fKLM;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600279
280 static constexpr int kVertsPerCubic = 4;
281 static constexpr int kIndicesPerCubic = 6;
282
Brian Salomon477d0ef2017-07-14 10:12:26 -0400283 typedef BezierTestOp INHERITED;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600284};
285
286
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000287/**
288 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
289 */
290class BezierConicEffects : public GM {
291public:
292 BezierConicEffects() {
293 this->setBGColor(0xFFFFFFFF);
294 }
295
296protected:
mtklein36352bf2015-03-25 18:17:31 -0700297 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000298 return SkString("bezier_conic_effects");
299 }
300
mtklein36352bf2015-03-25 18:17:31 -0700301 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700302 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000303 }
304
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000305
mtklein36352bf2015-03-25 18:17:31 -0700306 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400307 GrRenderTargetContext* renderTargetContext =
308 canvas->internal_private_accessTopLayerRenderTargetContext();
309 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700310 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000311 return;
312 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000313
robertphillips175dd9b2016-04-28 14:32:04 -0700314 GrContext* context = canvas->getGrContext();
315 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800316 return;
317 }
318
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000319 struct Vertex {
320 SkPoint fPosition;
321 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
322 };
323
mtkleindbfd7ab2016-09-01 11:24:54 -0700324 constexpr int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000325 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000326
327 // Mult by 3 for each edge effect type
328 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
329 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400330 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
331 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000332 int row = 0;
333 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700334 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000335
336 for (int i = 0; i < kNumConics; ++i) {
337 SkPoint baseControlPts[] = {
338 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
339 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
340 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
341 };
342 SkScalar weight = rand.nextRangeF(0.f, 2.f);
joshualittb0a8a372014-09-23 09:50:21 -0700343 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700344 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800345 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700346 gp = GrConicEffect::Make(color, SkMatrix::I(), et,
347 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800348 if (!gp) {
349 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000350 }
351
Mike Reeddf85c382017-02-14 10:59:19 -0500352 SkScalar x = col * w;
353 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000354 SkPoint controlPts[] = {
355 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
356 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
357 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
358 };
359 SkConic dst[4];
csmartdaltoncc261272017-03-23 13:38:45 -0600360 SkMatrix klm;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000361 int cnt = chop_conic(controlPts, dst, weight);
csmartdaltoncc261272017-03-23 13:38:45 -0600362 GrPathUtils::getConicKLM(controlPts, weight, &klm);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000363
364 SkPaint ctrlPtPaint;
365 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
366 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400367 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000368 }
369
370 SkPaint polyPaint;
371 polyPaint.setColor(0xffA0A0A0);
372 polyPaint.setStrokeWidth(0);
373 polyPaint.setStyle(SkPaint::kStroke_Style);
374 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
375
376 SkPaint choppedPtPaint;
377 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
378
379 for (int c = 0; c < cnt; ++c) {
380 SkPoint* pts = dst[c].fPts;
381 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400382 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000383 }
384
385 SkRect bounds;
386 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
387 //bounds.set(bPts, 2);
388 bounds.set(pts, 3);
389
390 SkPaint boundsPaint;
391 boundsPaint.setColor(0xff808080);
392 boundsPaint.setStrokeWidth(0);
393 boundsPaint.setStyle(SkPaint::kStroke_Style);
394 canvas->drawRect(bounds, boundsPaint);
395
Brian Salomon477d0ef2017-07-14 10:12:26 -0400396 std::unique_ptr<GrDrawOp> op = BezierConicTestOp::Make(gp, bounds, color, klm);
397 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000398 }
399 ++col;
400 if (numCols == col) {
401 col = 0;
402 ++row;
403 }
404 }
405 }
406 }
407
408private:
409 // Uses the max curvature function for quads to estimate
410 // where to chop the conic. If the max curvature is not
411 // found along the curve segment it will return 1 and
412 // dst[0] is the original conic. If it returns 2 the dst[0]
413 // and dst[1] are the two new conics.
414 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
415 SkScalar t = SkFindQuadMaxCurvature(src);
416 if (t == 0) {
417 if (dst) {
418 dst[0].set(src, weight);
419 }
420 return 1;
421 } else {
422 if (dst) {
423 SkConic conic;
424 conic.set(src, weight);
caryclark414c4292016-09-26 11:03:54 -0700425 if (!conic.chopAt(t, dst)) {
426 dst[0].set(src, weight);
427 return 1;
428 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000429 }
430 return 2;
431 }
432 }
433
434 // Calls split_conic on the entire conic and then once more on each subsection.
435 // Most cases will result in either 1 conic (chop point is not within t range)
436 // or 3 points (split once and then one subsection is split again).
437 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
438 SkConic dstTemp[2];
439 int conicCnt = split_conic(src, dstTemp, weight);
440 if (2 == conicCnt) {
441 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
442 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
443 } else {
444 dst[0] = dstTemp[0];
445 }
446 return conicCnt;
447 }
448
449 typedef GM INHERITED;
450};
451
452//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800453
Brian Salomon477d0ef2017-07-14 10:12:26 -0400454class BezierQuadTestOp : public BezierTestOp {
joshualitt95964c62015-02-11 13:45:50 -0800455public:
Brian Salomon25a88092016-12-01 09:36:50 -0500456 DEFINE_OP_CLASS_ID
Brian Salomon6b316e92016-12-16 09:35:49 -0500457 const char* name() const override { return "BezierQuadTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -0800458
Brian Salomon477d0ef2017-07-14 10:12:26 -0400459 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
460 GrColor color, const GrPathUtils::QuadUVMatrix& devToUV) {
461 return std::unique_ptr<GrDrawOp>(new BezierQuadTestOp(std::move(gp), rect, color, devToUV));
joshualitt95964c62015-02-11 13:45:50 -0800462 }
463
464private:
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500465 BezierQuadTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
Brian Salomon6b316e92016-12-16 09:35:49 -0500466 const GrPathUtils::QuadUVMatrix& devToUV)
Brian Salomon477d0ef2017-07-14 10:12:26 -0400467 : INHERITED(std::move(gp), rect, color, ClassID()), fDevToUV(devToUV) {}
joshualitt95964c62015-02-11 13:45:50 -0800468
469 struct Vertex {
470 SkPoint fPosition;
471 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
472 };
473
Brian Salomon91326c32017-08-09 16:02:19 -0400474 void onPrepareDraws(Target* target) override {
bsalomonb5238a72015-05-05 07:49:49 -0700475 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -0400476 size_t vertexStride = this->gp()->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700477 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700478 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700479 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800480 return;
481 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400482 SkRect rect = this->rect();
483 verts[0].fPosition.setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
joshualitt95964c62015-02-11 13:45:50 -0800484 sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800485 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400486 helper.recordDraw(target, this->gp(), this->makePipeline(target));
joshualitt95964c62015-02-11 13:45:50 -0800487 }
488
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500489 GrPathUtils::QuadUVMatrix fDevToUV;
joshualitt95964c62015-02-11 13:45:50 -0800490
mtkleindbfd7ab2016-09-01 11:24:54 -0700491 static constexpr int kVertsPerCubic = 4;
492 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800493
Brian Salomon477d0ef2017-07-14 10:12:26 -0400494 typedef BezierTestOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800495};
496
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000497/**
498 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
499 */
500class BezierQuadEffects : public GM {
501public:
502 BezierQuadEffects() {
503 this->setBGColor(0xFFFFFFFF);
504 }
505
506protected:
mtklein36352bf2015-03-25 18:17:31 -0700507 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000508 return SkString("bezier_quad_effects");
509 }
510
mtklein36352bf2015-03-25 18:17:31 -0700511 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700512 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000513 }
514
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000515
mtklein36352bf2015-03-25 18:17:31 -0700516 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400517 GrRenderTargetContext* renderTargetContext =
518 canvas->internal_private_accessTopLayerRenderTargetContext();
519 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700520 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000521 return;
522 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000523
robertphillips175dd9b2016-04-28 14:32:04 -0700524 GrContext* context = canvas->getGrContext();
525 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800526 return;
527 }
528
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000529 struct Vertex {
530 SkPoint fPosition;
531 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
532 };
533
mtkleindbfd7ab2016-09-01 11:24:54 -0700534 constexpr int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000535 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000536
537 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
538 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400539 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
540 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000541 int row = 0;
542 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700543 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000544
545 for (int i = 0; i < kNumQuads; ++i) {
546 SkPoint baseControlPts[] = {
547 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
548 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
549 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
550 };
joshualittb0a8a372014-09-23 09:50:21 -0700551 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700552 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800553 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700554 gp = GrQuadEffect::Make(color, SkMatrix::I(), et,
555 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800556 if (!gp) {
557 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000558 }
559
Mike Reeddf85c382017-02-14 10:59:19 -0500560 SkScalar x = col * w;
561 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000562 SkPoint controlPts[] = {
563 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
564 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
565 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
566 };
567 SkPoint chopped[5];
568 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
569
570 SkPaint ctrlPtPaint;
571 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
572 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400573 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000574 }
575
576 SkPaint polyPaint;
577 polyPaint.setColor(0xffA0A0A0);
578 polyPaint.setStrokeWidth(0);
579 polyPaint.setStyle(SkPaint::kStroke_Style);
580 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
581
582 SkPaint choppedPtPaint;
583 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
584
585 for (int c = 0; c < cnt; ++c) {
586 SkPoint* pts = chopped + 2 * c;
587
588 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400589 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000590 }
591
592 SkRect bounds;
593 bounds.set(pts, 3);
594
595 SkPaint boundsPaint;
596 boundsPaint.setColor(0xff808080);
597 boundsPaint.setStrokeWidth(0);
598 boundsPaint.setStyle(SkPaint::kStroke_Style);
599 canvas->drawRect(bounds, boundsPaint);
600
robertphillips28a838e2016-06-23 14:07:00 -0700601 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500602 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
joshualitt3f284d72015-02-11 11:34:58 -0800603
joshualitt95964c62015-02-11 13:45:50 -0800604 GrPathUtils::QuadUVMatrix DevToUV(pts);
605
Brian Salomon477d0ef2017-07-14 10:12:26 -0400606 std::unique_ptr<GrDrawOp> op =
Brian Salomonf8334782017-01-03 09:42:58 -0500607 BezierQuadTestOp::Make(gp, bounds, color, DevToUV);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400608 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000609 }
610 ++col;
611 if (numCols == col) {
612 col = 0;
613 ++row;
614 }
615 }
616 }
617 }
618
619private:
620 typedef GM INHERITED;
621};
622
halcanary385fe4d2015-08-26 13:07:48 -0700623DEF_GM(return new BezierCubicEffects;)
624DEF_GM(return new BezierConicEffects;)
625DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000626}
627
628#endif