blob: d3f1965d4f1affbd5ddc970264bb3f66e7202d93 [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
Brian Osman11052242016-10-27 14:47:55 -040014#include "GrRenderTargetContextPriv.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000015#include "GrContext.h"
16#include "GrPathUtils.h"
17#include "GrTest.h"
18#include "SkColorPriv.h"
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000019#include "SkGeometry.h"
20
Brian Salomon89527432016-12-16 09:52:16 -050021#include "ops/GrTestMeshDrawOp.h"
joshualitt2771b562015-08-07 12:46:26 -070022
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000023#include "effects/GrBezierEffect.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 Salomon6b316e92016-12-16 09:35:49 -050027class BezierCubicOrConicTestOp : public GrTestMeshDrawOp {
joshualitt95964c62015-02-11 13:45:50 -080028public:
Brian Salomon25a88092016-12-01 09:36:50 -050029 DEFINE_OP_CLASS_ID
joshualitt95964c62015-02-11 13:45:50 -080030
Brian Salomon6b316e92016-12-16 09:35:49 -050031 const char* name() const override { return "BezierCubicOrConicTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -080032
Brian Salomond3ccb0a2017-04-03 10:38:00 -040033 static std::unique_ptr<GrLegacyMeshDrawOp> Make(sk_sp<GrGeometryProcessor> gp,
34 const SkRect& rect, GrColor color,
35 const SkMatrix& klm, SkScalar sign) {
36 return std::unique_ptr<GrLegacyMeshDrawOp>(
csmartdaltoncc261272017-03-23 13:38:45 -060037 new BezierCubicOrConicTestOp(gp, rect, color, klm, sign));
Brian Salomon6b316e92016-12-16 09:35:49 -050038 }
39
40private:
Brian Salomon9e50f7b2017-03-06 12:02:34 -050041 BezierCubicOrConicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
csmartdaltoncc261272017-03-23 13:38:45 -060042 const SkMatrix& klm, SkScalar sign)
43 : INHERITED(ClassID(), rect, color)
44 , fKLM(klm)
45 , fRect(rect)
46 , fGeometryProcessor(std::move(gp)) {
47 if (1 != sign) {
48 fKLM.postScale(sign, sign);
joshualitt95964c62015-02-11 13:45:50 -080049 }
joshualitt95964c62015-02-11 13:45:50 -080050 }
joshualitt95964c62015-02-11 13:45:50 -080051 struct Vertex {
52 SkPoint fPosition;
53 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
54 };
55
bsalomon342bfc22016-04-01 06:06:20 -070056 void onPrepareDraws(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -070057 QuadHelper helper;
bsalomon342bfc22016-04-01 06:06:20 -070058 size_t vertexStride = fGeometryProcessor->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -070059 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -070060 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -070061 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -080062 return;
63 }
Brian Salomon9e50f7b2017-03-06 12:02:34 -050064 verts[0].fPosition.setRectFan(fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
joshualitt95964c62015-02-11 13:45:50 -080065 sizeof(Vertex));
66 for (int v = 0; v < 4; ++v) {
csmartdaltoncc261272017-03-23 13:38:45 -060067 SkScalar pt3[3] = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
68 fKLM.mapHomogeneousPoints(verts[v].fKLM, pt3, 1);
joshualitt95964c62015-02-11 13:45:50 -080069 }
Brian Salomond3ccb0a2017-04-03 10:38:00 -040070 helper.recordDraw(target, fGeometryProcessor.get(), this->pipeline());
joshualitt95964c62015-02-11 13:45:50 -080071 }
72
csmartdaltoncc261272017-03-23 13:38:45 -060073 SkMatrix fKLM;
Brian Salomon9e50f7b2017-03-06 12:02:34 -050074 SkRect fRect;
bungeman06ca8ec2016-06-09 08:01:03 -070075 sk_sp<GrGeometryProcessor> fGeometryProcessor;
joshualitt95964c62015-02-11 13:45:50 -080076
mtkleindbfd7ab2016-09-01 11:24:54 -070077 static constexpr int kVertsPerCubic = 4;
78 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -080079
Brian Salomon6b316e92016-12-16 09:35:49 -050080 typedef GrTestMeshDrawOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -080081};
82
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000083/**
84 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
85 */
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000086class BezierCubicEffects : public GM {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000087public:
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000088 BezierCubicEffects() {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000089 this->setBGColor(0xFFFFFFFF);
90 }
91
92protected:
mtklein36352bf2015-03-25 18:17:31 -070093 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000094 return SkString("bezier_cubic_effects");
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000095 }
96
mtklein36352bf2015-03-25 18:17:31 -070097 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -070098 return SkISize::Make(800, 800);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000099 }
100
mtklein36352bf2015-03-25 18:17:31 -0700101 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400102 GrRenderTargetContext* renderTargetContext =
103 canvas->internal_private_accessTopLayerRenderTargetContext();
104 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700105 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000106 return;
107 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000108
robertphillips175dd9b2016-04-28 14:32:04 -0700109 GrContext* context = canvas->getGrContext();
110 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800111 return;
112 }
113
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000114 struct Vertex {
115 SkPoint fPosition;
116 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
117 };
118
mtkleindbfd7ab2016-09-01 11:24:54 -0700119 constexpr int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000120 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000121
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000122 // Mult by 3 for each edge effect type
123 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
124 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400125 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
126 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000127 int row = 0;
128 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700129 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000130
131 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000132 SkPoint baseControlPts[] = {
133 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
134 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
135 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
136 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000137 };
joshualittb0a8a372014-09-23 09:50:21 -0700138 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700139 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800140 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700141 gp = GrCubicEffect::Make(color, SkMatrix::I(), et, *context->caps());
joshualittf5883a62016-01-13 07:47:38 -0800142 if (!gp) {
143 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000144 }
Mike Reeddf85c382017-02-14 10:59:19 -0500145 SkScalar x = col * w;
146 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000147 SkPoint controlPts[] = {
148 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
149 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
150 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
151 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
152 };
153 SkPoint chopped[10];
csmartdaltoncc261272017-03-23 13:38:45 -0600154 SkMatrix klm;
Greg Daniel8199d942017-03-14 10:20:24 -0400155 int loopIndex;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000156 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
157 chopped,
csmartdaltoncc261272017-03-23 13:38:45 -0600158 &klm,
Greg Daniel8199d942017-03-14 10:20:24 -0400159 &loopIndex);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000160
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000161 SkPaint ctrlPtPaint;
162 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
Hal Canary23e474c2017-05-15 13:35:35 -0400163 canvas->drawCircle(controlPts[0], 8.f, ctrlPtPaint);
Greg Daniel8199d942017-03-14 10:20:24 -0400164 for (int i = 1; i < 4; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400165 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000166 }
167
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000168 SkPaint polyPaint;
169 polyPaint.setColor(0xffA0A0A0);
170 polyPaint.setStrokeWidth(0);
171 polyPaint.setStyle(SkPaint::kStroke_Style);
172 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000173
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000174 SkPaint choppedPtPaint;
175 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000176
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000177 for (int c = 0; c < cnt; ++c) {
178 SkPoint* pts = chopped + 3 * c;
179
180 for (int i = 0; i < 4; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400181 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000182 }
183
184 SkRect bounds;
185 bounds.set(pts, 4);
186
187 SkPaint boundsPaint;
188 boundsPaint.setColor(0xff808080);
189 boundsPaint.setStrokeWidth(0);
190 boundsPaint.setStyle(SkPaint::kStroke_Style);
191 canvas->drawRect(bounds, boundsPaint);
192
robertphillips28a838e2016-06-23 14:07:00 -0700193 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500194 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000195
Greg Daniel8199d942017-03-14 10:20:24 -0400196 SkScalar sign = 1.0f;
197 if (c == loopIndex && cnt != 3) {
198 sign = -1.0f;
199 }
200
Brian Salomond3ccb0a2017-04-03 10:38:00 -0400201 std::unique_ptr<GrLegacyMeshDrawOp> op =
csmartdaltoncc261272017-03-23 13:38:45 -0600202 BezierCubicOrConicTestOp::Make(gp, bounds, color, klm, sign);
joshualitt95964c62015-02-11 13:45:50 -0800203
Brian Salomond3ccb0a2017-04-03 10:38:00 -0400204 renderTargetContext->priv().testingOnly_addLegacyMeshDrawOp(
Brian Salomon82f44312017-01-11 13:42:54 -0500205 std::move(grPaint), GrAAType::kNone, std::move(op));
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000206 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000207 ++col;
208 if (numCols == col) {
209 col = 0;
210 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000211 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000212 }
213 }
214 }
215
216private:
217 typedef GM INHERITED;
218};
219
220//////////////////////////////////////////////////////////////////////////////
221
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000222/**
223 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
224 */
225class BezierConicEffects : public GM {
226public:
227 BezierConicEffects() {
228 this->setBGColor(0xFFFFFFFF);
229 }
230
231protected:
mtklein36352bf2015-03-25 18:17:31 -0700232 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000233 return SkString("bezier_conic_effects");
234 }
235
mtklein36352bf2015-03-25 18:17:31 -0700236 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700237 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000238 }
239
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000240
mtklein36352bf2015-03-25 18:17:31 -0700241 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400242 GrRenderTargetContext* renderTargetContext =
243 canvas->internal_private_accessTopLayerRenderTargetContext();
244 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700245 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000246 return;
247 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000248
robertphillips175dd9b2016-04-28 14:32:04 -0700249 GrContext* context = canvas->getGrContext();
250 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800251 return;
252 }
253
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000254 struct Vertex {
255 SkPoint fPosition;
256 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
257 };
258
mtkleindbfd7ab2016-09-01 11:24:54 -0700259 constexpr int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000260 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000261
262 // Mult by 3 for each edge effect type
263 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
264 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400265 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
266 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000267 int row = 0;
268 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700269 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000270
271 for (int i = 0; i < kNumConics; ++i) {
272 SkPoint baseControlPts[] = {
273 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
274 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
275 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
276 };
277 SkScalar weight = rand.nextRangeF(0.f, 2.f);
joshualittb0a8a372014-09-23 09:50:21 -0700278 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700279 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800280 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700281 gp = GrConicEffect::Make(color, SkMatrix::I(), et,
282 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800283 if (!gp) {
284 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000285 }
286
Mike Reeddf85c382017-02-14 10:59:19 -0500287 SkScalar x = col * w;
288 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000289 SkPoint controlPts[] = {
290 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
291 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
292 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
293 };
294 SkConic dst[4];
csmartdaltoncc261272017-03-23 13:38:45 -0600295 SkMatrix klm;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000296 int cnt = chop_conic(controlPts, dst, weight);
csmartdaltoncc261272017-03-23 13:38:45 -0600297 GrPathUtils::getConicKLM(controlPts, weight, &klm);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000298
299 SkPaint ctrlPtPaint;
300 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
301 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400302 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000303 }
304
305 SkPaint polyPaint;
306 polyPaint.setColor(0xffA0A0A0);
307 polyPaint.setStrokeWidth(0);
308 polyPaint.setStyle(SkPaint::kStroke_Style);
309 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
310
311 SkPaint choppedPtPaint;
312 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
313
314 for (int c = 0; c < cnt; ++c) {
315 SkPoint* pts = dst[c].fPts;
316 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400317 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000318 }
319
320 SkRect bounds;
321 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
322 //bounds.set(bPts, 2);
323 bounds.set(pts, 3);
324
325 SkPaint boundsPaint;
326 boundsPaint.setColor(0xff808080);
327 boundsPaint.setStrokeWidth(0);
328 boundsPaint.setStyle(SkPaint::kStroke_Style);
329 canvas->drawRect(bounds, boundsPaint);
330
robertphillips28a838e2016-06-23 14:07:00 -0700331 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500332 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000333
Brian Salomond3ccb0a2017-04-03 10:38:00 -0400334 std::unique_ptr<GrLegacyMeshDrawOp> op =
csmartdaltoncc261272017-03-23 13:38:45 -0600335 BezierCubicOrConicTestOp::Make(gp, bounds, color, klm, 1.f);
joshualitt95964c62015-02-11 13:45:50 -0800336
Brian Salomond3ccb0a2017-04-03 10:38:00 -0400337 renderTargetContext->priv().testingOnly_addLegacyMeshDrawOp(
Brian Salomon82f44312017-01-11 13:42:54 -0500338 std::move(grPaint), GrAAType::kNone, std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000339 }
340 ++col;
341 if (numCols == col) {
342 col = 0;
343 ++row;
344 }
345 }
346 }
347 }
348
349private:
350 // Uses the max curvature function for quads to estimate
351 // where to chop the conic. If the max curvature is not
352 // found along the curve segment it will return 1 and
353 // dst[0] is the original conic. If it returns 2 the dst[0]
354 // and dst[1] are the two new conics.
355 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
356 SkScalar t = SkFindQuadMaxCurvature(src);
357 if (t == 0) {
358 if (dst) {
359 dst[0].set(src, weight);
360 }
361 return 1;
362 } else {
363 if (dst) {
364 SkConic conic;
365 conic.set(src, weight);
caryclark414c4292016-09-26 11:03:54 -0700366 if (!conic.chopAt(t, dst)) {
367 dst[0].set(src, weight);
368 return 1;
369 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000370 }
371 return 2;
372 }
373 }
374
375 // Calls split_conic on the entire conic and then once more on each subsection.
376 // Most cases will result in either 1 conic (chop point is not within t range)
377 // or 3 points (split once and then one subsection is split again).
378 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
379 SkConic dstTemp[2];
380 int conicCnt = split_conic(src, dstTemp, weight);
381 if (2 == conicCnt) {
382 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
383 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
384 } else {
385 dst[0] = dstTemp[0];
386 }
387 return conicCnt;
388 }
389
390 typedef GM INHERITED;
391};
392
393//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800394
Brian Salomon6b316e92016-12-16 09:35:49 -0500395class BezierQuadTestOp : public GrTestMeshDrawOp {
joshualitt95964c62015-02-11 13:45:50 -0800396public:
Brian Salomon25a88092016-12-01 09:36:50 -0500397 DEFINE_OP_CLASS_ID
Brian Salomon6b316e92016-12-16 09:35:49 -0500398 const char* name() const override { return "BezierQuadTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -0800399
Brian Salomond3ccb0a2017-04-03 10:38:00 -0400400 static std::unique_ptr<GrLegacyMeshDrawOp> Make(sk_sp<GrGeometryProcessor> gp,
401 const SkRect& rect, GrColor color,
402 const GrPathUtils::QuadUVMatrix& devToUV) {
403 return std::unique_ptr<GrLegacyMeshDrawOp>(new BezierQuadTestOp(gp, rect, color, devToUV));
joshualitt95964c62015-02-11 13:45:50 -0800404 }
405
406private:
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500407 BezierQuadTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color,
Brian Salomon6b316e92016-12-16 09:35:49 -0500408 const GrPathUtils::QuadUVMatrix& devToUV)
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500409 : INHERITED(ClassID(), rect, color)
Brian Salomon6b316e92016-12-16 09:35:49 -0500410 , fDevToUV(devToUV)
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500411 , fRect(rect)
Brian Salomon6b316e92016-12-16 09:35:49 -0500412 , fGeometryProcessor(std::move(gp)) {}
joshualitt95964c62015-02-11 13:45:50 -0800413
414 struct Vertex {
415 SkPoint fPosition;
416 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
417 };
418
bsalomon342bfc22016-04-01 06:06:20 -0700419 void onPrepareDraws(Target* target) const override {
bsalomonb5238a72015-05-05 07:49:49 -0700420 QuadHelper helper;
bsalomon342bfc22016-04-01 06:06:20 -0700421 size_t vertexStride = fGeometryProcessor->getVertexStride();
bsalomonb5238a72015-05-05 07:49:49 -0700422 SkASSERT(vertexStride == sizeof(Vertex));
bsalomon75398562015-08-17 12:55:38 -0700423 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
bsalomonb5238a72015-05-05 07:49:49 -0700424 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800425 return;
426 }
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500427 verts[0].fPosition.setRectFan(fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
joshualitt95964c62015-02-11 13:45:50 -0800428 sizeof(Vertex));
joshualitt95964c62015-02-11 13:45:50 -0800429 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
Brian Salomond3ccb0a2017-04-03 10:38:00 -0400430 helper.recordDraw(target, fGeometryProcessor.get(), this->pipeline());
joshualitt95964c62015-02-11 13:45:50 -0800431 }
432
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500433 GrPathUtils::QuadUVMatrix fDevToUV;
434 SkRect fRect;
bungeman06ca8ec2016-06-09 08:01:03 -0700435 sk_sp<GrGeometryProcessor> fGeometryProcessor;
joshualitt95964c62015-02-11 13:45:50 -0800436
mtkleindbfd7ab2016-09-01 11:24:54 -0700437 static constexpr int kVertsPerCubic = 4;
438 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800439
Brian Salomon6b316e92016-12-16 09:35:49 -0500440 typedef GrTestMeshDrawOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800441};
442
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000443/**
444 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
445 */
446class BezierQuadEffects : public GM {
447public:
448 BezierQuadEffects() {
449 this->setBGColor(0xFFFFFFFF);
450 }
451
452protected:
mtklein36352bf2015-03-25 18:17:31 -0700453 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000454 return SkString("bezier_quad_effects");
455 }
456
mtklein36352bf2015-03-25 18:17:31 -0700457 SkISize onISize() override {
tfarinaf5393182014-06-09 23:59:03 -0700458 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000459 }
460
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000461
mtklein36352bf2015-03-25 18:17:31 -0700462 void onDraw(SkCanvas* canvas) override {
Brian Osman11052242016-10-27 14:47:55 -0400463 GrRenderTargetContext* renderTargetContext =
464 canvas->internal_private_accessTopLayerRenderTargetContext();
465 if (!renderTargetContext) {
halcanary2a243382015-09-09 08:16:41 -0700466 skiagm::GM::DrawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000467 return;
468 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000469
robertphillips175dd9b2016-04-28 14:32:04 -0700470 GrContext* context = canvas->getGrContext();
471 if (!context) {
joshualittf5883a62016-01-13 07:47:38 -0800472 return;
473 }
474
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000475 struct Vertex {
476 SkPoint fPosition;
477 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
478 };
479
mtkleindbfd7ab2016-09-01 11:24:54 -0700480 constexpr int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000481 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000482
483 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
484 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
Brian Osman11052242016-10-27 14:47:55 -0400485 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols;
486 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000487 int row = 0;
488 int col = 0;
mtkleindbfd7ab2016-09-01 11:24:54 -0700489 constexpr GrColor color = 0xff000000;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000490
491 for (int i = 0; i < kNumQuads; ++i) {
492 SkPoint baseControlPts[] = {
493 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
494 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
495 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
496 };
joshualittb0a8a372014-09-23 09:50:21 -0700497 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
bungeman06ca8ec2016-06-09 08:01:03 -0700498 sk_sp<GrGeometryProcessor> gp;
joshualittf5883a62016-01-13 07:47:38 -0800499 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
bungeman06ca8ec2016-06-09 08:01:03 -0700500 gp = GrQuadEffect::Make(color, SkMatrix::I(), et,
501 *context->caps(), SkMatrix::I(), false);
joshualittf5883a62016-01-13 07:47:38 -0800502 if (!gp) {
503 continue;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000504 }
505
Mike Reeddf85c382017-02-14 10:59:19 -0500506 SkScalar x = col * w;
507 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000508 SkPoint controlPts[] = {
509 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
510 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
511 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
512 };
513 SkPoint chopped[5];
514 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
515
516 SkPaint ctrlPtPaint;
517 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
518 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400519 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000520 }
521
522 SkPaint polyPaint;
523 polyPaint.setColor(0xffA0A0A0);
524 polyPaint.setStrokeWidth(0);
525 polyPaint.setStyle(SkPaint::kStroke_Style);
526 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
527
528 SkPaint choppedPtPaint;
529 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
530
531 for (int c = 0; c < cnt; ++c) {
532 SkPoint* pts = chopped + 2 * c;
533
534 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400535 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000536 }
537
538 SkRect bounds;
539 bounds.set(pts, 3);
540
541 SkPaint boundsPaint;
542 boundsPaint.setColor(0xff808080);
543 boundsPaint.setStrokeWidth(0);
544 boundsPaint.setStyle(SkPaint::kStroke_Style);
545 canvas->drawRect(bounds, boundsPaint);
546
robertphillips28a838e2016-06-23 14:07:00 -0700547 GrPaint grPaint;
Brian Salomona1633922017-01-09 11:46:10 -0500548 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
joshualitt3f284d72015-02-11 11:34:58 -0800549
joshualitt95964c62015-02-11 13:45:50 -0800550 GrPathUtils::QuadUVMatrix DevToUV(pts);
551
Brian Salomond3ccb0a2017-04-03 10:38:00 -0400552 std::unique_ptr<GrLegacyMeshDrawOp> op =
Brian Salomonf8334782017-01-03 09:42:58 -0500553 BezierQuadTestOp::Make(gp, bounds, color, DevToUV);
joshualitt95964c62015-02-11 13:45:50 -0800554
Brian Salomond3ccb0a2017-04-03 10:38:00 -0400555 renderTargetContext->priv().testingOnly_addLegacyMeshDrawOp(
Brian Salomon82f44312017-01-11 13:42:54 -0500556 std::move(grPaint), GrAAType::kNone, std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000557 }
558 ++col;
559 if (numCols == col) {
560 col = 0;
561 ++row;
562 }
563 }
564 }
565 }
566
567private:
568 typedef GM INHERITED;
569};
570
halcanary385fe4d2015-08-26 13:07:48 -0700571DEF_GM(return new BezierCubicEffects;)
572DEF_GM(return new BezierConicEffects;)
573DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000574}
575
576#endif