blob: 9e8d1b8c39c3813f1599e7729c2f19792d746ef2 [file] [log] [blame]
Chris Daltonebb37e72021-01-27 17:59:45 -07001/*
2 * Copyright 2019 Google LLC.
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
Robert Phillipse453fa02021-08-19 14:57:05 -04008#include "src/gpu/ops/PathInnerTriangulateOp.h"
Chris Daltonebb37e72021-01-27 17:59:45 -07009
10#include "src/gpu/GrEagerVertexAllocator.h"
Chris Daltond9bdc322021-06-01 19:22:05 -060011#include "src/gpu/GrGpu.h"
Chris Daltonebb37e72021-01-27 17:59:45 -070012#include "src/gpu/GrOpFlushState.h"
13#include "src/gpu/GrRecordingContextPriv.h"
Robert Phillips1a82a4e2021-07-01 10:27:44 -040014#include "src/gpu/GrResourceProvider.h"
Chris Dalton2f733ec2021-06-01 12:11:57 -060015#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
Chris Daltond9bdc322021-06-01 19:22:05 -060016#include "src/gpu/tessellate/GrPathCurveTessellator.h"
Chris Dalton3b412782021-06-01 13:40:03 -060017#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
Chris Daltonebb37e72021-01-27 17:59:45 -070018
Robert Phillips832f3fb2021-08-18 13:05:15 -040019using PathFlags = GrTessellationPathFlags;
Chris Daltonebb37e72021-01-27 17:59:45 -070020
Chris Dalton2f733ec2021-06-01 12:11:57 -060021namespace {
22
23// Fills an array of convex hulls surrounding 4-point cubic or conic instances. This shader is used
Chris Dalton031d76b2021-06-08 16:32:00 -060024// for the "cover" pass after the curves have been fully stencilled.
Chris Dalton2f733ec2021-06-01 12:11:57 -060025class HullShader : public GrPathTessellationShader {
26public:
Chris Daltona05ccc32021-06-29 19:42:13 -060027 HullShader(const SkMatrix& viewMatrix, SkPMColor4f color, const GrShaderCaps& shaderCaps)
Chris Dalton2f733ec2021-06-01 12:11:57 -060028 : GrPathTessellationShader(kTessellate_HullShader_ClassID,
29 GrPrimitiveType::kTriangleStrip, 0, viewMatrix, color) {
Chris Dalton50516f32021-07-18 22:26:27 -060030 fInstanceAttribs.emplace_back("p01", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
31 fInstanceAttribs.emplace_back("p23", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
32 if (!shaderCaps.infinitySupport()) {
33 // A conic curve is written out with p3=[w,Infinity], but GPUs that don't support
34 // infinity can't detect this. On these platforms we also write out an extra float with
35 // each patch that explicitly tells the shader what type of curve it is.
36 fInstanceAttribs.emplace_back("curveType", kFloat_GrVertexAttribType, kFloat_GrSLType);
37 }
38 this->setInstanceAttributes(fInstanceAttribs.data(), fInstanceAttribs.count());
39 SkASSERT(fInstanceAttribs.count() <= kMaxInstanceAttribCount);
40
Chris Daltona05ccc32021-06-29 19:42:13 -060041 if (!shaderCaps.vertexIDSupport()) {
42 constexpr static Attribute kVertexIdxAttrib("vertexidx", kFloat_GrVertexAttribType,
43 kFloat_GrSLType);
44 this->setVertexAttributes(&kVertexIdxAttrib, 1);
45 }
Chris Dalton2f733ec2021-06-01 12:11:57 -060046 }
47
48private:
Chris Daltonb63711a2021-06-01 14:52:02 -060049 const char* name() const final { return "tessellate_HullShader"; }
Brian Salomon13b28732021-08-06 15:33:58 -040050 void addToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
Brian Salomonf95940b2021-08-09 15:56:24 -040051 std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const final;
Chris Dalton50516f32021-07-18 22:26:27 -060052
53 constexpr static int kMaxInstanceAttribCount = 3;
54 SkSTArray<kMaxInstanceAttribCount, Attribute> fInstanceAttribs;
Chris Dalton2f733ec2021-06-01 12:11:57 -060055};
56
Brian Salomonf95940b2021-08-09 15:56:24 -040057std::unique_ptr<GrGeometryProcessor::ProgramImpl> HullShader::makeProgramImpl(
58 const GrShaderCaps&) const {
Chris Dalton2f733ec2021-06-01 12:11:57 -060059 class Impl : public GrPathTessellationShader::Impl {
Chris Dalton69043032021-07-01 11:17:53 -060060 void emitVertexCode(const GrShaderCaps& shaderCaps, const GrPathTessellationShader&,
61 GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
Chris Dalton50516f32021-07-18 22:26:27 -060062 if (shaderCaps.infinitySupport()) {
63 v->insertFunction(R"(
64 bool is_conic_curve() { return isinf(p23.w); }
65 bool is_non_triangular_conic_curve() {
66 // We consider a conic non-triangular as long as its weight isn't infinity.
67 // NOTE: "isinf == false" works on Mac Radeon GLSL; "!isinf" can get the wrong
68 // answer.
69 return isinf(p23.z) == false;
70 })");
71 } else {
72 v->insertFunction(SkStringPrintf(R"(
73 bool is_conic_curve() { return curveType != %g; })", kCubicCurveType).c_str());
74 v->insertFunction(SkStringPrintf(R"(
75 bool is_non_triangular_conic_curve() {
76 return curveType == %g;
77 })", kConicCurveType).c_str());
78 }
Chris Dalton2f733ec2021-06-01 12:11:57 -060079 v->codeAppend(R"(
Chris Dalton202441f2021-06-30 22:48:30 -060080 float2 p0=p01.xy, p1=p01.zw, p2=p23.xy, p3=p23.zw;
Chris Dalton50516f32021-07-18 22:26:27 -060081 if (is_conic_curve()) {
82 // Conics are 3 points, with the weight in p3.
Chris Dalton202441f2021-06-30 22:48:30 -060083 float w = p3.x;
Chris Dalton50516f32021-07-18 22:26:27 -060084 p3 = p2; // Duplicate the endpoint for shared code that also runs on cubics.
85 if (is_non_triangular_conic_curve()) {
Chris Dalton2f733ec2021-06-01 12:11:57 -060086 // Convert the points to a trapeziodal hull that circumcscribes the conic.
Chris Dalton202441f2021-06-30 22:48:30 -060087 float2 p1w = p1 * w;
Chris Dalton2f733ec2021-06-01 12:11:57 -060088 float T = .51; // Bias outward a bit to ensure we cover the outermost samples.
Chris Dalton202441f2021-06-30 22:48:30 -060089 float2 c1 = mix(p0, p1w, T);
90 float2 c2 = mix(p2, p1w, T);
Chris Dalton2f733ec2021-06-01 12:11:57 -060091 float iw = 1 / mix(1, w, T);
Chris Dalton202441f2021-06-30 22:48:30 -060092 p2 = c2 * iw;
93 p1 = c1 * iw;
Chris Dalton2f733ec2021-06-01 12:11:57 -060094 }
95 }
96
97 // Translate the points to v0..3 where v0=0.
Chris Dalton202441f2021-06-30 22:48:30 -060098 float2 v1 = p1 - p0;
99 float2 v2 = p2 - p0;
100 float2 v3 = p3 - p0;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600101
102 // Reorder the points so v2 bisects v1 and v3.
Chris Dalton202441f2021-06-30 22:48:30 -0600103 if (sign(cross(v2, v1)) == sign(cross(v2, v3))) {
104 float2 tmp = p2;
105 if (sign(cross(v1, v2)) != sign(cross(v1, v3))) {
106 p2 = p1; // swap(p2, p1)
107 p1 = tmp;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600108 } else {
Chris Dalton202441f2021-06-30 22:48:30 -0600109 p2 = p3; // swap(p2, p3)
110 p3 = tmp;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600111 }
Chris Daltona05ccc32021-06-29 19:42:13 -0600112 })");
113
Chris Dalton69043032021-07-01 11:17:53 -0600114 if (shaderCaps.vertexIDSupport()) {
Chris Daltona05ccc32021-06-29 19:42:13 -0600115 // If we don't have sk_VertexID support then "vertexidx" already came in as a
116 // vertex attrib.
117 v->codeAppend(R"(
118 // sk_VertexID comes in fan order. Convert to strip order.
119 int vertexidx = sk_VertexID;
120 vertexidx ^= vertexidx >> 1;)");
Chris Dalton2f733ec2021-06-01 12:11:57 -0600121 }
122
Chris Daltona05ccc32021-06-29 19:42:13 -0600123 v->codeAppend(R"(
Chris Dalton2f733ec2021-06-01 12:11:57 -0600124 // Find the "turn direction" of each corner and net turn direction.
125 float vertexdir = 0;
126 float netdir = 0;
Chris Daltona05ccc32021-06-29 19:42:13 -0600127 float2 prev, next;
128 float dir;
129 float2 localcoord;
130 float2 nextcoord;)");
131
Chris Dalton2f733ec2021-06-01 12:11:57 -0600132 for (int i = 0; i < 4; ++i) {
Chris Daltona05ccc32021-06-29 19:42:13 -0600133 v->codeAppendf(R"(
Chris Dalton202441f2021-06-30 22:48:30 -0600134 prev = p%i - p%i;)", i, (i + 3) % 4);
Chris Daltona05ccc32021-06-29 19:42:13 -0600135 v->codeAppendf(R"(
Chris Dalton202441f2021-06-30 22:48:30 -0600136 next = p%i - p%i;)", (i + 1) % 4, i);
Chris Daltona05ccc32021-06-29 19:42:13 -0600137 v->codeAppendf(R"(
Chris Dalton202441f2021-06-30 22:48:30 -0600138 dir = sign(cross(prev, next));
Chris Daltona05ccc32021-06-29 19:42:13 -0600139 if (vertexidx == %i) {
Chris Dalton2f733ec2021-06-01 12:11:57 -0600140 vertexdir = dir;
Chris Dalton202441f2021-06-30 22:48:30 -0600141 localcoord = p%i;
142 nextcoord = p%i;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600143 }
Chris Daltona05ccc32021-06-29 19:42:13 -0600144 netdir += dir;)", i, i, (i + 1) % 4);
Chris Dalton2f733ec2021-06-01 12:11:57 -0600145 }
146
Chris Daltona05ccc32021-06-29 19:42:13 -0600147 v->codeAppend(R"(
Chris Dalton2f733ec2021-06-01 12:11:57 -0600148 // Remove the non-convex vertex, if any.
149 if (vertexdir != sign(netdir)) {
Chris Daltona05ccc32021-06-29 19:42:13 -0600150 localcoord = nextcoord;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600151 }
152
Chris Dalton2f733ec2021-06-01 12:11:57 -0600153 float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
154 gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
155 gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
156 }
157 };
Brian Salomonf95940b2021-08-09 15:56:24 -0400158 return std::make_unique<Impl>();
Chris Dalton2f733ec2021-06-01 12:11:57 -0600159}
160
Robert Phillips62bd6332021-08-26 09:56:55 -0400161} // anonymous namespace
Chris Dalton2f733ec2021-06-01 12:11:57 -0600162
Robert Phillips62bd6332021-08-26 09:56:55 -0400163namespace skgpu::v1 {
164
165void PathInnerTriangulateOp::visitProxies(const GrVisitProxyFunc& func) const {
Chris Daltonebb37e72021-01-27 17:59:45 -0700166 if (fPipelineForFills) {
Robert Phillips294723d2021-06-17 09:23:58 -0400167 fPipelineForFills->visitProxies(func);
Chris Daltonebb37e72021-01-27 17:59:45 -0700168 } else {
Robert Phillips294723d2021-06-17 09:23:58 -0400169 fProcessors.visitProxies(func);
Chris Daltonebb37e72021-01-27 17:59:45 -0700170 }
171}
172
Robert Phillips62bd6332021-08-26 09:56:55 -0400173GrDrawOp::FixedFunctionFlags PathInnerTriangulateOp::fixedFunctionFlags() const {
Chris Daltonebb37e72021-01-27 17:59:45 -0700174 auto flags = FixedFunctionFlags::kUsesStencil;
175 if (GrAAType::kNone != fAAType) {
176 flags |= FixedFunctionFlags::kUsesHWAA;
177 }
178 return flags;
179}
180
Robert Phillips62bd6332021-08-26 09:56:55 -0400181GrProcessorSet::Analysis PathInnerTriangulateOp::finalize(const GrCaps& caps,
182 const GrAppliedClip* clip,
183 GrClampType clampType) {
Chris Dalton57ab06c2021-04-22 12:57:28 -0600184 return fProcessors.finalize(fColor, GrProcessorAnalysisCoverage::kNone, clip, nullptr, caps,
185 clampType, &fColor);
Chris Daltonebb37e72021-01-27 17:59:45 -0700186}
187
Robert Phillips62bd6332021-08-26 09:56:55 -0400188void PathInnerTriangulateOp::pushFanStencilProgram(const GrTessellationShader::ProgramArgs& args,
189 const GrPipeline* pipelineForStencils,
190 const GrUserStencilSettings* stencil) {
Chris Daltona8c4de92021-07-26 21:46:28 +0000191 SkASSERT(pipelineForStencils);
192 auto shader = GrPathTessellationShader::MakeSimpleTriangleShader(args.fArena, fViewMatrix,
193 SK_PMColor4fTRANSPARENT);
194 fFanPrograms.push_back(GrTessellationShader::MakeProgram(args, shader, pipelineForStencils,
195 stencil)); }
196
Robert Phillips62bd6332021-08-26 09:56:55 -0400197void PathInnerTriangulateOp::pushFanFillProgram(const GrTessellationShader::ProgramArgs& args,
198 const GrUserStencilSettings* stencil) {
Chris Daltona8c4de92021-07-26 21:46:28 +0000199 SkASSERT(fPipelineForFills);
200 auto shader = GrPathTessellationShader::MakeSimpleTriangleShader(args.fArena, fViewMatrix,
201 fColor);
202 fFanPrograms.push_back(GrTessellationShader::MakeProgram(args, shader, fPipelineForFills,
203 stencil));
Chris Daltonebb37e72021-01-27 17:59:45 -0700204}
205
Robert Phillips62bd6332021-08-26 09:56:55 -0400206void PathInnerTriangulateOp::prePreparePrograms(const GrTessellationShader::ProgramArgs& args,
207 GrAppliedClip&& appliedClip) {
Chris Daltonebb37e72021-01-27 17:59:45 -0700208 SkASSERT(!fFanTriangulator);
209 SkASSERT(!fFanPolys);
210 SkASSERT(!fPipelineForFills);
211 SkASSERT(!fTessellator);
212 SkASSERT(!fStencilCurvesProgram);
213 SkASSERT(fFanPrograms.empty());
Chris Dalton031d76b2021-06-08 16:32:00 -0600214 SkASSERT(!fCoverHullsProgram);
Chris Daltonebb37e72021-01-27 17:59:45 -0700215
216 if (fPath.countVerbs() <= 0) {
217 return;
218 }
219
Chris Dalton031d76b2021-06-08 16:32:00 -0600220 // If using wireframe, we have to fall back on a standard Redbook "stencil then cover" algorithm
Chris Dalton57ab06c2021-04-22 12:57:28 -0600221 // instead of bypassing the stencil buffer to fill the fan directly.
Chris Dalton917f9192021-06-08 14:32:37 -0600222 bool forceRedbookStencilPass = (fPathFlags & (PathFlags::kStencilOnly | PathFlags::kWireframe));
223 bool doFill = !(fPathFlags & PathFlags::kStencilOnly);
Chris Daltonebb37e72021-01-27 17:59:45 -0700224
225 bool isLinear;
226 fFanTriangulator = args.fArena->make<GrInnerFanTriangulator>(fPath, args.fArena);
227 fFanPolys = fFanTriangulator->pathToPolys(&fFanBreadcrumbs, &isLinear);
228
229 // Create a pipeline for stencil passes if needed.
230 const GrPipeline* pipelineForStencils = nullptr;
231 if (forceRedbookStencilPass || !isLinear) { // Curves always get stencilled.
Chris Dalton2f733ec2021-06-01 12:11:57 -0600232 pipelineForStencils = GrPathTessellationShader::MakeStencilOnlyPipeline(
Chris Dalton917f9192021-06-08 14:32:37 -0600233 args, fAAType, fPathFlags, appliedClip.hardClip());
Chris Daltonebb37e72021-01-27 17:59:45 -0700234 }
235
236 // Create a pipeline for fill passes if needed.
237 if (doFill) {
Chris Dalton2f733ec2021-06-01 12:11:57 -0600238 fPipelineForFills = GrTessellationShader::MakePipeline(args, fAAType,
239 std::move(appliedClip),
240 std::move(fProcessors));
Chris Daltonebb37e72021-01-27 17:59:45 -0700241 }
242
243 // Pass 1: Tessellate the outer curves into the stencil buffer.
244 if (!isLinear) {
Chris Dalton26666bd2021-06-08 16:25:46 -0600245 fTessellator = GrPathCurveTessellator::Make(args.fArena, fViewMatrix,
246 SK_PMColor4fTRANSPARENT,
Chris Daltond2b8ba32021-06-09 00:12:59 -0600247 GrPathCurveTessellator::DrawInnerFan::kNo,
Chris Dalton198ac152021-06-09 13:49:43 -0600248 fPath.countVerbs(), *pipelineForStencils,
249 *args.fCaps);
Chris Dalton2f733ec2021-06-01 12:11:57 -0600250 const GrUserStencilSettings* stencilPathSettings =
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600251 GrPathTessellationShader::StencilPathSettings(GrFillRuleForSkPath(fPath));
Chris Dalton2f733ec2021-06-01 12:11:57 -0600252 fStencilCurvesProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(),
253 pipelineForStencils,
254 stencilPathSettings);
Chris Daltonebb37e72021-01-27 17:59:45 -0700255 }
256
257 // Pass 2: Fill the path's inner fan with a stencil test against the curves.
258 if (fFanPolys) {
259 if (forceRedbookStencilPass) {
Chris Dalton031d76b2021-06-08 16:32:00 -0600260 // Use a standard Redbook "stencil then cover" algorithm instead of bypassing the
261 // stencil buffer to fill the fan directly.
Chris Dalton2f733ec2021-06-01 12:11:57 -0600262 const GrUserStencilSettings* stencilPathSettings =
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600263 GrPathTessellationShader::StencilPathSettings(GrFillRuleForSkPath(fPath));
Chris Daltona8c4de92021-07-26 21:46:28 +0000264 this->pushFanStencilProgram(args, pipelineForStencils, stencilPathSettings);
Chris Daltonebb37e72021-01-27 17:59:45 -0700265 if (doFill) {
Chris Daltona8c4de92021-07-26 21:46:28 +0000266 this->pushFanFillProgram(args,
267 GrPathTessellationShader::TestAndResetStencilSettings());
Chris Daltonebb37e72021-01-27 17:59:45 -0700268 }
269 } else if (isLinear) {
270 // There are no outer curves! Ignore stencil and fill the path directly.
271 SkASSERT(!pipelineForStencils);
Chris Daltona8c4de92021-07-26 21:46:28 +0000272 this->pushFanFillProgram(args, &GrUserStencilSettings::kUnused);
Chris Daltonebb37e72021-01-27 17:59:45 -0700273 } else if (!fPipelineForFills->hasStencilClip()) {
274 // These are a twist on the standard Redbook stencil settings that allow us to fill the
275 // inner polygon directly to the final render target. By the time these programs
276 // execute, the outer curves will already be stencilled in. So if the stencil value is
277 // zero, then it means the sample in question is not affected by any curves and we can
278 // fill it in directly. If the stencil value is nonzero, then we don't fill and instead
279 // continue the standard Redbook counting process.
280 constexpr static GrUserStencilSettings kFillOrIncrDecrStencil(
281 GrUserStencilSettings::StaticInitSeparate<
282 0x0000, 0x0000,
283 GrUserStencilTest::kEqual, GrUserStencilTest::kEqual,
284 0xffff, 0xffff,
285 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
286 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
287 0xffff, 0xffff>());
288
289 constexpr static GrUserStencilSettings kFillOrInvertStencil(
290 GrUserStencilSettings::StaticInit<
291 0x0000,
292 GrUserStencilTest::kEqual,
293 0xffff,
294 GrUserStencilOp::kKeep,
295 // "Zero" instead of "Invert" because the fan only touches any given pixel once.
296 GrUserStencilOp::kZero,
297 0xffff>());
298
299 auto* stencil = (fPath.getFillType() == SkPathFillType::kWinding)
300 ? &kFillOrIncrDecrStencil
301 : &kFillOrInvertStencil;
Chris Daltona8c4de92021-07-26 21:46:28 +0000302 this->pushFanFillProgram(args, stencil);
Chris Daltonebb37e72021-01-27 17:59:45 -0700303 } else {
304 // This is the same idea as above, but we use two passes instead of one because there is
305 // a stencil clip. The stencil test isn't expressive enough to do the above tests and
306 // also check the clip bit in a single pass.
307 constexpr static GrUserStencilSettings kFillIfZeroAndInClip(
308 GrUserStencilSettings::StaticInit<
309 0x0000,
310 GrUserStencilTest::kEqualIfInClip,
311 0xffff,
312 GrUserStencilOp::kKeep,
313 GrUserStencilOp::kKeep,
314 0xffff>());
315
316 constexpr static GrUserStencilSettings kIncrDecrStencilIfNonzero(
317 GrUserStencilSettings::StaticInitSeparate<
318 0x0000, 0x0000,
319 // No need to check the clip because the previous stencil pass will have only
320 // written to samples already inside the clip.
321 GrUserStencilTest::kNotEqual, GrUserStencilTest::kNotEqual,
322 0xffff, 0xffff,
323 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
324 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
325 0xffff, 0xffff>());
326
327 constexpr static GrUserStencilSettings kInvertStencilIfNonZero(
328 GrUserStencilSettings::StaticInit<
329 0x0000,
330 // No need to check the clip because the previous stencil pass will have only
331 // written to samples already inside the clip.
332 GrUserStencilTest::kNotEqual,
333 0xffff,
334 // "Zero" instead of "Invert" because the fan only touches any given pixel once.
335 GrUserStencilOp::kZero,
336 GrUserStencilOp::kKeep,
337 0xffff>());
338
339 // Pass 2a: Directly fill fan samples whose stencil values (from curves) are zero.
Chris Daltona8c4de92021-07-26 21:46:28 +0000340 this->pushFanFillProgram(args, &kFillIfZeroAndInClip);
Chris Daltonebb37e72021-01-27 17:59:45 -0700341
342 // Pass 2b: Redbook counting on fan samples whose stencil values (from curves) != 0.
343 auto* stencil = (fPath.getFillType() == SkPathFillType::kWinding)
344 ? &kIncrDecrStencilIfNonzero
345 : &kInvertStencilIfNonZero;
Chris Daltona8c4de92021-07-26 21:46:28 +0000346 this->pushFanStencilProgram(args, pipelineForStencils, stencil);
Chris Daltonebb37e72021-01-27 17:59:45 -0700347 }
348 }
349
350 // Pass 3: Draw convex hulls around each curve.
351 if (doFill && !isLinear) {
352 // By the time this program executes, every pixel will be filled in except the ones touched
353 // by curves. We issue a final cover pass over the curves by drawing their convex hulls.
354 // This will fill in any remaining samples and reset the stencil values back to zero.
355 SkASSERT(fTessellator);
Chris Daltona05ccc32021-06-29 19:42:13 -0600356 auto* hullShader = args.fArena->make<HullShader>(fViewMatrix, fColor,
357 *args.fCaps->shaderCaps());
Chris Dalton031d76b2021-06-08 16:32:00 -0600358 fCoverHullsProgram = GrTessellationShader::MakeProgram(
Chris Daltonebb37e72021-01-27 17:59:45 -0700359 args, hullShader, fPipelineForFills,
Chris Dalton2f733ec2021-06-01 12:11:57 -0600360 GrPathTessellationShader::TestAndResetStencilSettings());
Chris Daltonebb37e72021-01-27 17:59:45 -0700361 }
362}
363
Robert Phillips62bd6332021-08-26 09:56:55 -0400364void PathInnerTriangulateOp::onPrePrepare(GrRecordingContext* context,
365 const GrSurfaceProxyView& writeView,
366 GrAppliedClip* clip,
367 const GrDstProxyView& dstProxyView,
368 GrXferBarrierFlags renderPassXferBarriers,
369 GrLoadOp colorLoadOp) {
Chris Dalton2a26c502021-08-26 10:05:11 -0600370 // DMSAA is not supported on DDL.
371 bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1;
372 this->prePreparePrograms({context->priv().recordTimeAllocator(), writeView, usesMSAASurface,
373 &dstProxyView, renderPassXferBarriers, colorLoadOp,
374 context->priv().caps()},
Chris Daltonebb37e72021-01-27 17:59:45 -0700375 (clip) ? std::move(*clip) : GrAppliedClip::Disabled());
376 if (fStencilCurvesProgram) {
377 context->priv().recordProgramInfo(fStencilCurvesProgram);
378 }
379 for (const GrProgramInfo* fanProgram : fFanPrograms) {
380 context->priv().recordProgramInfo(fanProgram);
381 }
Chris Dalton031d76b2021-06-08 16:32:00 -0600382 if (fCoverHullsProgram) {
383 context->priv().recordProgramInfo(fCoverHullsProgram);
Chris Daltonebb37e72021-01-27 17:59:45 -0700384 }
385}
386
Chris Daltona05ccc32021-06-29 19:42:13 -0600387GR_DECLARE_STATIC_UNIQUE_KEY(gHullVertexBufferKey);
388
Robert Phillips62bd6332021-08-26 09:56:55 -0400389void PathInnerTriangulateOp::onPrepare(GrOpFlushState* flushState) {
Chris Daltonebb37e72021-01-27 17:59:45 -0700390 if (!fFanTriangulator) {
391 this->prePreparePrograms({flushState->allocator(), flushState->writeView(),
Chris Dalton2a26c502021-08-26 10:05:11 -0600392 flushState->usesMSAASurface(), &flushState->dstProxyView(),
393 flushState->renderPassBarriers(), flushState->colorLoadOp(),
394 &flushState->caps()}, flushState->detachAppliedClip());
Chris Daltonebb37e72021-01-27 17:59:45 -0700395 if (!fFanTriangulator) {
396 return;
397 }
398 }
399
400 if (fFanPolys) {
401 GrEagerDynamicVertexAllocator alloc(flushState, &fFanBuffer, &fBaseFanVertex);
402 fFanVertexCount = fFanTriangulator->polysToTriangles(fFanPolys, &alloc, &fFanBreadcrumbs);
403 }
404
405 if (fTessellator) {
406 // Must be called after polysToTriangles() in order for fFanBreadcrumbs to be complete.
Chris Dalton17eaf622021-07-28 09:43:52 -0600407 fTessellator->prepare(flushState, this->bounds(), {SkMatrix::I(), fPath},
408 fPath.countVerbs(), &fFanBreadcrumbs);
Chris Daltonebb37e72021-01-27 17:59:45 -0700409 }
Chris Daltona05ccc32021-06-29 19:42:13 -0600410
411 if (!flushState->caps().shaderCaps()->vertexIDSupport()) {
412 constexpr static float kStripOrderIDs[4] = {0, 1, 3, 2};
413
414 GR_DEFINE_STATIC_UNIQUE_KEY(gHullVertexBufferKey);
415
416 fHullVertexBufferIfNoIDSupport = flushState->resourceProvider()->findOrMakeStaticBuffer(
417 GrGpuBufferType::kVertex, sizeof(kStripOrderIDs), kStripOrderIDs,
418 gHullVertexBufferKey);
419 }
Chris Daltonebb37e72021-01-27 17:59:45 -0700420}
421
Robert Phillips62bd6332021-08-26 09:56:55 -0400422void PathInnerTriangulateOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
Chris Daltonebb37e72021-01-27 17:59:45 -0700423 if (fStencilCurvesProgram) {
424 SkASSERT(fTessellator);
425 flushState->bindPipelineAndScissorClip(*fStencilCurvesProgram, this->bounds());
426 fTessellator->draw(flushState);
Chris Daltond9bdc322021-06-01 19:22:05 -0600427 if (flushState->caps().requiresManualFBBarrierAfterTessellatedStencilDraw()) {
428 flushState->gpu()->insertManualFramebufferBarrier(); // http://skbug.com/9739
429 }
Chris Daltonebb37e72021-01-27 17:59:45 -0700430 }
431
432 for (const GrProgramInfo* fanProgram : fFanPrograms) {
433 SkASSERT(fFanBuffer);
434 flushState->bindPipelineAndScissorClip(*fanProgram, this->bounds());
Robert Phillips787fd9d2021-03-22 14:48:09 -0400435 flushState->bindTextures(fanProgram->geomProc(), nullptr, fanProgram->pipeline());
Chris Daltonebb37e72021-01-27 17:59:45 -0700436 flushState->bindBuffers(nullptr, nullptr, fFanBuffer);
437 flushState->draw(fFanVertexCount, fBaseFanVertex);
438 }
439
Chris Dalton031d76b2021-06-08 16:32:00 -0600440 if (fCoverHullsProgram) {
Chris Daltonebb37e72021-01-27 17:59:45 -0700441 SkASSERT(fTessellator);
Chris Dalton031d76b2021-06-08 16:32:00 -0600442 flushState->bindPipelineAndScissorClip(*fCoverHullsProgram, this->bounds());
443 flushState->bindTextures(fCoverHullsProgram->geomProc(), nullptr, *fPipelineForFills);
Chris Daltona05ccc32021-06-29 19:42:13 -0600444 fTessellator->drawHullInstances(flushState, fHullVertexBufferIfNoIDSupport);
Chris Daltonebb37e72021-01-27 17:59:45 -0700445 }
Chris Daltonebb37e72021-01-27 17:59:45 -0700446}
Robert Phillips62bd6332021-08-26 09:56:55 -0400447
448} // namespace skgpu::v1