blob: e61e0f39c59d31e19aa4a71a158b4f4703337554 [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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "include/gpu/GrContext.h"
24#include "include/private/GrRecordingContext.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040025#include "include/private/GrSharedEnums.h"
26#include "include/private/GrTypesPriv.h"
27#include "include/private/SkColorData.h"
28#include "include/utils/SkRandom.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#include "src/core/SkGeometry.h"
30#include "src/core/SkPointPriv.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040031#include "src/gpu/GrCaps.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050032#include "src/gpu/GrContextPriv.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040033#include "src/gpu/GrGeometryProcessor.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050034#include "src/gpu/GrMemoryPool.h"
35#include "src/gpu/GrOpFlushState.h"
Robert Phillipsce978572020-02-28 11:56:44 -050036#include "src/gpu/GrOpsRenderPass.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040037#include "src/gpu/GrPaint.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040038#include "src/gpu/GrProcessorAnalysis.h"
39#include "src/gpu/GrProcessorSet.h"
Robert Phillipsce978572020-02-28 11:56:44 -050040#include "src/gpu/GrProgramInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050041#include "src/gpu/GrRecordingContextPriv.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040042#include "src/gpu/GrRenderTargetContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050043#include "src/gpu/GrRenderTargetContextPriv.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040044#include "src/gpu/GrUserStencilSettings.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050045#include "src/gpu/effects/GrBezierEffect.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040046#include "src/gpu/effects/GrPorterDuffXferProcessor.h"
Michael Ludwig663afe52019-06-03 16:46:19 -040047#include "src/gpu/geometry/GrPathUtils.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040048#include "src/gpu/ops/GrDrawOp.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050049#include "src/gpu/ops/GrMeshDrawOp.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040050#include "src/gpu/ops/GrOp.h"
Robert Phillips3968fcb2019-12-05 16:40:31 -050051#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040052
53#include <memory>
54#include <utility>
55
56class GrAppliedClip;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000057
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000058namespace skiagm {
joshualitt95964c62015-02-11 13:45:50 -080059
Brian Salomon477d0ef2017-07-14 10:12:26 -040060class BezierTestOp : public GrMeshDrawOp {
61public:
62 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
63
Chris Dalton6ce447a2019-06-23 18:07:38 -060064 GrProcessorSet::Analysis finalize(
65 const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
66 GrClampType clampType) override {
Chris Daltonb8fff0d2019-03-05 10:11:58 -070067 return fProcessorSet.finalize(
68 fColor, GrProcessorAnalysisCoverage::kSingleChannel, clip,
Chris Dalton6ce447a2019-06-23 18:07:38 -060069 &GrUserStencilSettings::kUnused, hasMixedSampledCoverage, caps, clampType, &fColor);
Brian Salomon477d0ef2017-07-14 10:12:26 -040070 }
71
Chris Dalton1706cbf2019-05-21 19:35:29 -060072 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillips4f93c572020-03-18 08:13:53 -040073 if (fProgramInfo) {
74 fProgramInfo->visitFPProxies(func);
75 } else {
76 fProcessorSet.visitProxies(func);
77 }
Robert Phillipsb493eeb2017-09-13 13:10:52 -040078 }
79
Brian Salomon477d0ef2017-07-14 10:12:26 -040080protected:
Robert Phillips7cd0bfe2019-11-20 16:08:10 -050081 BezierTestOp(GrClipEdgeType et, const SkRect& rect, const SkPMColor4f& color, int32_t classID)
Brian Salomon477d0ef2017-07-14 10:12:26 -040082 : INHERITED(classID)
83 , fRect(rect)
84 , fColor(color)
Robert Phillips7cd0bfe2019-11-20 16:08:10 -050085 , fEdgeType(et)
Brian Salomon477d0ef2017-07-14 10:12:26 -040086 , fProcessorSet(SkBlendMode::kSrc) {
Greg Daniel5faf4742019-10-01 15:14:44 -040087 this->setBounds(rect, HasAABloat::kYes, IsHairline::kNo);
Brian Salomon477d0ef2017-07-14 10:12:26 -040088 }
89
Robert Phillipsce978572020-02-28 11:56:44 -050090 virtual GrGeometryProcessor* makeGP(const GrCaps& caps, SkArenaAlloc* arena) = 0;
Robert Phillips3968fcb2019-12-05 16:40:31 -050091
Robert Phillips2669a7b2020-03-12 12:07:19 -040092 GrProgramInfo* programInfo() override { return fProgramInfo; }
93
Robert Phillips4133dc42020-03-11 15:55:55 -040094 void onCreateProgramInfo(const GrCaps* caps,
95 SkArenaAlloc* arena,
Brian Salomon8afde5f2020-04-01 16:22:00 -040096 const GrSurfaceProxyView* writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -040097 GrAppliedClip&& appliedClip,
98 const GrXferProcessor::DstProxyView& dstProxyView) 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,
Robert Phillips4133dc42020-03-11 15:55:55 -0400107 std::move(appliedClip),
108 dstProxyView, gp,
109 std::move(fProcessorSet),
110 GrPrimitiveType::kTriangles,
111 flags);
Robert Phillipsce978572020-02-28 11:56:44 -0500112 }
113
Robert Phillipsce978572020-02-28 11:56:44 -0500114 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) final {
115 if (!fProgramInfo) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400116 this->createProgramInfo(flushState);
Robert Phillipsce978572020-02-28 11:56:44 -0500117 }
118
119 if (!fProgramInfo) {
120 return;
121 }
122
Chris Dalton765ed362020-03-16 17:34:44 -0600123 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
124 flushState->bindTextures(fProgramInfo->primProc(), nullptr, fProgramInfo->pipeline());
125 flushState->drawMesh(*fMesh);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400126 }
127
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500128 GrClipEdgeType edgeType() const { return fEdgeType; }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400129
130 const SkRect& rect() const { return fRect; }
Brian Osmancf860852018-10-31 14:04:39 -0400131 const SkPMColor4f& color() const { return fColor; }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400132
Robert Phillipsce978572020-02-28 11:56:44 -0500133protected:
Chris Daltoneb694b72020-03-16 09:25:50 -0600134 GrSimpleMesh* fMesh = nullptr; // filled in by the derived classes
Robert Phillipsce978572020-02-28 11:56:44 -0500135
Brian Salomon477d0ef2017-07-14 10:12:26 -0400136private:
Robert Phillipsce978572020-02-28 11:56:44 -0500137 SkRect fRect;
138 SkPMColor4f fColor;
139 GrClipEdgeType fEdgeType;
140 GrProcessorSet fProcessorSet;
141 GrProgramInfo* fProgramInfo = nullptr;
Brian Salomon477d0ef2017-07-14 10:12:26 -0400142
143 typedef GrMeshDrawOp INHERITED;
144};
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
Robert Phillipsbe9aff22019-02-15 11:33:22 -0500155 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500156 GrClipEdgeType et,
Robert Phillips7c525e62018-06-12 10:11:12 -0400157 const SkRect& rect,
Brian Osmancf860852018-10-31 14:04:39 -0400158 const SkPMColor4f& color,
Robert Phillips7c525e62018-06-12 10:11:12 -0400159 const SkMatrix& klm) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500160 GrOpMemoryPool* pool = context->priv().opMemoryPool();
Robert Phillipsc994a932018-06-19 13:09:54 -0400161
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500162 return pool->allocate<BezierConicTestOp>(et, rect, color, klm);
Chris Daltonfebbffa2017-06-08 13:12:02 -0600163 }
164
165private:
Robert Phillips7c525e62018-06-12 10:11:12 -0400166 friend class ::GrOpMemoryPool; // for ctor
167
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500168 BezierConicTestOp(GrClipEdgeType et, const SkRect& rect,
Brian Osmancf860852018-10-31 14:04:39 -0400169 const SkPMColor4f& color, const SkMatrix& klm)
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500170 : INHERITED(et, rect, color, ClassID()), fKLM(klm) {}
Brian Salomon477d0ef2017-07-14 10:12:26 -0400171
Chris Daltonfebbffa2017-06-08 13:12:02 -0600172 struct Vertex {
173 SkPoint fPosition;
174 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
175 };
176
Robert Phillipsce978572020-02-28 11:56:44 -0500177 GrGeometryProcessor* makeGP(const GrCaps& caps, SkArenaAlloc* arena) final {
178 auto tmp = GrConicEffect::Make(arena, this->color(), SkMatrix::I(), this->edgeType(),
179 caps, SkMatrix::I(), false);
180 if (!tmp) {
181 return nullptr;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500182 }
Robert Phillipsce978572020-02-28 11:56:44 -0500183 SkASSERT(tmp->vertexStride() == sizeof(Vertex));
184 return tmp;
185 }
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500186
Robert Phillipsce978572020-02-28 11:56:44 -0500187 void onPrepareDraws(Target* target) final {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000188 QuadHelper helper(target, sizeof(Vertex), 1);
189 Vertex* verts = reinterpret_cast<Vertex*>(helper.vertices());
Chris Daltonfebbffa2017-06-08 13:12:02 -0600190 if (!verts) {
191 return;
192 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400193 SkRect rect = this->rect();
Robert Phillipsce978572020-02-28 11:56:44 -0500194 SkPointPriv::SetRectTriStrip(&verts[0].fPosition, rect, sizeof(Vertex));
Chris Daltonfebbffa2017-06-08 13:12:02 -0600195 for (int v = 0; v < 4; ++v) {
Cary Clarke4442cb2017-10-18 11:46:18 -0400196 SkPoint3 pt3 = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
197 fKLM.mapHomogeneousPoints((SkPoint3* ) verts[v].fKLM, &pt3, 1);
Chris Daltonfebbffa2017-06-08 13:12:02 -0600198 }
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700199
Robert Phillipsce978572020-02-28 11:56:44 -0500200 fMesh = helper.mesh();
Chris Daltonfebbffa2017-06-08 13:12:02 -0600201 }
202
203 SkMatrix fKLM;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600204
205 static constexpr int kVertsPerCubic = 4;
206 static constexpr int kIndicesPerCubic = 6;
207
Brian Salomon477d0ef2017-07-14 10:12:26 -0400208 typedef BezierTestOp INHERITED;
Chris Daltonfebbffa2017-06-08 13:12:02 -0600209};
210
211
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000212/**
213 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
214 */
Chris Dalton3a778372019-02-07 15:23:36 -0700215class BezierConicEffects : public GpuGM {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000216public:
217 BezierConicEffects() {
218 this->setBGColor(0xFFFFFFFF);
219 }
220
221protected:
Robert Phillips98f3fd92019-11-21 13:16:21 -0500222 static const int kNumConics = 10;
223 static const int kCellWidth = 128;
224 static const int kCellHeight = 128;
225
mtklein36352bf2015-03-25 18:17:31 -0700226 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000227 return SkString("bezier_conic_effects");
228 }
229
mtklein36352bf2015-03-25 18:17:31 -0700230 SkISize onISize() override {
Robert Phillips98f3fd92019-11-21 13:16:21 -0500231 return SkISize::Make(kGrClipEdgeTypeCnt*kCellWidth, kNumConics*kCellHeight);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000232 }
233
Chris Dalton3a778372019-02-07 15:23:36 -0700234 void onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
235 SkCanvas* canvas) override {
Robert Phillips98f3fd92019-11-21 13:16:21 -0500236
237 const SkScalar w = kCellWidth, h = kCellHeight;
238 const SkPMColor4f kOpaqueBlack = SkPMColor4f::FromBytes_RGBA(0xff000000);
239
240 const SkPoint baseControlPts[kNumConics][3] = {
241 { { 0.31f * w, 0.01f * h}, { 0.48f * w, 0.74f * h }, { 0.19f * w, 0.33f * h } },
242 { { 0.00f * w, 0.07f * h}, { 0.30f * w, 0.70f * h }, { 0.47f * w, 0.37f * h } },
243 { { 0.15f * w, 0.23f * h}, { 0.49f * w, 0.87f * h }, { 0.85f * w, 0.66f * h } },
244 { { 0.09f * w, 0.15f * h}, { 0.42f * w, 0.33f * h }, { 0.17f * w, 0.38f * h } },
245 { { 0.98f * w, 0.54f * h}, { 0.83f * w, 0.91f * h }, { 0.62f * w, 0.40f * h } },
246 { { 0.96f * w, 0.65f * h}, { 0.03f * w, 0.79f * h }, { 0.24f * w, 0.56f * h } },
247 { { 0.57f * w, 0.12f * h}, { 0.33f * w, 0.67f * h }, { 0.59f * w, 0.33f * h } },
248 { { 0.12f * w, 0.72f * h}, { 0.69f * w, 0.85f * h }, { 0.46f * w, 0.32f * h } },
249 { { 0.27f * w, 0.49f * h}, { 0.41f * w, 0.02f * h }, { 0.11f * w, 0.42f * h } },
250 { { 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 +0000251 };
Robert Phillips98f3fd92019-11-21 13:16:21 -0500252 const SkScalar weights[kNumConics] = { 0.62f, 0.01f, 0.95f, 1.48f, 0.37f,
253 0.66f, 0.15f, 0.14f, 0.61f, 1.4f };
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000254
Robert Phillips98f3fd92019-11-21 13:16:21 -0500255 SkPaint ctrlPtPaint;
256 ctrlPtPaint.setColor(SK_ColorRED);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000257
Robert Phillips98f3fd92019-11-21 13:16:21 -0500258 SkPaint choppedPtPaint;
259 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000260
Robert Phillips98f3fd92019-11-21 13:16:21 -0500261 SkPaint polyPaint;
262 polyPaint.setColor(0xffA0A0A0);
263 polyPaint.setStrokeWidth(0);
264 polyPaint.setStyle(SkPaint::kStroke_Style);
265
266 SkPaint boundsPaint;
267 boundsPaint.setColor(0xff808080);
268 boundsPaint.setStrokeWidth(0);
269 boundsPaint.setStyle(SkPaint::kStroke_Style);
270
271
272 for (int row = 0; row < kNumConics; ++row) {
273 for(int col = 0; col < kGrClipEdgeTypeCnt; ++col) {
274 GrClipEdgeType et = (GrClipEdgeType) col;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000275
Mike Reeddf85c382017-02-14 10:59:19 -0500276 SkScalar x = col * w;
277 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000278 SkPoint controlPts[] = {
Robert Phillips98f3fd92019-11-21 13:16:21 -0500279 {x + baseControlPts[row][0].fX, y + baseControlPts[row][0].fY},
280 {x + baseControlPts[row][1].fX, y + baseControlPts[row][1].fY},
281 {x + baseControlPts[row][2].fX, y + baseControlPts[row][2].fY}
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000282 };
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000283
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000284 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400285 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000286 }
287
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000288 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
289
Robert Phillips98f3fd92019-11-21 13:16:21 -0500290 SkConic dst[4];
291 SkMatrix klm;
292 int cnt = ChopConic(controlPts, dst, weights[row]);
293 GrPathUtils::getConicKLM(controlPts, weights[row], &klm);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000294
295 for (int c = 0; c < cnt; ++c) {
296 SkPoint* pts = dst[c].fPts;
297 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400298 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000299 }
300
301 SkRect bounds;
Mike Reed92b33352019-08-24 19:39:13 -0400302 bounds.setBounds(pts, 3);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000303
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000304 canvas->drawRect(bounds, boundsPaint);
305
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500306 std::unique_ptr<GrDrawOp> op = BezierConicTestOp::Make(context, et, bounds,
Robert Phillips98f3fd92019-11-21 13:16:21 -0500307 kOpaqueBlack, klm);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400308 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000309 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000310 }
311 }
312 }
313
314private:
315 // Uses the max curvature function for quads to estimate
316 // where to chop the conic. If the max curvature is not
317 // found along the curve segment it will return 1 and
318 // dst[0] is the original conic. If it returns 2 the dst[0]
319 // and dst[1] are the two new conics.
Robert Phillips98f3fd92019-11-21 13:16:21 -0500320 static int SplitConic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000321 SkScalar t = SkFindQuadMaxCurvature(src);
Chris Dalton1d474dd2018-07-24 01:08:31 -0600322 if (t == 0 || t == 1) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000323 if (dst) {
324 dst[0].set(src, weight);
325 }
326 return 1;
327 } else {
328 if (dst) {
329 SkConic conic;
330 conic.set(src, weight);
caryclark414c4292016-09-26 11:03:54 -0700331 if (!conic.chopAt(t, dst)) {
332 dst[0].set(src, weight);
333 return 1;
334 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000335 }
336 return 2;
337 }
338 }
339
Robert Phillips98f3fd92019-11-21 13:16:21 -0500340 // Calls SplitConic on the entire conic and then once more on each subsection.
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000341 // Most cases will result in either 1 conic (chop point is not within t range)
342 // or 3 points (split once and then one subsection is split again).
Robert Phillips98f3fd92019-11-21 13:16:21 -0500343 static int ChopConic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000344 SkConic dstTemp[2];
Robert Phillips98f3fd92019-11-21 13:16:21 -0500345 int conicCnt = SplitConic(src, dstTemp, weight);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000346 if (2 == conicCnt) {
Robert Phillips98f3fd92019-11-21 13:16:21 -0500347 int conicCnt2 = SplitConic(dstTemp[0].fPts, dst, dstTemp[0].fW);
348 conicCnt = conicCnt2 + SplitConic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000349 } else {
350 dst[0] = dstTemp[0];
351 }
352 return conicCnt;
353 }
354
355 typedef GM INHERITED;
356};
357
358//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800359
Brian Salomon477d0ef2017-07-14 10:12:26 -0400360class BezierQuadTestOp : public BezierTestOp {
joshualitt95964c62015-02-11 13:45:50 -0800361public:
Brian Salomon25a88092016-12-01 09:36:50 -0500362 DEFINE_OP_CLASS_ID
Brian Salomon6b316e92016-12-16 09:35:49 -0500363 const char* name() const override { return "BezierQuadTestOp"; }
joshualitt95964c62015-02-11 13:45:50 -0800364
Michael Ludwig28b0c5d2019-12-19 14:51:00 -0500365 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500366 GrClipEdgeType et,
Robert Phillips7c525e62018-06-12 10:11:12 -0400367 const SkRect& rect,
Brian Osmancf860852018-10-31 14:04:39 -0400368 const SkPMColor4f& color,
Robert Phillips7c525e62018-06-12 10:11:12 -0400369 const GrPathUtils::QuadUVMatrix& devToUV) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500370 GrOpMemoryPool* pool = context->priv().opMemoryPool();
Robert Phillipsc994a932018-06-19 13:09:54 -0400371
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500372 return pool->allocate<BezierQuadTestOp>(et, rect, color, devToUV);
joshualitt95964c62015-02-11 13:45:50 -0800373 }
374
375private:
Robert Phillips7c525e62018-06-12 10:11:12 -0400376 friend class ::GrOpMemoryPool; // for ctor
377
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500378 BezierQuadTestOp(GrClipEdgeType et, const SkRect& rect,
Brian Osmancf860852018-10-31 14:04:39 -0400379 const SkPMColor4f& color, const GrPathUtils::QuadUVMatrix& devToUV)
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500380 : INHERITED(et, rect, color, ClassID()), fDevToUV(devToUV) {}
joshualitt95964c62015-02-11 13:45:50 -0800381
382 struct Vertex {
383 SkPoint fPosition;
384 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
385 };
386
Robert Phillipsce978572020-02-28 11:56:44 -0500387 GrGeometryProcessor* makeGP(const GrCaps& caps, SkArenaAlloc* arena) final {
388 auto tmp = GrQuadEffect::Make(arena, this->color(), SkMatrix::I(), this->edgeType(),
389 caps, SkMatrix::I(), false);
390 if (!tmp) {
391 return nullptr;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500392 }
Robert Phillipsce978572020-02-28 11:56:44 -0500393 SkASSERT(tmp->vertexStride() == sizeof(Vertex));
394 return tmp;
395 }
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500396
Robert Phillipsce978572020-02-28 11:56:44 -0500397 void onPrepareDraws(Target* target) final {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000398 QuadHelper helper(target, sizeof(Vertex), 1);
399 Vertex* verts = reinterpret_cast<Vertex*>(helper.vertices());
bsalomonb5238a72015-05-05 07:49:49 -0700400 if (!verts) {
joshualitt4b31de82015-03-05 14:33:41 -0800401 return;
402 }
Brian Salomon477d0ef2017-07-14 10:12:26 -0400403 SkRect rect = this->rect();
Brian Salomonec42e152018-05-18 12:52:22 -0400404 SkPointPriv::SetRectTriStrip(&verts[0].fPosition, rect, sizeof(Vertex));
Brian Osman568bec72018-12-26 16:48:25 -0500405 fDevToUV.apply(verts, 4, sizeof(Vertex), sizeof(SkPoint));
Robert Phillipsce978572020-02-28 11:56:44 -0500406
407 fMesh = helper.mesh();
joshualitt95964c62015-02-11 13:45:50 -0800408 }
409
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500410 GrPathUtils::QuadUVMatrix fDevToUV;
joshualitt95964c62015-02-11 13:45:50 -0800411
mtkleindbfd7ab2016-09-01 11:24:54 -0700412 static constexpr int kVertsPerCubic = 4;
413 static constexpr int kIndicesPerCubic = 6;
joshualitt95964c62015-02-11 13:45:50 -0800414
Brian Salomon477d0ef2017-07-14 10:12:26 -0400415 typedef BezierTestOp INHERITED;
joshualitt95964c62015-02-11 13:45:50 -0800416};
417
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000418/**
419 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
420 */
Chris Dalton3a778372019-02-07 15:23:36 -0700421class BezierQuadEffects : public GpuGM {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000422public:
423 BezierQuadEffects() {
424 this->setBGColor(0xFFFFFFFF);
425 }
426
427protected:
Robert Phillips98f3fd92019-11-21 13:16:21 -0500428 static const int kNumQuads = 5;
429 static const int kCellWidth = 128;
430 static const int kCellHeight = 128;
431
mtklein36352bf2015-03-25 18:17:31 -0700432 SkString onShortName() override {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000433 return SkString("bezier_quad_effects");
434 }
435
mtklein36352bf2015-03-25 18:17:31 -0700436 SkISize onISize() override {
Robert Phillips98f3fd92019-11-21 13:16:21 -0500437 return SkISize::Make(kGrClipEdgeTypeCnt*kCellWidth, kNumQuads*kCellHeight);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000438 }
439
Chris Dalton3a778372019-02-07 15:23:36 -0700440 void onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
441 SkCanvas* canvas) override {
Robert Phillips98f3fd92019-11-21 13:16:21 -0500442
443 const SkScalar w = kCellWidth, h = kCellHeight;
444 const SkPMColor4f kOpaqueBlack = SkPMColor4f::FromBytes_RGBA(0xff000000);
445
446 const SkPoint baseControlPts[kNumQuads][3] = {
447 { { 0.31f * w, 0.01f * h}, { 0.48f * w, 0.74f * h }, { 0.19f * w, 0.33f * h } },
448 { { 0.00f * w, 0.07f * h}, { 0.30f * w, 0.70f * h }, { 0.47f * w, 0.37f * h } },
449 { { 0.15f * w, 0.23f * h}, { 0.49f * w, 0.87f * h }, { 0.85f * w, 0.66f * h } },
450 { { 0.09f * w, 0.15f * h}, { 0.42f * w, 0.33f * h }, { 0.17f * w, 0.38f * h } },
451 { { 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 +0000452 };
453
Robert Phillips98f3fd92019-11-21 13:16:21 -0500454 SkPaint ctrlPtPaint;
455 ctrlPtPaint.setColor(SK_ColorRED);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000456
Robert Phillips98f3fd92019-11-21 13:16:21 -0500457 SkPaint choppedPtPaint;
458 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000459
Robert Phillips98f3fd92019-11-21 13:16:21 -0500460 SkPaint polyPaint;
461 polyPaint.setColor(0xffA0A0A0);
462 polyPaint.setStrokeWidth(0);
463 polyPaint.setStyle(SkPaint::kStroke_Style);
464
465 SkPaint boundsPaint;
466 boundsPaint.setColor(0xff808080);
467 boundsPaint.setStrokeWidth(0);
468 boundsPaint.setStyle(SkPaint::kStroke_Style);
469
470 for (int row = 0; row < kNumQuads; ++row) {
471 for(int col = 0; col < kGrClipEdgeTypeCnt; ++col) {
472 GrClipEdgeType et = (GrClipEdgeType) col;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000473
Mike Reeddf85c382017-02-14 10:59:19 -0500474 SkScalar x = col * w;
475 SkScalar y = row * h;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000476 SkPoint controlPts[] = {
Robert Phillips98f3fd92019-11-21 13:16:21 -0500477 {x + baseControlPts[row][0].fX, y + baseControlPts[row][0].fY},
478 {x + baseControlPts[row][1].fX, y + baseControlPts[row][1].fY},
479 {x + baseControlPts[row][2].fX, y + baseControlPts[row][2].fY}
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000480 };
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000481
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000482 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400483 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000484 }
485
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000486 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
487
Robert Phillips98f3fd92019-11-21 13:16:21 -0500488 SkPoint chopped[5];
489 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000490
491 for (int c = 0; c < cnt; ++c) {
492 SkPoint* pts = chopped + 2 * c;
493
494 for (int i = 0; i < 3; ++i) {
Hal Canary23e474c2017-05-15 13:35:35 -0400495 canvas->drawCircle(pts[i], 3.f, choppedPtPaint);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000496 }
497
498 SkRect bounds;
Mike Reed92b33352019-08-24 19:39:13 -0400499 bounds.setBounds(pts, 3);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000500
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000501 canvas->drawRect(bounds, boundsPaint);
502
joshualitt95964c62015-02-11 13:45:50 -0800503 GrPathUtils::QuadUVMatrix DevToUV(pts);
504
Robert Phillips98f3fd92019-11-21 13:16:21 -0500505 std::unique_ptr<GrDrawOp> op = BezierQuadTestOp::Make(context, et, bounds,
506 kOpaqueBlack, DevToUV);
Brian Salomon477d0ef2017-07-14 10:12:26 -0400507 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000508 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000509 }
510 }
511 }
512
513private:
514 typedef GM INHERITED;
515};
516
halcanary385fe4d2015-08-26 13:07:48 -0700517DEF_GM(return new BezierConicEffects;)
518DEF_GM(return new BezierQuadEffects;)
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000519}