blob: ebcd27bb495eaef34fe8336a62a565dff4a36e7d [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"
Cary Clarke4442cb2017-10-18 11:46:18 -040021#include "SkPoint3.h"
Cary Clark74f623d2017-11-06 20:02:02 -050022#include "SkPointPriv.h"
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000023#include "effects/GrBezierEffect.h"
Brian Salomon477d0ef2017-07-14 10:12:26 -040024#include "ops/GrMeshDrawOp.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000025
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000026namespace skiagm {
joshualitt95964c62015-02-11 13:45:50 -080027
Brian Salomon477d0ef2017-07-14 10:12:26 -040028class BezierTestOp : public GrMeshDrawOp {
29public:
30 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
31
Brian Osman9a725dd2017-09-20 09:53:22 -040032 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip,
33 GrPixelConfigIsClamped dstIsClamped) override {
Brian Salomon477d0ef2017-07-14 10:12:26 -040034 auto analysis = fProcessorSet.finalize(fColor, GrProcessorAnalysisCoverage::kSingleChannel,
Brian Osman9a725dd2017-09-20 09:53:22 -040035 clip, false, caps, dstIsClamped, &fColor);
Brian Salomon477d0ef2017-07-14 10:12:26 -040036 return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo;
37 }
38
Robert Phillipsf1748f52017-09-14 14:11:24 -040039 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -040040 fProcessorSet.visitProxies(func);
41 }
42
Brian Salomon477d0ef2017-07-14 10:12:26 -040043protected:
44 BezierTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color, int32_t classID)
45 : INHERITED(classID)
46 , fRect(rect)
47 , fColor(color)
48 , fGeometryProcessor(std::move(gp))
49 , fProcessorSet(SkBlendMode::kSrc) {
50 this->setBounds(rect, HasAABloat::kYes, IsZeroArea::kNo);
51 }
52
Brian Salomon91326c32017-08-09 16:02:19 -040053 const GrPipeline* makePipeline(Target* target) {
Brian Salomonbfd18cd2017-08-09 16:27:09 -040054 return target->makePipeline(0, std::move(fProcessorSet), target->detachAppliedClip());
Brian Salomon477d0ef2017-07-14 10:12:26 -040055 }
56
57 const GrGeometryProcessor* gp() const { return fGeometryProcessor.get(); }
58
59 const SkRect& rect() const { return fRect; }
60 GrColor color() const { return fColor; }
61
62private:
63 bool onCombineIfPossible(GrOp* op, const GrCaps& caps) override { return false; }
64
65 SkRect fRect;
66 GrColor fColor;
67 sk_sp<GrGeometryProcessor> fGeometryProcessor;
68 GrProcessorSet fProcessorSet;
69
70 typedef GrMeshDrawOp INHERITED;
71};
72
73class BezierCubicTestOp : public BezierTestOp {
joshualitt95964c62015-02-11 13:45:50 -080074public:
Brian Salomon25a88092016-12-01 09:36:50 -050075 DEFINE_OP_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -080076
Chris Daltonfebbffa2017-06-08 13:12:02 -060077 const char* name() const override { return "BezierCubicTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -080078
Brian Salomon477d0ef2017-07-14 10:12:26 -040079 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
80 GrColor color) {
81 return std::unique_ptr<GrDrawOp>(new BezierCubicTestOp(std::move(gp), rect, color));
Brian Salomon6b316e92016-12-16 09:35:49 -050082 }
83
84private:
Chris Daltonfebbffa2017-06-08 13:12:02 -060085 BezierCubicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color)
Brian Salomon477d0ef2017-07-14 10:12:26 -040086 : INHERITED(std::move(gp), rect, color, ClassID()) {}
joshualitt95964c62015-02-11 13:45:50 -080087
Brian Salomon91326c32017-08-09 16:02:19 -040088 void onPrepareDraws(Target* target) override {
bsalomonb5238a72015-05-05 07:49:49 -070089 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -040090 size_t vertexStride = this->gp()->getVertexStride();
Chris Daltonfebbffa2017-06-08 13:12:02 -060091 SkASSERT(vertexStride == sizeof(SkPoint));
92 SkPoint* pts = reinterpret_cast<SkPoint*>(helper.init(target, vertexStride, 1));
93 if (!pts) {
joshualitt4b31de82015-03-05 14:33:41 -080094 return;
95 }
Brian Salomon477d0ef2017-07-14 10:12:26 -040096 SkRect rect = this->rect();
Cary Clark74f623d2017-11-06 20:02:02 -050097 SkPointPriv::SetRectTriStrip(pts, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
Brian Salomon477d0ef2017-07-14 10:12:26 -040098 helper.recordDraw(target, this->gp(), this->makePipeline(target));
joshualitt95964c62015-02-11 13:45:50 -080099 }
100
mtkleindbfd7ab2016-09-01 11:24:54 -0700101 static constexpr int kVertsPerCubic = 4;
102 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800103
Brian Salomon477d0ef2017-07-14 10:12:26 -0400104 typedef BezierTestOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800105};
106
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000107/**
108 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
109 */
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000110class BezierCubicEffects : public GM {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000111public:
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000112 BezierCubicEffects() {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000113 this->setBGColor(0xFFFFFFFF);
114 }
115
116protected:
mtklein36352bf2015-03-25 18:17:31 -0700117 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000118 return SkString("bezier_cubic_effects");
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000119 }
120
mtklein36352bf2015-03-25 18:17:31 -0700121 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700122 return SkISize::Make(800, 800);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000123 }
124
mtklein36352bf2015-03-25 18:17:31 -0700125 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400126 GrRenderTargetContext* renderTargetContext =
127 canvas->internal_private_accessTopLayerRenderTargetContext();
128 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700129 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000130 return;
131 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000132
robertphillips175dd9b2016-04-28 14:32:04 -0700133 GrContext* context = canvas->getGrContext();
134 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800135 return;
136 }
137
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000138 struct Vertex {
139 SkPoint fPosition;
140 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
141 };
142
mtkleindbfd7ab2016-09-01 11:24:54 -0700143 constexpr int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000144 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000145
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000146 // Mult by 3 for each edge effect type
147 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
148 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400149 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
150 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000151 int row = 0;
152 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700153 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000154
155 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000156 SkPoint baseControlPts[] = {
157 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
158 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
159 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
160 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000161 };
Ethan Nicholas1706f842017-11-10 11:58:19 -0500162 for(GrClipEdgeType edgeType : {GrClipEdgeType::kFillBW,
163 GrClipEdgeType::kFillAA,
164 GrClipEdgeType::kHairlineAA}) {
Mike Reeddf85c382017-02-14 10:59:19 -0500165 SkScalar x = col * w;
166 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000167 SkPoint controlPts[] = {
168 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
169 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
170 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
171 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
172 };
173 SkPoint chopped[10];
csmartdaltoncc261272017-03-23 13:38:45 -0600174 SkMatrix klm;
Greg Daniel8199d942017-03-14 10:20:24 -0400175 int loopIndex;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000176 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
177 chopped,
csmartdaltoncc261272017-03-23 13:38:45 -0600178 &klm,
Greg Daniel8199d942017-03-14 10:20:24 -0400179 &loopIndex);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000180
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000181 SkPaint ctrlPtPaint;
182 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
Hal Canary23e474c2017-05-15 13:35:35 -0400183 canvas->drawCircle(controlPts[0], 8.f, ctrlPtPaint);
Greg Daniel8199d942017-03-14 10:20:24 -0400184 for (int i = 1; i < 4; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400185 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000186 }
187
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000188 SkPaint polyPaint;
189 polyPaint.setColor(0xffA0A0A0);
190 polyPaint.setStrokeWidth(0);
191 polyPaint.setStyle(SkPaint::kStroke_Style);
192 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000193
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000194 SkPaint choppedPtPaint;
195 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000196
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000197 for (int c = 0; c < cnt; ++c) {
198 SkPoint* pts = chopped + 3 * c;
199
200 for (int i = 0; i < 4; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400201 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000202 }
203
204 SkRect bounds;
205 bounds.set(pts, 4);
206
207 SkPaint boundsPaint;
208 boundsPaint.setColor(0xff808080);
209 boundsPaint.setStrokeWidth(0);
210 boundsPaint.setStyle(SkPaint::kStroke_Style);
211 canvas->drawRect(bounds, boundsPaint);
212
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000213
Chris Daltonfebbffa2017-06-08 13:12:02 -0600214 bool flipKL = (c == loopIndex && cnt != 3);
215 sk_sp<GrGeometryProcessor> gp = GrCubicEffect::Make(color, SkMatrix::I(), klm,
216 flipKL, edgeType,
217 *context->caps());
218 if (!gp) {
219 break;
Greg Daniel8199d942017-03-14 10:20:24 -0400220 }
221
Brian Salomon477d0ef2017-07-14 10:12:26 -0400222 std::unique_ptr<GrDrawOp> op =
Chris Daltonfebbffa2017-06-08 13:12:02 -0600223 BezierCubicTestOp::Make(std::move(gp), bounds, color);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400224 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000225 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000226 ++col;
227 if (numCols == col) {
228 col = 0;
229 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000230 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000231 }
232 }
233 }
234
235private:
236 typedef GM INHERITED;
237};
238
239//////////////////////////////////////////////////////////////////////////////
240
Brian Salomon477d0ef2017-07-14 10:12:26 -0400241class BezierConicTestOp : public BezierTestOp {
Chris Daltonfebbffa2017-06-08 13:12:02 -0600242public:
243 DEFINE_OP_CLASS_ID
244
245 const char* name() const override { return "BezierConicTestOp"; }
246
Brian Salomon477d0ef2017-07-14 10:12:26 -0400247 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
248 GrColor color, const SkMatrix& klm) {
249 return std::unique_ptr<GrMeshDrawOp>(
250 new BezierConicTestOp(std::move(gp), rect, color, klm));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600251 }
252
253private:
254 BezierConicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
255 const SkMatrix& klm)
Brian Salomon477d0ef2017-07-14 10:12:26 -0400256 : INHERITED(std::move(gp), rect, color, ClassID()), fKLM(klm) {}
257
Chris Daltonfebbffa2017-06-08 13:12:02 -0600258 struct Vertex {
259 SkPoint fPosition;
260 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
261 };
262
Brian Salomon91326c32017-08-09 16:02:19 -0400263 void onPrepareDraws(Target* target) override {
Chris Daltonfebbffa2017-06-08 13:12:02 -0600264 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -0400265 size_t vertexStride = this->gp()->getVertexStride();
Chris Daltonfebbffa2017-06-08 13:12:02 -0600266 SkASSERT(vertexStride == sizeof(Vertex));
267 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
268 if (!verts) {
269 return;
270 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400271 SkRect rect = this->rect();
Cary Clark74f623d2017-11-06 20:02:02 -0500272 SkPointPriv::SetRectTriStrip(&verts[0].fPosition, rect.fLeft, rect.fTop, rect.fRight,
273 rect.fBottom, sizeof(Vertex));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600274 for (int v = 0; v < 4; ++v) {
Cary Clarke4442cb2017-10-18 11:46:18 -0400275 SkPoint3 pt3 = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
276 fKLM.mapHomogeneousPoints((SkPoint3* ) verts[v].fKLM, &pt3, 1);
Chris Daltonfebbffa2017-06-08 13:12:02 -0600277 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400278 helper.recordDraw(target, this->gp(), this->makePipeline(target));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600279 }
280
281 SkMatrix fKLM;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600282
283 static constexpr int kVertsPerCubic = 4;
284 static constexpr int kIndicesPerCubic = 6;
285
Brian Salomon477d0ef2017-07-14 10:12:26 -0400286 typedef BezierTestOp INHERITED;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600287};
288
289
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000290/**
291 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
292 */
293class BezierConicEffects : public GM {
294public:
295 BezierConicEffects() {
296 this->setBGColor(0xFFFFFFFF);
297 }
298
299protected:
mtklein36352bf2015-03-25 18:17:31 -0700300 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000301 return SkString("bezier_conic_effects");
302 }
303
mtklein36352bf2015-03-25 18:17:31 -0700304 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700305 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000306 }
307
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000308
mtklein36352bf2015-03-25 18:17:31 -0700309 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400310 GrRenderTargetContext* renderTargetContext =
311 canvas->internal_private_accessTopLayerRenderTargetContext();
312 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700313 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000314 return;
315 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000316
robertphillips175dd9b2016-04-28 14:32:04 -0700317 GrContext* context = canvas->getGrContext();
318 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800319 return;
320 }
321
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000322 struct Vertex {
323 SkPoint fPosition;
324 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
325 };
326
mtkleindbfd7ab2016-09-01 11:24:54 -0700327 constexpr int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000328 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000329
330 // Mult by 3 for each edge effect type
331 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
332 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400333 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
334 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000335 int row = 0;
336 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700337 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000338
339 for (int i = 0; i < kNumConics; ++i) {
340 SkPoint baseControlPts[] = {
341 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
342 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
343 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
344 };
345 SkScalar weight = rand.nextRangeF(0.f, 2.f);
Ethan Nicholas1706f842017-11-10 11:58:19 -0500346 for(int edgeType = 0; edgeType < kGrClipEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700347 sk_sp<GrGeometryProcessor> gp;
Ethan Nicholas0f3c7322017-11-09 14:51:17 -0500348 GrClipEdgeType et = (GrClipEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700349 gp = GrConicEffect::Make(color, SkMatrix::I(), et,
350 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800351 if (!gp) {
352 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000353 }
354
Mike Reeddf85c382017-02-14 10:59:19 -0500355 SkScalar x = col * w;
356 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000357 SkPoint controlPts[] = {
358 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
359 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
360 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
361 };
362 SkConic dst[4];
csmartdaltoncc261272017-03-23 13:38:45 -0600363 SkMatrix klm;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000364 int cnt = chop_conic(controlPts, dst, weight);
csmartdaltoncc261272017-03-23 13:38:45 -0600365 GrPathUtils::getConicKLM(controlPts, weight, &klm);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000366
367 SkPaint ctrlPtPaint;
368 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
369 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400370 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000371 }
372
373 SkPaint polyPaint;
374 polyPaint.setColor(0xffA0A0A0);
375 polyPaint.setStrokeWidth(0);
376 polyPaint.setStyle(SkPaint::kStroke_Style);
377 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
378
379 SkPaint choppedPtPaint;
380 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
381
382 for (int c = 0; c < cnt; ++c) {
383 SkPoint* pts = dst[c].fPts;
384 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400385 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000386 }
387
388 SkRect bounds;
389 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
390 //bounds.set(bPts, 2);
391 bounds.set(pts, 3);
392
393 SkPaint boundsPaint;
394 boundsPaint.setColor(0xff808080);
395 boundsPaint.setStrokeWidth(0);
396 boundsPaint.setStyle(SkPaint::kStroke_Style);
397 canvas->drawRect(bounds, boundsPaint);
398
Brian Salomon477d0ef2017-07-14 10:12:26 -0400399 std::unique_ptr<GrDrawOp> op = BezierConicTestOp::Make(gp, bounds, color, klm);
400 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000401 }
402 ++col;
403 if (numCols == col) {
404 col = 0;
405 ++row;
406 }
407 }
408 }
409 }
410
411private:
412 // Uses the max curvature function for quads to estimate
413 // where to chop the conic. If the max curvature is not
414 // found along the curve segment it will return 1 and
415 // dst[0] is the original conic. If it returns 2 the dst[0]
416 // and dst[1] are the two new conics.
417 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
418 SkScalar t = SkFindQuadMaxCurvature(src);
419 if (t == 0) {
420 if (dst) {
421 dst[0].set(src, weight);
422 }
423 return 1;
424 } else {
425 if (dst) {
426 SkConic conic;
427 conic.set(src, weight);
caryclark414c4292016-09-26 11:03:54 -0700428 if (!conic.chopAt(t, dst)) {
429 dst[0].set(src, weight);
430 return 1;
431 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000432 }
433 return 2;
434 }
435 }
436
437 // Calls split_conic on the entire conic and then once more on each subsection.
438 // Most cases will result in either 1 conic (chop point is not within t range)
439 // or 3 points (split once and then one subsection is split again).
440 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
441 SkConic dstTemp[2];
442 int conicCnt = split_conic(src, dstTemp, weight);
443 if (2 == conicCnt) {
444 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
445 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
446 } else {
447 dst[0] = dstTemp[0];
448 }
449 return conicCnt;
450 }
451
452 typedef GM INHERITED;
453};
454
455//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800456
Brian Salomon477d0ef2017-07-14 10:12:26 -0400457class BezierQuadTestOp : public BezierTestOp {
joshualitt95964c62015-02-11 13:45:50 -0800458public:
Brian Salomon25a88092016-12-01 09:36:50 -0500459 DEFINE_OP_CLASS_ID
Brian Salomon6b316e92016-12-16 09:35:49 -0500460 const char* name() const override { return "BezierQuadTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -0800461
Brian Salomon477d0ef2017-07-14 10:12:26 -0400462 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
463 GrColor color, const GrPathUtils::QuadUVMatrix& devToUV) {
464 return std::unique_ptr<GrDrawOp>(new BezierQuadTestOp(std::move(gp), rect, color, devToUV));
joshualitt95964c62015-02-11 13:45:50 -0800465 }
466
467private:
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500468 BezierQuadTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
Brian Salomon6b316e92016-12-16 09:35:49 -0500469 const GrPathUtils::QuadUVMatrix& devToUV)
Brian Salomon477d0ef2017-07-14 10:12:26 -0400470 : INHERITED(std::move(gp), rect, color, ClassID()), fDevToUV(devToUV) {}
joshualitt95964c62015-02-11 13:45:50 -0800471
472 struct Vertex {
473 SkPoint fPosition;
474 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
475 };
476
Brian Salomon91326c32017-08-09 16:02:19 -0400477 void onPrepareDraws(Target* target) override {
bsalomonb5238a72015-05-05 07:49:49 -0700478 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -0400479 size_t vertexStride = this->gp()->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700480 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700481 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700482 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800483 return;
484 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400485 SkRect rect = this->rect();
Cary Clark74f623d2017-11-06 20:02:02 -0500486 SkPointPriv::SetRectTriStrip(&verts[0].fPosition, rect.fLeft, rect.fTop, rect.fRight,
487 rect.fBottom, sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800488 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400489 helper.recordDraw(target, this->gp(), this->makePipeline(target));
joshualitt95964c62015-02-11 13:45:50 -0800490 }
491
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500492 GrPathUtils::QuadUVMatrix fDevToUV;
joshualitt95964c62015-02-11 13:45:50 -0800493
mtkleindbfd7ab2016-09-01 11:24:54 -0700494 static constexpr int kVertsPerCubic = 4;
495 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800496
Brian Salomon477d0ef2017-07-14 10:12:26 -0400497 typedef BezierTestOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800498};
499
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000500/**
501 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
502 */
503class BezierQuadEffects : public GM {
504public:
505 BezierQuadEffects() {
506 this->setBGColor(0xFFFFFFFF);
507 }
508
509protected:
mtklein36352bf2015-03-25 18:17:31 -0700510 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000511 return SkString("bezier_quad_effects");
512 }
513
mtklein36352bf2015-03-25 18:17:31 -0700514 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700515 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000516 }
517
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000518
mtklein36352bf2015-03-25 18:17:31 -0700519 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400520 GrRenderTargetContext* renderTargetContext =
521 canvas->internal_private_accessTopLayerRenderTargetContext();
522 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700523 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000524 return;
525 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000526
robertphillips175dd9b2016-04-28 14:32:04 -0700527 GrContext* context = canvas->getGrContext();
528 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800529 return;
530 }
531
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000532 struct Vertex {
533 SkPoint fPosition;
534 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
535 };
536
mtkleindbfd7ab2016-09-01 11:24:54 -0700537 constexpr int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000538 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000539
540 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
541 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400542 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
543 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000544 int row = 0;
545 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700546 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000547
548 for (int i = 0; i < kNumQuads; ++i) {
549 SkPoint baseControlPts[] = {
550 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
551 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
552 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
553 };
Ethan Nicholas1706f842017-11-10 11:58:19 -0500554 for(int edgeType = 0; edgeType < kGrClipEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700555 sk_sp<GrGeometryProcessor> gp;
Ethan Nicholas0f3c7322017-11-09 14:51:17 -0500556 GrClipEdgeType et = (GrClipEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700557 gp = GrQuadEffect::Make(color, SkMatrix::I(), et,
558 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800559 if (!gp) {
560 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000561 }
562
Mike Reeddf85c382017-02-14 10:59:19 -0500563 SkScalar x = col * w;
564 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000565 SkPoint controlPts[] = {
566 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
567 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
568 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
569 };
570 SkPoint chopped[5];
571 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
572
573 SkPaint ctrlPtPaint;
574 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
575 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400576 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000577 }
578
579 SkPaint polyPaint;
580 polyPaint.setColor(0xffA0A0A0);
581 polyPaint.setStrokeWidth(0);
582 polyPaint.setStyle(SkPaint::kStroke_Style);
583 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
584
585 SkPaint choppedPtPaint;
586 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
587
588 for (int c = 0; c < cnt; ++c) {
589 SkPoint* pts = chopped + 2 * c;
590
591 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400592 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000593 }
594
595 SkRect bounds;
596 bounds.set(pts, 3);
597
598 SkPaint boundsPaint;
599 boundsPaint.setColor(0xff808080);
600 boundsPaint.setStrokeWidth(0);
601 boundsPaint.setStyle(SkPaint::kStroke_Style);
602 canvas->drawRect(bounds, boundsPaint);
603
robertphillips28a838e2016-06-23 14:07:00 -0700604 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500605 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
joshualitt3f284d72015-02-11 11:34:58 -0800606
joshualitt95964c62015-02-11 13:45:50 -0800607 GrPathUtils::QuadUVMatrix DevToUV(pts);
608
Brian Salomon477d0ef2017-07-14 10:12:26 -0400609 std::unique_ptr<GrDrawOp> op =
Brian Salomonf8334782017-01-03 09:42:58 -0500610 BezierQuadTestOp::Make(gp, bounds, color, DevToUV);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400611 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000612 }
613 ++col;
614 if (numCols == col) {
615 col = 0;
616 ++row;
617 }
618 }
619 }
620 }
621
622private:
623 typedef GM INHERITED;
624};
625
halcanary385fe4d2015-08-26 13:07:48 -0700626DEF_GM(return new BezierCubicEffects;)
627DEF_GM(return new BezierConicEffects;)
628DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000629}
630
631#endif