blob: ab9a5fdb5b3082e776c9786e8a555e312f7d908c [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"
Chris Dalton1d4af542018-04-16 14:23:00 -060011#include "sk_tool_utils.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000012
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000013#include "GrContext.h"
Brian Salomon477d0ef2017-07-14 10:12:26 -040014#include "GrOpFlushState.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000015#include "GrPathUtils.h"
Brian Salomon477d0ef2017-07-14 10:12:26 -040016#include "GrRenderTargetContextPriv.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000017#include "GrTest.h"
18#include "SkColorPriv.h"
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000019#include "SkGeometry.h"
Cary Clarke4442cb2017-10-18 11:46:18 -040020#include "SkPoint3.h"
Cary Clark74f623d2017-11-06 20:02:02 -050021#include "SkPointPriv.h"
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000022#include "effects/GrBezierEffect.h"
Brian Salomon477d0ef2017-07-14 10:12:26 -040023#include "ops/GrMeshDrawOp.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000024
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000025namespace skiagm {
joshualitt95964c62015-02-11 13:45:50 -080026
Brian Salomon477d0ef2017-07-14 10:12:26 -040027class BezierTestOp : public GrMeshDrawOp {
28public:
29 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
30
Brian Osman9a725dd2017-09-20 09:53:22 -040031 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip,
32 GrPixelConfigIsClamped dstIsClamped) override {
Brian Salomon477d0ef2017-07-14 10:12:26 -040033 auto analysis = fProcessorSet.finalize(fColor, GrProcessorAnalysisCoverage::kSingleChannel,
Brian Osman9a725dd2017-09-20 09:53:22 -040034 clip, false, caps, dstIsClamped, &fColor);
Brian Salomon477d0ef2017-07-14 10:12:26 -040035 return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo;
36 }
37
Robert Phillipsf1748f52017-09-14 14:11:24 -040038 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -040039 fProcessorSet.visitProxies(func);
40 }
41
Brian Salomon477d0ef2017-07-14 10:12:26 -040042protected:
43 BezierTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color, int32_t classID)
44 : INHERITED(classID)
45 , fRect(rect)
46 , fColor(color)
47 , fGeometryProcessor(std::move(gp))
48 , fProcessorSet(SkBlendMode::kSrc) {
49 this->setBounds(rect, HasAABloat::kYes, IsZeroArea::kNo);
50 }
51
Brian Salomon91326c32017-08-09 16:02:19 -040052 const GrPipeline* makePipeline(Target* target) {
Brian Salomonbfd18cd2017-08-09 16:27:09 -040053 return target->makePipeline(0, std::move(fProcessorSet), target->detachAppliedClip());
Brian Salomon477d0ef2017-07-14 10:12:26 -040054 }
55
56 const GrGeometryProcessor* gp() const { return fGeometryProcessor.get(); }
57
58 const SkRect& rect() const { return fRect; }
59 GrColor color() const { return fColor; }
60
61private:
62 bool onCombineIfPossible(GrOp* op, const GrCaps& caps) override { return false; }
63
64 SkRect fRect;
65 GrColor fColor;
66 sk_sp<GrGeometryProcessor> fGeometryProcessor;
67 GrProcessorSet fProcessorSet;
68
69 typedef GrMeshDrawOp INHERITED;
70};
71
72class BezierCubicTestOp : public BezierTestOp {
joshualitt95964c62015-02-11 13:45:50 -080073public:
Brian Salomon25a88092016-12-01 09:36:50 -050074 DEFINE_OP_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -080075
Chris Daltonfebbffa2017-06-08 13:12:02 -060076 const char* name() const override { return "BezierCubicTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -080077
Brian Salomon477d0ef2017-07-14 10:12:26 -040078 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
79 GrColor color) {
80 return std::unique_ptr<GrDrawOp>(new BezierCubicTestOp(std::move(gp), rect, color));
Brian Salomon6b316e92016-12-16 09:35:49 -050081 }
82
83private:
Chris Daltonfebbffa2017-06-08 13:12:02 -060084 BezierCubicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color)
Brian Salomon477d0ef2017-07-14 10:12:26 -040085 : INHERITED(std::move(gp), rect, color, ClassID()) {}
joshualitt95964c62015-02-11 13:45:50 -080086
Brian Salomon91326c32017-08-09 16:02:19 -040087 void onPrepareDraws(Target* target) override {
bsalomonb5238a72015-05-05 07:49:49 -070088 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -040089 size_t vertexStride = this->gp()->getVertexStride();
Chris Daltonfebbffa2017-06-08 13:12:02 -060090 SkASSERT(vertexStride == sizeof(SkPoint));
91 SkPoint* pts = reinterpret_cast<SkPoint*>(helper.init(target, vertexStride, 1));
92 if (!pts) {
joshualitt4b31de82015-03-05 14:33:41 -080093 return;
94 }
Brian Salomon477d0ef2017-07-14 10:12:26 -040095 SkRect rect = this->rect();
Brian Salomonec42e152018-05-18 12:52:22 -040096 SkPointPriv::SetRectTriStrip(pts, rect, vertexStride);
Brian Salomon477d0ef2017-07-14 10:12:26 -040097 helper.recordDraw(target, this->gp(), this->makePipeline(target));
joshualitt95964c62015-02-11 13:45:50 -080098 }
99
mtkleindbfd7ab2016-09-01 11:24:54 -0700100 static constexpr int kVertsPerCubic = 4;
101 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800102
Brian Salomon477d0ef2017-07-14 10:12:26 -0400103 typedef BezierTestOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800104};
105
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000106/**
107 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
108 */
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000109class BezierCubicEffects : public GM {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000110public:
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000111 BezierCubicEffects() {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000112 this->setBGColor(0xFFFFFFFF);
113 }
114
115protected:
mtklein36352bf2015-03-25 18:17:31 -0700116 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000117 return SkString("bezier_cubic_effects");
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000118 }
119
mtklein36352bf2015-03-25 18:17:31 -0700120 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700121 return SkISize::Make(800, 800);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000122 }
123
mtklein36352bf2015-03-25 18:17:31 -0700124 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400125 GrRenderTargetContext* renderTargetContext =
126 canvas->internal_private_accessTopLayerRenderTargetContext();
127 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700128 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000129 return;
130 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000131
robertphillips175dd9b2016-04-28 14:32:04 -0700132 GrContext* context = canvas->getGrContext();
133 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800134 return;
135 }
136
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400137 if (!context->contextPriv().caps()->shaderCaps()->floatIs32Bits()) {
Chris Dalton1d4af542018-04-16 14:23:00 -0600138 SkPaint paint;
139 sk_tool_utils::set_portable_typeface(&paint);
140 paint.setAntiAlias(true);
141 paint.setTextSize(20);
142
143 canvas->clear(SK_ColorWHITE);
144 canvas->drawString("float != fp32", 20, 40, paint);
145 return;
146 }
147
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000148 struct Vertex {
149 SkPoint fPosition;
150 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
151 };
152
mtkleindbfd7ab2016-09-01 11:24:54 -0700153 constexpr int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000154 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000155
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000156 // Mult by 3 for each edge effect type
157 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
158 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400159 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
160 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000161 int row = 0;
162 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700163 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000164
165 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000166 SkPoint baseControlPts[] = {
167 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
168 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
169 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
170 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000171 };
Ethan Nicholas1706f842017-11-10 11:58:19 -0500172 for(GrClipEdgeType edgeType : {GrClipEdgeType::kFillBW,
173 GrClipEdgeType::kFillAA,
174 GrClipEdgeType::kHairlineAA}) {
Mike Reeddf85c382017-02-14 10:59:19 -0500175 SkScalar x = col * w;
176 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000177 SkPoint controlPts[] = {
178 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
179 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
180 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
181 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
182 };
183 SkPoint chopped[10];
csmartdaltoncc261272017-03-23 13:38:45 -0600184 SkMatrix klm;
Greg Daniel8199d942017-03-14 10:20:24 -0400185 int loopIndex;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000186 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
187 chopped,
csmartdaltoncc261272017-03-23 13:38:45 -0600188 &klm,
Greg Daniel8199d942017-03-14 10:20:24 -0400189 &loopIndex);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000190
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000191 SkPaint ctrlPtPaint;
192 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
Hal Canary23e474c2017-05-15 13:35:35 -0400193 canvas->drawCircle(controlPts[0], 8.f, ctrlPtPaint);
Greg Daniel8199d942017-03-14 10:20:24 -0400194 for (int i = 1; i < 4; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400195 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000196 }
197
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000198 SkPaint polyPaint;
199 polyPaint.setColor(0xffA0A0A0);
200 polyPaint.setStrokeWidth(0);
201 polyPaint.setStyle(SkPaint::kStroke_Style);
202 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000203
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000204 SkPaint choppedPtPaint;
205 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000206
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000207 for (int c = 0; c < cnt; ++c) {
208 SkPoint* pts = chopped + 3 * c;
209
210 for (int i = 0; i < 4; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400211 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000212 }
213
214 SkRect bounds;
215 bounds.set(pts, 4);
216
217 SkPaint boundsPaint;
218 boundsPaint.setColor(0xff808080);
219 boundsPaint.setStrokeWidth(0);
220 boundsPaint.setStyle(SkPaint::kStroke_Style);
221 canvas->drawRect(bounds, boundsPaint);
222
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000223
Chris Daltonfebbffa2017-06-08 13:12:02 -0600224 bool flipKL = (c == loopIndex && cnt != 3);
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400225 sk_sp<GrGeometryProcessor> gp =
226 GrCubicEffect::Make(color, SkMatrix::I(), klm, flipKL, edgeType,
227 *context->contextPriv().caps());
Chris Daltonfebbffa2017-06-08 13:12:02 -0600228 if (!gp) {
229 break;
Greg Daniel8199d942017-03-14 10:20:24 -0400230 }
231
Brian Salomon477d0ef2017-07-14 10:12:26 -0400232 std::unique_ptr<GrDrawOp> op =
Chris Daltonfebbffa2017-06-08 13:12:02 -0600233 BezierCubicTestOp::Make(std::move(gp), bounds, color);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400234 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000235 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000236 ++col;
237 if (numCols == col) {
238 col = 0;
239 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000240 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000241 }
242 }
243 }
244
245private:
246 typedef GM INHERITED;
247};
248
249//////////////////////////////////////////////////////////////////////////////
250
Brian Salomon477d0ef2017-07-14 10:12:26 -0400251class BezierConicTestOp : public BezierTestOp {
Chris Daltonfebbffa2017-06-08 13:12:02 -0600252public:
253 DEFINE_OP_CLASS_ID
254
255 const char* name() const override { return "BezierConicTestOp"; }
256
Brian Salomon477d0ef2017-07-14 10:12:26 -0400257 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
258 GrColor color, const SkMatrix& klm) {
259 return std::unique_ptr<GrMeshDrawOp>(
260 new BezierConicTestOp(std::move(gp), rect, color, klm));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600261 }
262
263private:
264 BezierConicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
265 const SkMatrix& klm)
Brian Salomon477d0ef2017-07-14 10:12:26 -0400266 : INHERITED(std::move(gp), rect, color, ClassID()), fKLM(klm) {}
267
Chris Daltonfebbffa2017-06-08 13:12:02 -0600268 struct Vertex {
269 SkPoint fPosition;
270 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
271 };
272
Brian Salomon91326c32017-08-09 16:02:19 -0400273 void onPrepareDraws(Target* target) override {
Chris Daltonfebbffa2017-06-08 13:12:02 -0600274 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -0400275 size_t vertexStride = this->gp()->getVertexStride();
Chris Daltonfebbffa2017-06-08 13:12:02 -0600276 SkASSERT(vertexStride == sizeof(Vertex));
277 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
278 if (!verts) {
279 return;
280 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400281 SkRect rect = this->rect();
Cary Clark74f623d2017-11-06 20:02:02 -0500282 SkPointPriv::SetRectTriStrip(&verts[0].fPosition, rect.fLeft, rect.fTop, rect.fRight,
283 rect.fBottom, sizeof(Vertex));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600284 for (int v = 0; v < 4; ++v) {
Cary Clarke4442cb2017-10-18 11:46:18 -0400285 SkPoint3 pt3 = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
286 fKLM.mapHomogeneousPoints((SkPoint3* ) verts[v].fKLM, &pt3, 1);
Chris Daltonfebbffa2017-06-08 13:12:02 -0600287 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400288 helper.recordDraw(target, this->gp(), this->makePipeline(target));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600289 }
290
291 SkMatrix fKLM;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600292
293 static constexpr int kVertsPerCubic = 4;
294 static constexpr int kIndicesPerCubic = 6;
295
Brian Salomon477d0ef2017-07-14 10:12:26 -0400296 typedef BezierTestOp INHERITED;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600297};
298
299
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000300/**
301 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
302 */
303class BezierConicEffects : public GM {
304public:
305 BezierConicEffects() {
306 this->setBGColor(0xFFFFFFFF);
307 }
308
309protected:
mtklein36352bf2015-03-25 18:17:31 -0700310 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000311 return SkString("bezier_conic_effects");
312 }
313
mtklein36352bf2015-03-25 18:17:31 -0700314 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700315 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000316 }
317
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000318
mtklein36352bf2015-03-25 18:17:31 -0700319 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400320 GrRenderTargetContext* renderTargetContext =
321 canvas->internal_private_accessTopLayerRenderTargetContext();
322 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700323 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000324 return;
325 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000326
robertphillips175dd9b2016-04-28 14:32:04 -0700327 GrContext* context = canvas->getGrContext();
328 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800329 return;
330 }
331
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000332 struct Vertex {
333 SkPoint fPosition;
334 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
335 };
336
mtkleindbfd7ab2016-09-01 11:24:54 -0700337 constexpr int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000338 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000339
340 // Mult by 3 for each edge effect type
341 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
342 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400343 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
344 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000345 int row = 0;
346 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700347 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000348
349 for (int i = 0; i < kNumConics; ++i) {
350 SkPoint baseControlPts[] = {
351 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
352 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
353 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
354 };
355 SkScalar weight = rand.nextRangeF(0.f, 2.f);
Ethan Nicholas1706f842017-11-10 11:58:19 -0500356 for(int edgeType = 0; edgeType < kGrClipEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700357 sk_sp<GrGeometryProcessor> gp;
Ethan Nicholas0f3c7322017-11-09 14:51:17 -0500358 GrClipEdgeType et = (GrClipEdgeType)edgeType;
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400359 gp = GrConicEffect::Make(color, SkMatrix::I(), et, *context->contextPriv().caps(),
360 SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800361 if (!gp) {
362 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000363 }
364
Mike Reeddf85c382017-02-14 10:59:19 -0500365 SkScalar x = col * w;
366 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000367 SkPoint controlPts[] = {
368 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
369 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
370 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
371 };
372 SkConic dst[4];
csmartdaltoncc261272017-03-23 13:38:45 -0600373 SkMatrix klm;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000374 int cnt = chop_conic(controlPts, dst, weight);
csmartdaltoncc261272017-03-23 13:38:45 -0600375 GrPathUtils::getConicKLM(controlPts, weight, &klm);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000376
377 SkPaint ctrlPtPaint;
378 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
379 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400380 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000381 }
382
383 SkPaint polyPaint;
384 polyPaint.setColor(0xffA0A0A0);
385 polyPaint.setStrokeWidth(0);
386 polyPaint.setStyle(SkPaint::kStroke_Style);
387 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
388
389 SkPaint choppedPtPaint;
390 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
391
392 for (int c = 0; c < cnt; ++c) {
393 SkPoint* pts = dst[c].fPts;
394 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400395 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000396 }
397
398 SkRect bounds;
399 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
400 //bounds.set(bPts, 2);
401 bounds.set(pts, 3);
402
403 SkPaint boundsPaint;
404 boundsPaint.setColor(0xff808080);
405 boundsPaint.setStrokeWidth(0);
406 boundsPaint.setStyle(SkPaint::kStroke_Style);
407 canvas->drawRect(bounds, boundsPaint);
408
Brian Salomon477d0ef2017-07-14 10:12:26 -0400409 std::unique_ptr<GrDrawOp> op = BezierConicTestOp::Make(gp, bounds, color, klm);
410 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000411 }
412 ++col;
413 if (numCols == col) {
414 col = 0;
415 ++row;
416 }
417 }
418 }
419 }
420
421private:
422 // Uses the max curvature function for quads to estimate
423 // where to chop the conic. If the max curvature is not
424 // found along the curve segment it will return 1 and
425 // dst[0] is the original conic. If it returns 2 the dst[0]
426 // and dst[1] are the two new conics.
427 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
428 SkScalar t = SkFindQuadMaxCurvature(src);
429 if (t == 0) {
430 if (dst) {
431 dst[0].set(src, weight);
432 }
433 return 1;
434 } else {
435 if (dst) {
436 SkConic conic;
437 conic.set(src, weight);
caryclark414c4292016-09-26 11:03:54 -0700438 if (!conic.chopAt(t, dst)) {
439 dst[0].set(src, weight);
440 return 1;
441 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000442 }
443 return 2;
444 }
445 }
446
447 // Calls split_conic on the entire conic and then once more on each subsection.
448 // Most cases will result in either 1 conic (chop point is not within t range)
449 // or 3 points (split once and then one subsection is split again).
450 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
451 SkConic dstTemp[2];
452 int conicCnt = split_conic(src, dstTemp, weight);
453 if (2 == conicCnt) {
454 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
455 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
456 } else {
457 dst[0] = dstTemp[0];
458 }
459 return conicCnt;
460 }
461
462 typedef GM INHERITED;
463};
464
465//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800466
Brian Salomon477d0ef2017-07-14 10:12:26 -0400467class BezierQuadTestOp : public BezierTestOp {
joshualitt95964c62015-02-11 13:45:50 -0800468public:
Brian Salomon25a88092016-12-01 09:36:50 -0500469 DEFINE_OP_CLASS_ID
Brian Salomon6b316e92016-12-16 09:35:49 -0500470 const char* name() const override { return "BezierQuadTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -0800471
Brian Salomon477d0ef2017-07-14 10:12:26 -0400472 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
473 GrColor color, const GrPathUtils::QuadUVMatrix& devToUV) {
474 return std::unique_ptr<GrDrawOp>(new BezierQuadTestOp(std::move(gp), rect, color, devToUV));
joshualitt95964c62015-02-11 13:45:50 -0800475 }
476
477private:
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500478 BezierQuadTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
Brian Salomon6b316e92016-12-16 09:35:49 -0500479 const GrPathUtils::QuadUVMatrix& devToUV)
Brian Salomon477d0ef2017-07-14 10:12:26 -0400480 : INHERITED(std::move(gp), rect, color, ClassID()), fDevToUV(devToUV) {}
joshualitt95964c62015-02-11 13:45:50 -0800481
482 struct Vertex {
483 SkPoint fPosition;
484 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
485 };
486
Brian Salomon91326c32017-08-09 16:02:19 -0400487 void onPrepareDraws(Target* target) override {
bsalomonb5238a72015-05-05 07:49:49 -0700488 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -0400489 size_t vertexStride = this->gp()->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700490 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700491 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700492 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800493 return;
494 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400495 SkRect rect = this->rect();
Brian Salomonec42e152018-05-18 12:52:22 -0400496 SkPointPriv::SetRectTriStrip(&verts[0].fPosition, rect, sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800497 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400498 helper.recordDraw(target, this->gp(), this->makePipeline(target));
joshualitt95964c62015-02-11 13:45:50 -0800499 }
500
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500501 GrPathUtils::QuadUVMatrix fDevToUV;
joshualitt95964c62015-02-11 13:45:50 -0800502
mtkleindbfd7ab2016-09-01 11:24:54 -0700503 static constexpr int kVertsPerCubic = 4;
504 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800505
Brian Salomon477d0ef2017-07-14 10:12:26 -0400506 typedef BezierTestOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800507};
508
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000509/**
510 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
511 */
512class BezierQuadEffects : public GM {
513public:
514 BezierQuadEffects() {
515 this->setBGColor(0xFFFFFFFF);
516 }
517
518protected:
mtklein36352bf2015-03-25 18:17:31 -0700519 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000520 return SkString("bezier_quad_effects");
521 }
522
mtklein36352bf2015-03-25 18:17:31 -0700523 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700524 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000525 }
526
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000527
mtklein36352bf2015-03-25 18:17:31 -0700528 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400529 GrRenderTargetContext* renderTargetContext =
530 canvas->internal_private_accessTopLayerRenderTargetContext();
531 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700532 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000533 return;
534 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000535
robertphillips175dd9b2016-04-28 14:32:04 -0700536 GrContext* context = canvas->getGrContext();
537 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800538 return;
539 }
540
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000541 struct Vertex {
542 SkPoint fPosition;
543 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
544 };
545
mtkleindbfd7ab2016-09-01 11:24:54 -0700546 constexpr int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000547 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000548
549 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
550 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400551 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
552 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000553 int row = 0;
554 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700555 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000556
557 for (int i = 0; i < kNumQuads; ++i) {
558 SkPoint baseControlPts[] = {
559 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
560 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
561 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
562 };
Ethan Nicholas1706f842017-11-10 11:58:19 -0500563 for(int edgeType = 0; edgeType < kGrClipEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700564 sk_sp<GrGeometryProcessor> gp;
Ethan Nicholas0f3c7322017-11-09 14:51:17 -0500565 GrClipEdgeType et = (GrClipEdgeType)edgeType;
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400566 gp = GrQuadEffect::Make(color, SkMatrix::I(), et, *context->contextPriv().caps(),
567 SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800568 if (!gp) {
569 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000570 }
571
Mike Reeddf85c382017-02-14 10:59:19 -0500572 SkScalar x = col * w;
573 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000574 SkPoint controlPts[] = {
575 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
576 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
577 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
578 };
579 SkPoint chopped[5];
580 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
581
582 SkPaint ctrlPtPaint;
583 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
584 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400585 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000586 }
587
588 SkPaint polyPaint;
589 polyPaint.setColor(0xffA0A0A0);
590 polyPaint.setStrokeWidth(0);
591 polyPaint.setStyle(SkPaint::kStroke_Style);
592 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
593
594 SkPaint choppedPtPaint;
595 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
596
597 for (int c = 0; c < cnt; ++c) {
598 SkPoint* pts = chopped + 2 * c;
599
600 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400601 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000602 }
603
604 SkRect bounds;
605 bounds.set(pts, 3);
606
607 SkPaint boundsPaint;
608 boundsPaint.setColor(0xff808080);
609 boundsPaint.setStrokeWidth(0);
610 boundsPaint.setStyle(SkPaint::kStroke_Style);
611 canvas->drawRect(bounds, boundsPaint);
612
robertphillips28a838e2016-06-23 14:07:00 -0700613 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500614 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
joshualitt3f284d72015-02-11 11:34:58 -0800615
joshualitt95964c62015-02-11 13:45:50 -0800616 GrPathUtils::QuadUVMatrix DevToUV(pts);
617
Brian Salomon477d0ef2017-07-14 10:12:26 -0400618 std::unique_ptr<GrDrawOp> op =
Brian Salomonf8334782017-01-03 09:42:58 -0500619 BezierQuadTestOp::Make(gp, bounds, color, DevToUV);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400620 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000621 }
622 ++col;
623 if (numCols == col) {
624 col = 0;
625 ++row;
626 }
627 }
628 }
629 }
630
631private:
632 typedef GM INHERITED;
633};
634
halcanary385fe4d2015-08-26 13:07:48 -0700635DEF_GM(return new BezierCubicEffects;)
636DEF_GM(return new BezierConicEffects;)
637DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000638}