blob: 55827ad76ef3dda4049d62357b19e5773d66dc89 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "gm/gm.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040011#include "include/core/SkBlendMode.h"
12#include "include/core/SkCanvas.h"
13#include "include/core/SkMatrix.h"
14#include "include/core/SkPaint.h"
15#include "include/core/SkPoint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "include/core/SkPoint3.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040017#include "include/core/SkRect.h"
18#include "include/core/SkRefCnt.h"
19#include "include/core/SkScalar.h"
20#include "include/core/SkSize.h"
21#include "include/core/SkString.h"
22#include "include/core/SkTypes.h"
Robert Phillipsb7bfbc22020-07-01 12:55:01 -040023#include "include/gpu/GrRecordingContext.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040024#include "include/private/SkColorData.h"
Robert Phillips59ba27b2022-04-12 09:59:38 -040025#include "include/private/gpu/ganesh/GrTypesPriv.h"
Kevin Lubick0d4d1142023-02-13 09:13:10 -050026#include "src/base/SkRandom.h"
Robert Phillips7a0d3c32021-07-21 15:39:51 -040027#include "src/core/SkCanvasPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050028#include "src/core/SkGeometry.h"
29#include "src/core/SkPointPriv.h"
Kevin Lubickacdc1082023-06-09 11:05:24 -040030#include "src/gpu/ganesh/GrCanvas.h"
Greg Daniel719239c2022-04-07 11:20:24 -040031#include "src/gpu/ganesh/GrCaps.h"
32#include "src/gpu/ganesh/GrDirectContextPriv.h"
33#include "src/gpu/ganesh/GrGeometryProcessor.h"
34#include "src/gpu/ganesh/GrMemoryPool.h"
35#include "src/gpu/ganesh/GrOpFlushState.h"
36#include "src/gpu/ganesh/GrOpsRenderPass.h"
37#include "src/gpu/ganesh/GrPaint.h"
38#include "src/gpu/ganesh/GrProcessorAnalysis.h"
39#include "src/gpu/ganesh/GrProcessorSet.h"
40#include "src/gpu/ganesh/GrProgramInfo.h"
41#include "src/gpu/ganesh/GrRecordingContextPriv.h"
42#include "src/gpu/ganesh/GrUserStencilSettings.h"
Robert Phillipsc1b94082022-08-09 17:16:19 -040043#include "src/gpu/ganesh/SurfaceDrawContext.h"
Greg Daniel719239c2022-04-07 11:20:24 -040044#include "src/gpu/ganesh/effects/GrBezierEffect.h"
45#include "src/gpu/ganesh/effects/GrPorterDuffXferProcessor.h"
46#include "src/gpu/ganesh/geometry/GrPathUtils.h"
47#include "src/gpu/ganesh/ops/GrDrawOp.h"
48#include "src/gpu/ganesh/ops/GrMeshDrawOp.h"
49#include "src/gpu/ganesh/ops/GrOp.h"
50#include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelper.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040051
52#include <memory>
53#include <utility>
54
55class GrAppliedClip;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000056
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000057namespace skiagm {
joshualitt95964c62015-02-11 13:45:50 -080058
Brian Salomon477d0ef2017-07-14 10:12:26 -040059class BezierTestOp : public GrMeshDrawOp {
60public:
61 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
62
Chris Dalton6ce447a2019-06-23 18:07:38 -060063 GrProcessorSet::Analysis finalize(
Chris Dalton57ab06c2021-04-22 12:57:28 -060064 const GrCaps& caps, const GrAppliedClip* clip, GrClampType clampType) override {
Chris Daltonb8fff0d2019-03-05 10:11:58 -070065 return fProcessorSet.finalize(
66 fColor, GrProcessorAnalysisCoverage::kSingleChannel, clip,
Chris Dalton57ab06c2021-04-22 12:57:28 -060067 &GrUserStencilSettings::kUnused, caps, clampType, &fColor);
Brian Salomon477d0ef2017-07-14 10:12:26 -040068 }
69
Robert Phillips294723d2021-06-17 09:23:58 -040070 void visitProxies(const GrVisitProxyFunc& func) const override {
Robert Phillips4f93c572020-03-18 08:13:53 -040071 if (fProgramInfo) {
72 fProgramInfo->visitFPProxies(func);
73 } else {
74 fProcessorSet.visitProxies(func);
75 }
Robert Phillipsb493eeb2017-09-13 13:10:52 -040076 }
77
Brian Salomon477d0ef2017-07-14 10:12:26 -040078protected:
John Stiles3b2c06c2020-06-17 12:45:57 -040079 BezierTestOp(const SkRect& rect, const SkPMColor4f& color, int32_t classID)
Brian Salomon477d0ef2017-07-14 10:12:26 -040080 : INHERITED(classID)
81 , fRect(rect)
82 , fColor(color)
Brian Salomon477d0ef2017-07-14 10:12:26 -040083 , fProcessorSet(SkBlendMode::kSrc) {
Greg Daniel5faf4742019-10-01 15:14:44 -040084 this->setBounds(rect, HasAABloat::kYes, IsHairline::kNo);
Brian Salomon477d0ef2017-07-14 10:12:26 -040085 }
86
Robert Phillipsce978572020-02-28 11:56:44 -050087 virtual GrGeometryProcessor* makeGP(const GrCaps& caps, SkArenaAlloc* arena) = 0;
Robert Phillips3968fcb2019-12-05 16:40:31 -050088
Robert Phillips2669a7b2020-03-12 12:07:19 -040089 GrProgramInfo* programInfo() override { return fProgramInfo; }
90
Robert Phillips4133dc42020-03-11 15:55:55 -040091 void onCreateProgramInfo(const GrCaps* caps,
92 SkArenaAlloc* arena,
Adlai Hollere2296f72020-11-19 13:41:26 -050093 const GrSurfaceProxyView& writeView,
Chris Dalton6aaf00f2021-07-13 13:26:39 -060094 bool usesMSAASurface,
Robert Phillips4133dc42020-03-11 15:55:55 -040095 GrAppliedClip&& appliedClip,
John Stiles52cb1d02021-06-02 11:58:05 -040096 const GrDstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -050097 GrXferBarrierFlags renderPassXferBarriers,
98 GrLoadOp colorLoadOp) override {
Robert Phillipsce978572020-02-28 11:56:44 -050099 auto gp = this->makeGP(*caps, arena);
100 if (!gp) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400101 return;
Robert Phillipsce978572020-02-28 11:56:44 -0500102 }
103
104 GrPipeline::InputFlags flags = GrPipeline::InputFlags::kNone;
105
Brian Salomon8afde5f2020-04-01 16:22:00 -0400106 fProgramInfo = GrSimpleMeshDrawOpHelper::CreateProgramInfo(caps, arena, writeView,
Chris Dalton2a26c502021-08-26 10:05:11 -0600107 usesMSAASurface,
Robert Phillips4133dc42020-03-11 15:55:55 -0400108 std::move(appliedClip),
109 dstProxyView, gp,
110 std::move(fProcessorSet),
111 GrPrimitiveType::kTriangles,
Greg Danield358cbe2020-09-11 09:33:54 -0400112 renderPassXferBarriers,
Greg Daniel42dbca52020-11-20 10:22:43 -0500113 colorLoadOp,
Robert Phillips4133dc42020-03-11 15:55:55 -0400114 flags);
Robert Phillipsce978572020-02-28 11:56:44 -0500115 }
116
Robert Phillipsce978572020-02-28 11:56:44 -0500117 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) final {
118 if (!fProgramInfo) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400119 this->createProgramInfo(flushState);
Robert Phillipsce978572020-02-28 11:56:44 -0500120 }
121
122 if (!fProgramInfo) {
123 return;
124 }
125
Chris Dalton765ed362020-03-16 17:34:44 -0600126 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
Robert Phillips787fd9d2021-03-22 14:48:09 -0400127 flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
Chris Dalton765ed362020-03-16 17:34:44 -0600128 flushState->drawMesh(*fMesh);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400129 }
130
Brian Salomon477d0ef2017-07-14 10:12:26 -0400131 const SkRect& rect() const { return fRect; }
Brian Osmancf860852018-10-31 14:04:39 -0400132 const SkPMColor4f& color() const { return fColor; }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400133
Robert Phillipsce978572020-02-28 11:56:44 -0500134protected:
Chris Daltoneb694b72020-03-16 09:25:50 -0600135 GrSimpleMesh* fMesh = nullptr; // filled in by the derived classes
Robert Phillipsce978572020-02-28 11:56:44 -0500136
Brian Salomon477d0ef2017-07-14 10:12:26 -0400137private:
Robert Phillipsce978572020-02-28 11:56:44 -0500138 SkRect fRect;
139 SkPMColor4f fColor;
Robert Phillipsce978572020-02-28 11:56:44 -0500140 GrProcessorSet fProcessorSet;
141 GrProgramInfo* fProgramInfo = nullptr;
Brian Salomon477d0ef2017-07-14 10:12:26 -0400142
John Stiles7571f9e2020-09-02 22:42:33 -0400143 using INHERITED = GrMeshDrawOp;
Brian Salomon477d0ef2017-07-14 10:12:26 -0400144};
145
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000146/**
147 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
148 */
Brian Salomon477d0ef2017-07-14 10:12:26 -0400149class BezierConicTestOp : public BezierTestOp {
Chris Daltonfebbffa2017-06-08 13:12:02 -0600150public:
151 DEFINE_OP_CLASS_ID
152
Robert Phillipsce978572020-02-28 11:56:44 -0500153 const char* name() const final { return "BezierConicTestOp"; }
Chris Daltonfebbffa2017-06-08 13:12:02 -0600154
Herb Derbyc76d4092020-10-07 16:46:15 -0400155 static GrOp::Owner Make(GrRecordingContext* context,
156 const SkRect& rect,
157 const SkPMColor4f& color,
158 const SkMatrix& klm) {
159 return GrOp::Make<BezierConicTestOp>(context, rect, color, klm);
Chris Daltonfebbffa2017-06-08 13:12:02 -0600160 }
161
162private:
Herb Derbyc76d4092020-10-07 16:46:15 -0400163 friend class ::GrOp; // for ctor
Robert Phillips7c525e62018-06-12 10:11:12 -0400164
John Stiles3b2c06c2020-06-17 12:45:57 -0400165 BezierConicTestOp(const SkRect& rect, const SkPMColor4f& color, const SkMatrix& klm)
166 : INHERITED(rect, color, ClassID())
167 , fKLM(klm) {}
Brian Salomon477d0ef2017-07-14 10:12:26 -0400168
Chris Daltonfebbffa2017-06-08 13:12:02 -0600169 struct Vertex {
170 SkPoint fPosition;
171 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
172 };
173
Robert Phillipsce978572020-02-28 11:56:44 -0500174 GrGeometryProcessor* makeGP(const GrCaps& caps, SkArenaAlloc* arena) final {
John Stiles3b2c06c2020-06-17 12:45:57 -0400175 auto tmp = GrConicEffect::Make(arena, this->color(), SkMatrix::I(), caps, SkMatrix::I(),
176 false);
Robert Phillipsce978572020-02-28 11:56:44 -0500177 if (!tmp) {
178 return nullptr;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500179 }
Robert Phillipsce978572020-02-28 11:56:44 -0500180 SkASSERT(tmp->vertexStride() == sizeof(Vertex));
181 return tmp;
182 }
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500183
Robert Phillips71143952021-06-17 14:55:07 -0400184 void onPrepareDraws(GrMeshDrawTarget* target) final {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000185 QuadHelper helper(target, sizeof(Vertex), 1);
186 Vertex* verts = reinterpret_cast<Vertex*>(helper.vertices());
Chris Daltonfebbffa2017-06-08 13:12:02 -0600187 if (!verts) {
188 return;
189 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400190 SkRect rect = this->rect();
Robert Phillipsce978572020-02-28 11:56:44 -0500191 SkPointPriv::SetRectTriStrip(&verts[0].fPosition, rect, sizeof(Vertex));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600192 for (int v = 0; v < 4; ++v) {
Cary Clarke4442cb2017-10-18 11:46:18 -0400193 SkPoint3 pt3 = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
194 fKLM.mapHomogeneousPoints((SkPoint3* ) verts[v].fKLM, &pt3, 1);
Chris Daltonfebbffa2017-06-08 13:12:02 -0600195 }
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700196
Robert Phillipsce978572020-02-28 11:56:44 -0500197 fMesh = helper.mesh();
Chris Daltonfebbffa2017-06-08 13:12:02 -0600198 }
199
200 SkMatrix fKLM;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600201
Brian Salomon9fa47cc2021-10-08 18:48:26 -0400202 inline static constexpr int kVertsPerCubic = 4;
203 inline static constexpr int kIndicesPerCubic = 6;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600204
John Stiles7571f9e2020-09-02 22:42:33 -0400205 using INHERITED = BezierTestOp;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600206};
207
208
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000209/**
210 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
211 */
Chris Dalton3a778372019-02-07 15:23:36 -0700212class BezierConicEffects : public GpuGM {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000213public:
214 BezierConicEffects() {
215 this->setBGColor(0xFFFFFFFF);
216 }
217
218protected:
Robert Phillips98f3fd92019-11-21 13:16:21 -0500219 static const int kNumConics = 10;
220 static const int kCellWidth = 128;
221 static const int kCellHeight = 128;
222
Leandro Lovisolo24fa2112023-08-15 19:05:17 +0000223 SkString getName() const override { return SkString("bezier_conic_effects"); }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000224
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000225 SkISize getISize() override { return SkISize::Make(kCellWidth, kNumConics * kCellHeight); }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000226
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400227 DrawResult onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) override {
Kevin Lubickacdc1082023-06-09 11:05:24 -0400228 auto sdc = skgpu::ganesh::TopDeviceSurfaceDrawContext(canvas);
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400229 if (!sdc) {
230 *errorMsg = kErrorMsg_DrawSkippedGpuOnly;
231 return DrawResult::kSkip;
232 }
Robert Phillips98f3fd92019-11-21 13:16:21 -0500233
234 const SkScalar w = kCellWidth, h = kCellHeight;
235 const SkPMColor4f kOpaqueBlack = SkPMColor4f::FromBytes_RGBA(0xff000000);
236
237 const SkPoint baseControlPts[kNumConics][3] = {
238 { { 0.31f * w, 0.01f * h}, { 0.48f * w, 0.74f * h }, { 0.19f * w, 0.33f * h } },
239 { { 0.00f * w, 0.07f * h}, { 0.30f * w, 0.70f * h }, { 0.47f * w, 0.37f * h } },
240 { { 0.15f * w, 0.23f * h}, { 0.49f * w, 0.87f * h }, { 0.85f * w, 0.66f * h } },
241 { { 0.09f * w, 0.15f * h}, { 0.42f * w, 0.33f * h }, { 0.17f * w, 0.38f * h } },
242 { { 0.98f * w, 0.54f * h}, { 0.83f * w, 0.91f * h }, { 0.62f * w, 0.40f * h } },
243 { { 0.96f * w, 0.65f * h}, { 0.03f * w, 0.79f * h }, { 0.24f * w, 0.56f * h } },
244 { { 0.57f * w, 0.12f * h}, { 0.33f * w, 0.67f * h }, { 0.59f * w, 0.33f * h } },
245 { { 0.12f * w, 0.72f * h}, { 0.69f * w, 0.85f * h }, { 0.46f * w, 0.32f * h } },
246 { { 0.27f * w, 0.49f * h}, { 0.41f * w, 0.02f * h }, { 0.11f * w, 0.42f * h } },
247 { { 0.40f * w, 0.13f * h}, { 0.83f * w, 0.30f * h }, { 0.31f * w, 0.68f * h } },
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000248 };
Robert Phillips98f3fd92019-11-21 13:16:21 -0500249 const SkScalar weights[kNumConics] = { 0.62f, 0.01f, 0.95f, 1.48f, 0.37f,
250 0.66f, 0.15f, 0.14f, 0.61f, 1.4f };
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000251
Robert Phillips98f3fd92019-11-21 13:16:21 -0500252 SkPaint ctrlPtPaint;
253 ctrlPtPaint.setColor(SK_ColorRED);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000254
Robert Phillips98f3fd92019-11-21 13:16:21 -0500255 SkPaint choppedPtPaint;
256 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000257
Robert Phillips98f3fd92019-11-21 13:16:21 -0500258 SkPaint polyPaint;
259 polyPaint.setColor(0xffA0A0A0);
260 polyPaint.setStrokeWidth(0);
261 polyPaint.setStyle(SkPaint::kStroke_Style);
262
263 SkPaint boundsPaint;
264 boundsPaint.setColor(0xff808080);
265 boundsPaint.setStrokeWidth(0);
266 boundsPaint.setStyle(SkPaint::kStroke_Style);
267
268
269 for (int row = 0; row < kNumConics; ++row) {
John Stiles3b2c06c2020-06-17 12:45:57 -0400270 SkScalar x = 0;
271 SkScalar y = row * h;
272 SkPoint controlPts[] = {
273 {x + baseControlPts[row][0].fX, y + baseControlPts[row][0].fY},
274 {x + baseControlPts[row][1].fX, y + baseControlPts[row][1].fY},
275 {x + baseControlPts[row][2].fX, y + baseControlPts[row][2].fY}
276 };
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000277
John Stiles3b2c06c2020-06-17 12:45:57 -0400278 for (int i = 0; i < 3; ++i) {
279 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
280 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000281
John Stiles3b2c06c2020-06-17 12:45:57 -0400282 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
283
284 SkConic dst[4];
285 SkMatrix klm;
286 int cnt = ChopConic(controlPts, dst, weights[row]);
287 GrPathUtils::getConicKLM(controlPts, weights[row], &klm);
288
289 for (int c = 0; c < cnt; ++c) {
290 SkPoint* pts = dst[c].fPts;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000291 for (int i = 0; i < 3; ++i) {
John Stiles3b2c06c2020-06-17 12:45:57 -0400292 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000293 }
294
John Stiles3b2c06c2020-06-17 12:45:57 -0400295 SkRect bounds;
296 bounds.setBounds(pts, 3);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000297
John Stiles3b2c06c2020-06-17 12:45:57 -0400298 canvas->drawRect(bounds, boundsPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000299
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400300 GrOp::Owner op = BezierConicTestOp::Make(rContext, bounds,
Herb Derbyc76d4092020-10-07 16:46:15 -0400301 kOpaqueBlack, klm);
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400302 sdc->addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000303 }
304 }
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400305
306 return DrawResult::kOk;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000307 }
308
309private:
310 // Uses the max curvature function for quads to estimate
311 // where to chop the conic. If the max curvature is not
312 // found along the curve segment it will return 1 and
313 // dst[0] is the original conic. If it returns 2 the dst[0]
314 // and dst[1] are the two new conics.
Robert Phillips98f3fd92019-11-21 13:16:21 -0500315 static int SplitConic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000316 SkScalar t = SkFindQuadMaxCurvature(src);
Chris Dalton1d474dd2018-07-24 01:08:31 -0600317 if (t == 0 || t == 1) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000318 if (dst) {
319 dst[0].set(src, weight);
320 }
321 return 1;
322 } else {
323 if (dst) {
324 SkConic conic;
325 conic.set(src, weight);
caryclark414c4292016-09-26 11:03:54 -0700326 if (!conic.chopAt(t, dst)) {
327 dst[0].set(src, weight);
328 return 1;
329 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000330 }
331 return 2;
332 }
333 }
334
Robert Phillips98f3fd92019-11-21 13:16:21 -0500335 // Calls SplitConic on the entire conic and then once more on each subsection.
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000336 // Most cases will result in either 1 conic (chop point is not within t range)
337 // or 3 points (split once and then one subsection is split again).
Robert Phillips98f3fd92019-11-21 13:16:21 -0500338 static int ChopConic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000339 SkConic dstTemp[2];
Robert Phillips98f3fd92019-11-21 13:16:21 -0500340 int conicCnt = SplitConic(src, dstTemp, weight);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000341 if (2 == conicCnt) {
Robert Phillips98f3fd92019-11-21 13:16:21 -0500342 int conicCnt2 = SplitConic(dstTemp[0].fPts, dst, dstTemp[0].fW);
343 conicCnt = conicCnt2 + SplitConic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000344 } else {
345 dst[0] = dstTemp[0];
346 }
347 return conicCnt;
348 }
349
John Stiles7571f9e2020-09-02 22:42:33 -0400350 using INHERITED = GM;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000351};
352
353//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800354
Brian Salomon477d0ef2017-07-14 10:12:26 -0400355class BezierQuadTestOp : public BezierTestOp {
joshualitt95964c62015-02-11 13:45:50 -0800356public:
Brian Salomon25a88092016-12-01 09:36:50 -0500357 DEFINE_OP_CLASS_ID
Brian Salomon6b316e92016-12-16 09:35:49 -0500358 const char* name() const override { return "BezierQuadTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -0800359
Herb Derbyc76d4092020-10-07 16:46:15 -0400360 static GrOp::Owner Make(GrRecordingContext* context,
361 const SkRect& rect,
362 const SkPMColor4f& color,
363 const GrPathUtils::QuadUVMatrix& devToUV) {
364 return GrOp::Make<BezierQuadTestOp>(context, rect, color, devToUV);
joshualitt95964c62015-02-11 13:45:50 -0800365 }
366
367private:
Herb Derbyc76d4092020-10-07 16:46:15 -0400368 friend class ::GrOp; // for ctor
Robert Phillips7c525e62018-06-12 10:11:12 -0400369
John Stiles3b2c06c2020-06-17 12:45:57 -0400370 BezierQuadTestOp(const SkRect& rect, const SkPMColor4f& color,
371 const GrPathUtils::QuadUVMatrix& devToUV)
372 : INHERITED(rect, color, ClassID())
373 , fDevToUV(devToUV) {}
joshualitt95964c62015-02-11 13:45:50 -0800374
375 struct Vertex {
376 SkPoint fPosition;
377 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
378 };
379
Robert Phillipsce978572020-02-28 11:56:44 -0500380 GrGeometryProcessor* makeGP(const GrCaps& caps, SkArenaAlloc* arena) final {
John Stiles3b2c06c2020-06-17 12:45:57 -0400381 auto tmp = GrQuadEffect::Make(arena, this->color(), SkMatrix::I(), caps, SkMatrix::I(),
382 false);
Robert Phillipsce978572020-02-28 11:56:44 -0500383 if (!tmp) {
384 return nullptr;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500385 }
Robert Phillipsce978572020-02-28 11:56:44 -0500386 SkASSERT(tmp->vertexStride() == sizeof(Vertex));
387 return tmp;
388 }
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500389
Robert Phillips71143952021-06-17 14:55:07 -0400390 void onPrepareDraws(GrMeshDrawTarget* target) final {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000391 QuadHelper helper(target, sizeof(Vertex), 1);
392 Vertex* verts = reinterpret_cast<Vertex*>(helper.vertices());
bsalomonb5238a72015-05-05 07:49:49 -0700393 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800394 return;
395 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400396 SkRect rect = this->rect();
Brian Salomonec42e152018-05-18 12:52:22 -0400397 SkPointPriv::SetRectTriStrip(&verts[0].fPosition, rect, sizeof(Vertex));
Brian Osman568bec72018-12-26 16:48:25 -0500398 fDevToUV.apply(verts, 4, sizeof(Vertex), sizeof(SkPoint));
Robert Phillipsce978572020-02-28 11:56:44 -0500399
400 fMesh = helper.mesh();
joshualitt95964c62015-02-11 13:45:50 -0800401 }
402
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500403 GrPathUtils::QuadUVMatrix fDevToUV;
joshualitt95964c62015-02-11 13:45:50 -0800404
Brian Salomon9fa47cc2021-10-08 18:48:26 -0400405 inline static constexpr int kVertsPerCubic = 4;
406 inline static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800407
John Stiles7571f9e2020-09-02 22:42:33 -0400408 using INHERITED = BezierTestOp;
joshualitt95964c62015-02-11 13:45:50 -0800409};
410
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000411/**
412 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
413 */
Chris Dalton3a778372019-02-07 15:23:36 -0700414class BezierQuadEffects : public GpuGM {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000415public:
416 BezierQuadEffects() {
417 this->setBGColor(0xFFFFFFFF);
418 }
419
420protected:
Robert Phillips98f3fd92019-11-21 13:16:21 -0500421 static const int kNumQuads = 5;
422 static const int kCellWidth = 128;
423 static const int kCellHeight = 128;
424
Leandro Lovisolo24fa2112023-08-15 19:05:17 +0000425 SkString getName() const override { return SkString("bezier_quad_effects"); }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000426
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000427 SkISize getISize() override { return SkISize::Make(kCellWidth, kNumQuads * kCellHeight); }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000428
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400429 DrawResult onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) override {
Kevin Lubickacdc1082023-06-09 11:05:24 -0400430 auto sdc = skgpu::ganesh::TopDeviceSurfaceDrawContext(canvas);
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400431 if (!sdc) {
432 *errorMsg = kErrorMsg_DrawSkippedGpuOnly;
433 return DrawResult::kSkip;
434 }
Robert Phillips98f3fd92019-11-21 13:16:21 -0500435
436 const SkScalar w = kCellWidth, h = kCellHeight;
437 const SkPMColor4f kOpaqueBlack = SkPMColor4f::FromBytes_RGBA(0xff000000);
438
439 const SkPoint baseControlPts[kNumQuads][3] = {
440 { { 0.31f * w, 0.01f * h}, { 0.48f * w, 0.74f * h }, { 0.19f * w, 0.33f * h } },
441 { { 0.00f * w, 0.07f * h}, { 0.30f * w, 0.70f * h }, { 0.47f * w, 0.37f * h } },
442 { { 0.15f * w, 0.23f * h}, { 0.49f * w, 0.87f * h }, { 0.85f * w, 0.66f * h } },
443 { { 0.09f * w, 0.15f * h}, { 0.42f * w, 0.33f * h }, { 0.17f * w, 0.38f * h } },
444 { { 0.98f * w, 0.54f * h}, { 0.83f * w, 0.91f * h }, { 0.62f * w, 0.40f * h } },
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000445 };
446
Robert Phillips98f3fd92019-11-21 13:16:21 -0500447 SkPaint ctrlPtPaint;
448 ctrlPtPaint.setColor(SK_ColorRED);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000449
Robert Phillips98f3fd92019-11-21 13:16:21 -0500450 SkPaint choppedPtPaint;
451 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000452
Robert Phillips98f3fd92019-11-21 13:16:21 -0500453 SkPaint polyPaint;
454 polyPaint.setColor(0xffA0A0A0);
455 polyPaint.setStrokeWidth(0);
456 polyPaint.setStyle(SkPaint::kStroke_Style);
457
458 SkPaint boundsPaint;
459 boundsPaint.setColor(0xff808080);
460 boundsPaint.setStrokeWidth(0);
461 boundsPaint.setStyle(SkPaint::kStroke_Style);
462
463 for (int row = 0; row < kNumQuads; ++row) {
John Stiles3b2c06c2020-06-17 12:45:57 -0400464 SkScalar x = 0;
465 SkScalar y = row * h;
466 SkPoint controlPts[] = {
467 {x + baseControlPts[row][0].fX, y + baseControlPts[row][0].fY},
468 {x + baseControlPts[row][1].fX, y + baseControlPts[row][1].fY},
469 {x + baseControlPts[row][2].fX, y + baseControlPts[row][2].fY}
470 };
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000471
John Stiles3b2c06c2020-06-17 12:45:57 -0400472 for (int i = 0; i < 3; ++i) {
473 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
474 }
475
476 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
477
478 SkPoint chopped[5];
479 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
480
481 for (int c = 0; c < cnt; ++c) {
482 SkPoint* pts = chopped + 2 * c;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000483
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000484 for (int i = 0; i < 3; ++i) {
John Stiles3b2c06c2020-06-17 12:45:57 -0400485 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000486 }
487
John Stiles3b2c06c2020-06-17 12:45:57 -0400488 SkRect bounds;
489 bounds.setBounds(pts, 3);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000490
John Stiles3b2c06c2020-06-17 12:45:57 -0400491 canvas->drawRect(bounds, boundsPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000492
John Stiles3b2c06c2020-06-17 12:45:57 -0400493 GrPathUtils::QuadUVMatrix DevToUV(pts);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000494
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400495 GrOp::Owner op = BezierQuadTestOp::Make(rContext, bounds,
Herb Derbyc76d4092020-10-07 16:46:15 -0400496 kOpaqueBlack, DevToUV);
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400497 sdc->addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000498 }
499 }
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400500
501 return DrawResult::kOk;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000502 }
503
504private:
John Stiles7571f9e2020-09-02 22:42:33 -0400505 using INHERITED = GM;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000506};
507
halcanary385fe4d2015-08-26 13:07:48 -0700508DEF_GM(return new BezierConicEffects;)
509DEF_GM(return new BezierQuadEffects;)
John Stilesa6841be2020-08-06 14:11:56 -0400510} // namespace skiagm