blob: 3a5548822e31a34df530ff36ee2a577fa43f3465 [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
Brian Osman9a725dd2017-09-20 09:53:22 -040030 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip,
31 GrPixelConfigIsClamped dstIsClamped) override {
Brian Salomon477d0ef2017-07-14 10:12:26 -040032 auto analysis = fProcessorSet.finalize(fColor, GrProcessorAnalysisCoverage::kSingleChannel,
Brian Osman9a725dd2017-09-20 09:53:22 -040033 clip, false, caps, dstIsClamped, &fColor);
Brian Salomon477d0ef2017-07-14 10:12:26 -040034 return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo;
35 }
36
Robert Phillipsf1748f52017-09-14 14:11:24 -040037 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -040038 fProcessorSet.visitProxies(func);
39 }
40
Brian Salomon477d0ef2017-07-14 10:12:26 -040041protected:
42 BezierTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color, int32_t classID)
43 : INHERITED(classID)
44 , fRect(rect)
45 , fColor(color)
46 , fGeometryProcessor(std::move(gp))
47 , fProcessorSet(SkBlendMode::kSrc) {
48 this->setBounds(rect, HasAABloat::kYes, IsZeroArea::kNo);
49 }
50
Brian Salomon91326c32017-08-09 16:02:19 -040051 const GrPipeline* makePipeline(Target* target) {
Brian Salomonbfd18cd2017-08-09 16:27:09 -040052 return target->makePipeline(0, std::move(fProcessorSet), target->detachAppliedClip());
Brian Salomon477d0ef2017-07-14 10:12:26 -040053 }
54
55 const GrGeometryProcessor* gp() const { return fGeometryProcessor.get(); }
56
57 const SkRect& rect() const { return fRect; }
58 GrColor color() const { return fColor; }
59
60private:
61 bool onCombineIfPossible(GrOp* op, const GrCaps& caps) override { return false; }
62
63 SkRect fRect;
64 GrColor fColor;
65 sk_sp<GrGeometryProcessor> fGeometryProcessor;
66 GrProcessorSet fProcessorSet;
67
68 typedef GrMeshDrawOp INHERITED;
69};
70
71class BezierCubicTestOp : public BezierTestOp {
joshualitt95964c62015-02-11 13:45:50 -080072public:
Brian Salomon25a88092016-12-01 09:36:50 -050073 DEFINE_OP_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -080074
Chris Daltonfebbffa2017-06-08 13:12:02 -060075 const char* name() const override { return "BezierCubicTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -080076
Brian Salomon477d0ef2017-07-14 10:12:26 -040077 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
78 GrColor color) {
79 return std::unique_ptr<GrDrawOp>(new BezierCubicTestOp(std::move(gp), rect, color));
Brian Salomon6b316e92016-12-16 09:35:49 -050080 }
81
82private:
Chris Daltonfebbffa2017-06-08 13:12:02 -060083 BezierCubicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color)
Brian Salomon477d0ef2017-07-14 10:12:26 -040084 : INHERITED(std::move(gp), rect, color, ClassID()) {}
joshualitt95964c62015-02-11 13:45:50 -080085
Brian Salomon91326c32017-08-09 16:02:19 -040086 void onPrepareDraws(Target* target) override {
bsalomonb5238a72015-05-05 07:49:49 -070087 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -040088 size_t vertexStride = this->gp()->getVertexStride();
Chris Daltonfebbffa2017-06-08 13:12:02 -060089 SkASSERT(vertexStride == sizeof(SkPoint));
90 SkPoint* pts = reinterpret_cast<SkPoint*>(helper.init(target, vertexStride, 1));
91 if (!pts) {
joshualitt4b31de82015-03-05 14:33:41 -080092 return;
93 }
Brian Salomon477d0ef2017-07-14 10:12:26 -040094 SkRect rect = this->rect();
95 pts[0].setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
96 helper.recordDraw(target, this->gp(), this->makePipeline(target));
joshualitt95964c62015-02-11 13:45:50 -080097 }
98
mtkleindbfd7ab2016-09-01 11:24:54 -070099 static constexpr int kVertsPerCubic = 4;
100 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800101
Brian Salomon477d0ef2017-07-14 10:12:26 -0400102 typedef BezierTestOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800103};
104
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000105/**
106 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
107 */
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000108class BezierCubicEffects : public GM {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000109public:
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000110 BezierCubicEffects() {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000111 this->setBGColor(0xFFFFFFFF);
112 }
113
114protected:
mtklein36352bf2015-03-25 18:17:31 -0700115 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000116 return SkString("bezier_cubic_effects");
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000117 }
118
mtklein36352bf2015-03-25 18:17:31 -0700119 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700120 return SkISize::Make(800, 800);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000121 }
122
mtklein36352bf2015-03-25 18:17:31 -0700123 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400124 GrRenderTargetContext* renderTargetContext =
125 canvas->internal_private_accessTopLayerRenderTargetContext();
126 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700127 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000128 return;
129 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000130
robertphillips175dd9b2016-04-28 14:32:04 -0700131 GrContext* context = canvas->getGrContext();
132 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800133 return;
134 }
135
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000136 struct Vertex {
137 SkPoint fPosition;
138 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
139 };
140
mtkleindbfd7ab2016-09-01 11:24:54 -0700141 constexpr int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000142 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000143
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000144 // Mult by 3 for each edge effect type
145 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
146 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400147 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
148 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000149 int row = 0;
150 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700151 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000152
153 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000154 SkPoint baseControlPts[] = {
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)},
158 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000159 };
Chris Daltonfebbffa2017-06-08 13:12:02 -0600160 for(GrPrimitiveEdgeType edgeType : {kFillBW_GrProcessorEdgeType,
161 kFillAA_GrProcessorEdgeType,
162 kHairlineAA_GrProcessorEdgeType}) {
Mike Reeddf85c382017-02-14 10:59:19 -0500163 SkScalar x = col * w;
164 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000165 SkPoint controlPts[] = {
166 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
167 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
168 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
169 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
170 };
171 SkPoint chopped[10];
csmartdaltoncc261272017-03-23 13:38:45 -0600172 SkMatrix klm;
Greg Daniel8199d942017-03-14 10:20:24 -0400173 int loopIndex;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000174 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
175 chopped,
csmartdaltoncc261272017-03-23 13:38:45 -0600176 &klm,
Greg Daniel8199d942017-03-14 10:20:24 -0400177 &loopIndex);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000178
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000179 SkPaint ctrlPtPaint;
180 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
Hal Canary23e474c2017-05-15 13:35:35 -0400181 canvas->drawCircle(controlPts[0], 8.f, ctrlPtPaint);
Greg Daniel8199d942017-03-14 10:20:24 -0400182 for (int i = 1; i < 4; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400183 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000184 }
185
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000186 SkPaint polyPaint;
187 polyPaint.setColor(0xffA0A0A0);
188 polyPaint.setStrokeWidth(0);
189 polyPaint.setStyle(SkPaint::kStroke_Style);
190 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000191
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000192 SkPaint choppedPtPaint;
193 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000194
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000195 for (int c = 0; c < cnt; ++c) {
196 SkPoint* pts = chopped + 3 * c;
197
198 for (int i = 0; i < 4; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400199 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000200 }
201
202 SkRect bounds;
203 bounds.set(pts, 4);
204
205 SkPaint boundsPaint;
206 boundsPaint.setColor(0xff808080);
207 boundsPaint.setStrokeWidth(0);
208 boundsPaint.setStyle(SkPaint::kStroke_Style);
209 canvas->drawRect(bounds, boundsPaint);
210
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000211
Chris Daltonfebbffa2017-06-08 13:12:02 -0600212 bool flipKL = (c == loopIndex && cnt != 3);
213 sk_sp<GrGeometryProcessor> gp = GrCubicEffect::Make(color, SkMatrix::I(), klm,
214 flipKL, edgeType,
215 *context->caps());
216 if (!gp) {
217 break;
Greg Daniel8199d942017-03-14 10:20:24 -0400218 }
219
Brian Salomon477d0ef2017-07-14 10:12:26 -0400220 std::unique_ptr<GrDrawOp> op =
Chris Daltonfebbffa2017-06-08 13:12:02 -0600221 BezierCubicTestOp::Make(std::move(gp), bounds, color);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400222 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000223 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000224 ++col;
225 if (numCols == col) {
226 col = 0;
227 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000228 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000229 }
230 }
231 }
232
233private:
234 typedef GM INHERITED;
235};
236
237//////////////////////////////////////////////////////////////////////////////
238
Brian Salomon477d0ef2017-07-14 10:12:26 -0400239class BezierConicTestOp : public BezierTestOp {
Chris Daltonfebbffa2017-06-08 13:12:02 -0600240public:
241 DEFINE_OP_CLASS_ID
242
243 const char* name() const override { return "BezierConicTestOp"; }
244
Brian Salomon477d0ef2017-07-14 10:12:26 -0400245 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
246 GrColor color, const SkMatrix& klm) {
247 return std::unique_ptr<GrMeshDrawOp>(
248 new BezierConicTestOp(std::move(gp), rect, color, klm));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600249 }
250
251private:
252 BezierConicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
253 const SkMatrix& klm)
Brian Salomon477d0ef2017-07-14 10:12:26 -0400254 : INHERITED(std::move(gp), rect, color, ClassID()), fKLM(klm) {}
255
Chris Daltonfebbffa2017-06-08 13:12:02 -0600256 struct Vertex {
257 SkPoint fPosition;
258 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
259 };
260
Brian Salomon91326c32017-08-09 16:02:19 -0400261 void onPrepareDraws(Target* target) override {
Chris Daltonfebbffa2017-06-08 13:12:02 -0600262 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -0400263 size_t vertexStride = this->gp()->getVertexStride();
Chris Daltonfebbffa2017-06-08 13:12:02 -0600264 SkASSERT(vertexStride == sizeof(Vertex));
265 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
266 if (!verts) {
267 return;
268 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400269 SkRect rect = this->rect();
270 verts[0].fPosition.setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
Chris Daltonfebbffa2017-06-08 13:12:02 -0600271 sizeof(Vertex));
272 for (int v = 0; v < 4; ++v) {
273 SkScalar pt3[3] = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
274 fKLM.mapHomogeneousPoints(verts[v].fKLM, pt3, 1);
275 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400276 helper.recordDraw(target, this->gp(), this->makePipeline(target));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600277 }
278
279 SkMatrix fKLM;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600280
281 static constexpr int kVertsPerCubic = 4;
282 static constexpr int kIndicesPerCubic = 6;
283
Brian Salomon477d0ef2017-07-14 10:12:26 -0400284 typedef BezierTestOp INHERITED;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600285};
286
287
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000288/**
289 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
290 */
291class BezierConicEffects : public GM {
292public:
293 BezierConicEffects() {
294 this->setBGColor(0xFFFFFFFF);
295 }
296
297protected:
mtklein36352bf2015-03-25 18:17:31 -0700298 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000299 return SkString("bezier_conic_effects");
300 }
301
mtklein36352bf2015-03-25 18:17:31 -0700302 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700303 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000304 }
305
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000306
mtklein36352bf2015-03-25 18:17:31 -0700307 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400308 GrRenderTargetContext* renderTargetContext =
309 canvas->internal_private_accessTopLayerRenderTargetContext();
310 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700311 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000312 return;
313 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000314
robertphillips175dd9b2016-04-28 14:32:04 -0700315 GrContext* context = canvas->getGrContext();
316 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800317 return;
318 }
319
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000320 struct Vertex {
321 SkPoint fPosition;
322 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
323 };
324
mtkleindbfd7ab2016-09-01 11:24:54 -0700325 constexpr int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000326 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000327
328 // Mult by 3 for each edge effect type
329 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
330 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400331 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
332 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000333 int row = 0;
334 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700335 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000336
337 for (int i = 0; i < kNumConics; ++i) {
338 SkPoint baseControlPts[] = {
339 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
340 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
341 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
342 };
343 SkScalar weight = rand.nextRangeF(0.f, 2.f);
joshualittb0a8a372014-09-23 09:50:21 -0700344 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700345 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800346 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700347 gp = GrConicEffect::Make(color, SkMatrix::I(), et,
348 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800349 if (!gp) {
350 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000351 }
352
Mike Reeddf85c382017-02-14 10:59:19 -0500353 SkScalar x = col * w;
354 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000355 SkPoint controlPts[] = {
356 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
357 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
358 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
359 };
360 SkConic dst[4];
csmartdaltoncc261272017-03-23 13:38:45 -0600361 SkMatrix klm;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000362 int cnt = chop_conic(controlPts, dst, weight);
csmartdaltoncc261272017-03-23 13:38:45 -0600363 GrPathUtils::getConicKLM(controlPts, weight, &klm);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000364
365 SkPaint ctrlPtPaint;
366 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
367 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400368 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000369 }
370
371 SkPaint polyPaint;
372 polyPaint.setColor(0xffA0A0A0);
373 polyPaint.setStrokeWidth(0);
374 polyPaint.setStyle(SkPaint::kStroke_Style);
375 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
376
377 SkPaint choppedPtPaint;
378 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
379
380 for (int c = 0; c < cnt; ++c) {
381 SkPoint* pts = dst[c].fPts;
382 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400383 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000384 }
385
386 SkRect bounds;
387 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
388 //bounds.set(bPts, 2);
389 bounds.set(pts, 3);
390
391 SkPaint boundsPaint;
392 boundsPaint.setColor(0xff808080);
393 boundsPaint.setStrokeWidth(0);
394 boundsPaint.setStyle(SkPaint::kStroke_Style);
395 canvas->drawRect(bounds, boundsPaint);
396
Brian Salomon477d0ef2017-07-14 10:12:26 -0400397 std::unique_ptr<GrDrawOp> op = BezierConicTestOp::Make(gp, bounds, color, klm);
398 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000399 }
400 ++col;
401 if (numCols == col) {
402 col = 0;
403 ++row;
404 }
405 }
406 }
407 }
408
409private:
410 // Uses the max curvature function for quads to estimate
411 // where to chop the conic. If the max curvature is not
412 // found along the curve segment it will return 1 and
413 // dst[0] is the original conic. If it returns 2 the dst[0]
414 // and dst[1] are the two new conics.
415 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
416 SkScalar t = SkFindQuadMaxCurvature(src);
417 if (t == 0) {
418 if (dst) {
419 dst[0].set(src, weight);
420 }
421 return 1;
422 } else {
423 if (dst) {
424 SkConic conic;
425 conic.set(src, weight);
caryclark414c4292016-09-26 11:03:54 -0700426 if (!conic.chopAt(t, dst)) {
427 dst[0].set(src, weight);
428 return 1;
429 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000430 }
431 return 2;
432 }
433 }
434
435 // Calls split_conic on the entire conic and then once more on each subsection.
436 // Most cases will result in either 1 conic (chop point is not within t range)
437 // or 3 points (split once and then one subsection is split again).
438 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
439 SkConic dstTemp[2];
440 int conicCnt = split_conic(src, dstTemp, weight);
441 if (2 == conicCnt) {
442 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
443 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
444 } else {
445 dst[0] = dstTemp[0];
446 }
447 return conicCnt;
448 }
449
450 typedef GM INHERITED;
451};
452
453//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800454
Brian Salomon477d0ef2017-07-14 10:12:26 -0400455class BezierQuadTestOp : public BezierTestOp {
joshualitt95964c62015-02-11 13:45:50 -0800456public:
Brian Salomon25a88092016-12-01 09:36:50 -0500457 DEFINE_OP_CLASS_ID
Brian Salomon6b316e92016-12-16 09:35:49 -0500458 const char* name() const override { return "BezierQuadTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -0800459
Brian Salomon477d0ef2017-07-14 10:12:26 -0400460 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect,
461 GrColor color, const GrPathUtils::QuadUVMatrix& devToUV) {
462 return std::unique_ptr<GrDrawOp>(new BezierQuadTestOp(std::move(gp), rect, color, devToUV));
joshualitt95964c62015-02-11 13:45:50 -0800463 }
464
465private:
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500466 BezierQuadTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
Brian Salomon6b316e92016-12-16 09:35:49 -0500467 const GrPathUtils::QuadUVMatrix& devToUV)
Brian Salomon477d0ef2017-07-14 10:12:26 -0400468 : INHERITED(std::move(gp), rect, color, ClassID()), fDevToUV(devToUV) {}
joshualitt95964c62015-02-11 13:45:50 -0800469
470 struct Vertex {
471 SkPoint fPosition;
472 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
473 };
474
Brian Salomon91326c32017-08-09 16:02:19 -0400475 void onPrepareDraws(Target* target) override {
bsalomonb5238a72015-05-05 07:49:49 -0700476 QuadHelper helper;
Brian Salomon477d0ef2017-07-14 10:12:26 -0400477 size_t vertexStride = this->gp()->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700478 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700479 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700480 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800481 return;
482 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400483 SkRect rect = this->rect();
484 verts[0].fPosition.setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
joshualitt95964c62015-02-11 13:45:50 -0800485 sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800486 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400487 helper.recordDraw(target, this->gp(), this->makePipeline(target));
joshualitt95964c62015-02-11 13:45:50 -0800488 }
489
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500490 GrPathUtils::QuadUVMatrix fDevToUV;
joshualitt95964c62015-02-11 13:45:50 -0800491
mtkleindbfd7ab2016-09-01 11:24:54 -0700492 static constexpr int kVertsPerCubic = 4;
493 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800494
Brian Salomon477d0ef2017-07-14 10:12:26 -0400495 typedef BezierTestOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800496};
497
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000498/**
499 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
500 */
501class BezierQuadEffects : public GM {
502public:
503 BezierQuadEffects() {
504 this->setBGColor(0xFFFFFFFF);
505 }
506
507protected:
mtklein36352bf2015-03-25 18:17:31 -0700508 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000509 return SkString("bezier_quad_effects");
510 }
511
mtklein36352bf2015-03-25 18:17:31 -0700512 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700513 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000514 }
515
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000516
mtklein36352bf2015-03-25 18:17:31 -0700517 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400518 GrRenderTargetContext* renderTargetContext =
519 canvas->internal_private_accessTopLayerRenderTargetContext();
520 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700521 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000522 return;
523 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000524
robertphillips175dd9b2016-04-28 14:32:04 -0700525 GrContext* context = canvas->getGrContext();
526 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800527 return;
528 }
529
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000530 struct Vertex {
531 SkPoint fPosition;
532 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
533 };
534
mtkleindbfd7ab2016-09-01 11:24:54 -0700535 constexpr int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000536 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000537
538 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
539 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400540 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
541 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000542 int row = 0;
543 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700544 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000545
546 for (int i = 0; i < kNumQuads; ++i) {
547 SkPoint baseControlPts[] = {
548 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
549 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
550 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
551 };
joshualittb0a8a372014-09-23 09:50:21 -0700552 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700553 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800554 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700555 gp = GrQuadEffect::Make(color, SkMatrix::I(), et,
556 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800557 if (!gp) {
558 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000559 }
560
Mike Reeddf85c382017-02-14 10:59:19 -0500561 SkScalar x = col * w;
562 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000563 SkPoint controlPts[] = {
564 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
565 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
566 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
567 };
568 SkPoint chopped[5];
569 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
570
571 SkPaint ctrlPtPaint;
572 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
573 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400574 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000575 }
576
577 SkPaint polyPaint;
578 polyPaint.setColor(0xffA0A0A0);
579 polyPaint.setStrokeWidth(0);
580 polyPaint.setStyle(SkPaint::kStroke_Style);
581 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
582
583 SkPaint choppedPtPaint;
584 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
585
586 for (int c = 0; c < cnt; ++c) {
587 SkPoint* pts = chopped + 2 * c;
588
589 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400590 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000591 }
592
593 SkRect bounds;
594 bounds.set(pts, 3);
595
596 SkPaint boundsPaint;
597 boundsPaint.setColor(0xff808080);
598 boundsPaint.setStrokeWidth(0);
599 boundsPaint.setStyle(SkPaint::kStroke_Style);
600 canvas->drawRect(bounds, boundsPaint);
601
robertphillips28a838e2016-06-23 14:07:00 -0700602 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500603 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
joshualitt3f284d72015-02-11 11:34:58 -0800604
joshualitt95964c62015-02-11 13:45:50 -0800605 GrPathUtils::QuadUVMatrix DevToUV(pts);
606
Brian Salomon477d0ef2017-07-14 10:12:26 -0400607 std::unique_ptr<GrDrawOp> op =
Brian Salomonf8334782017-01-03 09:42:58 -0500608 BezierQuadTestOp::Make(gp, bounds, color, DevToUV);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400609 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000610 }
611 ++col;
612 if (numCols == col) {
613 col = 0;
614 ++row;
615 }
616 }
617 }
618 }
619
620private:
621 typedef GM INHERITED;
622};
623
halcanary385fe4d2015-08-26 13:07:48 -0700624DEF_GM(return new BezierCubicEffects;)
625DEF_GM(return new BezierConicEffects;)
626DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000627}
628
629#endif