blob: 63466ce2c772914bcddbc8598e921c975828a5ec [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
8#include "src/gpu/tessellate/GrPathInnerTriangulateOp.h"
9
Chris Dalton09bc8af2021-07-19 11:02:39 -060010#include "src/gpu/GrDefaultGeoProcFactory.h"
Chris Daltonebb37e72021-01-27 17:59:45 -070011#include "src/gpu/GrEagerVertexAllocator.h"
Chris Daltond9bdc322021-06-01 19:22:05 -060012#include "src/gpu/GrGpu.h"
Chris Daltonebb37e72021-01-27 17:59:45 -070013#include "src/gpu/GrInnerFanTriangulator.h"
14#include "src/gpu/GrOpFlushState.h"
15#include "src/gpu/GrRecordingContextPriv.h"
Robert Phillips1a82a4e2021-07-01 10:27:44 -040016#include "src/gpu/GrResourceProvider.h"
Chris Dalton2f733ec2021-06-01 12:11:57 -060017#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
Chris Daltond9bdc322021-06-01 19:22:05 -060018#include "src/gpu/tessellate/GrPathCurveTessellator.h"
Chris Daltonebb37e72021-01-27 17:59:45 -070019#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
Chris Dalton3b412782021-06-01 13:40:03 -060020#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
Chris Daltonebb37e72021-01-27 17:59:45 -070021
Chris Dalton917f9192021-06-08 14:32:37 -060022using PathFlags = GrTessellationPathRenderer::PathFlags;
Chris Daltonebb37e72021-01-27 17:59:45 -070023
Chris Dalton2f733ec2021-06-01 12:11:57 -060024namespace {
25
26// Fills an array of convex hulls surrounding 4-point cubic or conic instances. This shader is used
Chris Dalton031d76b2021-06-08 16:32:00 -060027// for the "cover" pass after the curves have been fully stencilled.
Chris Dalton2f733ec2021-06-01 12:11:57 -060028class HullShader : public GrPathTessellationShader {
29public:
Chris Daltona05ccc32021-06-29 19:42:13 -060030 HullShader(const SkMatrix& viewMatrix, SkPMColor4f color, const GrShaderCaps& shaderCaps)
Chris Dalton2f733ec2021-06-01 12:11:57 -060031 : GrPathTessellationShader(kTessellate_HullShader_ClassID,
32 GrPrimitiveType::kTriangleStrip, 0, viewMatrix, color) {
Chris Dalton50516f32021-07-18 22:26:27 -060033 fInstanceAttribs.emplace_back("p01", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
34 fInstanceAttribs.emplace_back("p23", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
35 if (!shaderCaps.infinitySupport()) {
36 // A conic curve is written out with p3=[w,Infinity], but GPUs that don't support
37 // infinity can't detect this. On these platforms we also write out an extra float with
38 // each patch that explicitly tells the shader what type of curve it is.
39 fInstanceAttribs.emplace_back("curveType", kFloat_GrVertexAttribType, kFloat_GrSLType);
40 }
41 this->setInstanceAttributes(fInstanceAttribs.data(), fInstanceAttribs.count());
42 SkASSERT(fInstanceAttribs.count() <= kMaxInstanceAttribCount);
43
Chris Daltona05ccc32021-06-29 19:42:13 -060044 if (!shaderCaps.vertexIDSupport()) {
45 constexpr static Attribute kVertexIdxAttrib("vertexidx", kFloat_GrVertexAttribType,
46 kFloat_GrSLType);
47 this->setVertexAttributes(&kVertexIdxAttrib, 1);
48 }
Chris Dalton2f733ec2021-06-01 12:11:57 -060049 }
50
51private:
Chris Daltonb63711a2021-06-01 14:52:02 -060052 const char* name() const final { return "tessellate_HullShader"; }
Chris Dalton2f733ec2021-06-01 12:11:57 -060053 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
54 GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const final;
Chris Dalton50516f32021-07-18 22:26:27 -060055
56 constexpr static int kMaxInstanceAttribCount = 3;
57 SkSTArray<kMaxInstanceAttribCount, Attribute> fInstanceAttribs;
Chris Dalton2f733ec2021-06-01 12:11:57 -060058};
59
60GrGLSLGeometryProcessor* HullShader::createGLSLInstance(const GrShaderCaps&) const {
61 class Impl : public GrPathTessellationShader::Impl {
Chris Dalton69043032021-07-01 11:17:53 -060062 void emitVertexCode(const GrShaderCaps& shaderCaps, const GrPathTessellationShader&,
63 GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
Chris Dalton50516f32021-07-18 22:26:27 -060064 if (shaderCaps.infinitySupport()) {
65 v->insertFunction(R"(
66 bool is_conic_curve() { return isinf(p23.w); }
67 bool is_non_triangular_conic_curve() {
68 // We consider a conic non-triangular as long as its weight isn't infinity.
69 // NOTE: "isinf == false" works on Mac Radeon GLSL; "!isinf" can get the wrong
70 // answer.
71 return isinf(p23.z) == false;
72 })");
73 } else {
74 v->insertFunction(SkStringPrintf(R"(
75 bool is_conic_curve() { return curveType != %g; })", kCubicCurveType).c_str());
76 v->insertFunction(SkStringPrintf(R"(
77 bool is_non_triangular_conic_curve() {
78 return curveType == %g;
79 })", kConicCurveType).c_str());
80 }
Chris Dalton2f733ec2021-06-01 12:11:57 -060081 v->codeAppend(R"(
Chris Dalton202441f2021-06-30 22:48:30 -060082 float2 p0=p01.xy, p1=p01.zw, p2=p23.xy, p3=p23.zw;
Chris Dalton50516f32021-07-18 22:26:27 -060083 if (is_conic_curve()) {
84 // Conics are 3 points, with the weight in p3.
Chris Dalton202441f2021-06-30 22:48:30 -060085 float w = p3.x;
Chris Dalton50516f32021-07-18 22:26:27 -060086 p3 = p2; // Duplicate the endpoint for shared code that also runs on cubics.
87 if (is_non_triangular_conic_curve()) {
Chris Dalton2f733ec2021-06-01 12:11:57 -060088 // Convert the points to a trapeziodal hull that circumcscribes the conic.
Chris Dalton202441f2021-06-30 22:48:30 -060089 float2 p1w = p1 * w;
Chris Dalton2f733ec2021-06-01 12:11:57 -060090 float T = .51; // Bias outward a bit to ensure we cover the outermost samples.
Chris Dalton202441f2021-06-30 22:48:30 -060091 float2 c1 = mix(p0, p1w, T);
92 float2 c2 = mix(p2, p1w, T);
Chris Dalton2f733ec2021-06-01 12:11:57 -060093 float iw = 1 / mix(1, w, T);
Chris Dalton202441f2021-06-30 22:48:30 -060094 p2 = c2 * iw;
95 p1 = c1 * iw;
Chris Dalton2f733ec2021-06-01 12:11:57 -060096 }
97 }
98
99 // Translate the points to v0..3 where v0=0.
Chris Dalton202441f2021-06-30 22:48:30 -0600100 float2 v1 = p1 - p0;
101 float2 v2 = p2 - p0;
102 float2 v3 = p3 - p0;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600103
104 // Reorder the points so v2 bisects v1 and v3.
Chris Dalton202441f2021-06-30 22:48:30 -0600105 if (sign(cross(v2, v1)) == sign(cross(v2, v3))) {
106 float2 tmp = p2;
107 if (sign(cross(v1, v2)) != sign(cross(v1, v3))) {
108 p2 = p1; // swap(p2, p1)
109 p1 = tmp;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600110 } else {
Chris Dalton202441f2021-06-30 22:48:30 -0600111 p2 = p3; // swap(p2, p3)
112 p3 = tmp;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600113 }
Chris Daltona05ccc32021-06-29 19:42:13 -0600114 })");
115
Chris Dalton69043032021-07-01 11:17:53 -0600116 if (shaderCaps.vertexIDSupport()) {
Chris Daltona05ccc32021-06-29 19:42:13 -0600117 // If we don't have sk_VertexID support then "vertexidx" already came in as a
118 // vertex attrib.
119 v->codeAppend(R"(
120 // sk_VertexID comes in fan order. Convert to strip order.
121 int vertexidx = sk_VertexID;
122 vertexidx ^= vertexidx >> 1;)");
Chris Dalton2f733ec2021-06-01 12:11:57 -0600123 }
124
Chris Daltona05ccc32021-06-29 19:42:13 -0600125 v->codeAppend(R"(
Chris Dalton2f733ec2021-06-01 12:11:57 -0600126 // Find the "turn direction" of each corner and net turn direction.
127 float vertexdir = 0;
128 float netdir = 0;
Chris Daltona05ccc32021-06-29 19:42:13 -0600129 float2 prev, next;
130 float dir;
131 float2 localcoord;
132 float2 nextcoord;)");
133
Chris Dalton2f733ec2021-06-01 12:11:57 -0600134 for (int i = 0; i < 4; ++i) {
Chris Daltona05ccc32021-06-29 19:42:13 -0600135 v->codeAppendf(R"(
Chris Dalton202441f2021-06-30 22:48:30 -0600136 prev = p%i - p%i;)", i, (i + 3) % 4);
Chris Daltona05ccc32021-06-29 19:42:13 -0600137 v->codeAppendf(R"(
Chris Dalton202441f2021-06-30 22:48:30 -0600138 next = p%i - p%i;)", (i + 1) % 4, i);
Chris Daltona05ccc32021-06-29 19:42:13 -0600139 v->codeAppendf(R"(
Chris Dalton202441f2021-06-30 22:48:30 -0600140 dir = sign(cross(prev, next));
Chris Daltona05ccc32021-06-29 19:42:13 -0600141 if (vertexidx == %i) {
Chris Dalton2f733ec2021-06-01 12:11:57 -0600142 vertexdir = dir;
Chris Dalton202441f2021-06-30 22:48:30 -0600143 localcoord = p%i;
144 nextcoord = p%i;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600145 }
Chris Daltona05ccc32021-06-29 19:42:13 -0600146 netdir += dir;)", i, i, (i + 1) % 4);
Chris Dalton2f733ec2021-06-01 12:11:57 -0600147 }
148
Chris Daltona05ccc32021-06-29 19:42:13 -0600149 v->codeAppend(R"(
Chris Dalton2f733ec2021-06-01 12:11:57 -0600150 // Remove the non-convex vertex, if any.
151 if (vertexdir != sign(netdir)) {
Chris Daltona05ccc32021-06-29 19:42:13 -0600152 localcoord = nextcoord;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600153 }
154
Chris Dalton2f733ec2021-06-01 12:11:57 -0600155 float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
156 gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
157 gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
158 }
159 };
160 return new Impl;
161}
162
163} // namespace
164
Robert Phillips294723d2021-06-17 09:23:58 -0400165void GrPathInnerTriangulateOp::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
173GrDrawOp::FixedFunctionFlags GrPathInnerTriangulateOp::fixedFunctionFlags() const {
174 auto flags = FixedFunctionFlags::kUsesStencil;
175 if (GrAAType::kNone != fAAType) {
176 flags |= FixedFunctionFlags::kUsesHWAA;
177 }
178 return flags;
179}
180
181GrProcessorSet::Analysis GrPathInnerTriangulateOp::finalize(const GrCaps& caps,
182 const GrAppliedClip* clip,
Chris Daltonebb37e72021-01-27 17:59:45 -0700183 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
Chris Dalton09bc8af2021-07-19 11:02:39 -0600188void GrPathInnerTriangulateOp::pushFanProgram(const GrTessellationShader::ProgramArgs& args,
189 const GrPipeline* pipeline,
190 const SkPMColor4f& color,
191 const GrUserStencilSettings* stencil) {
192 auto triangleGP = GrDefaultGeoProcFactory::Make(
193 args.fArena,
194 GrDefaultGeoProcFactory::Color(color),
195 GrDefaultGeoProcFactory::Coverage::kSolid_Type,
196 GrDefaultGeoProcFactory::LocalCoords::kUsePosition_Type,
197 fViewMatrix);
198 fFanPrograms.push_back(GrSimpleMeshDrawOpHelper::CreateProgramInfo(args.fArena,
199 pipeline,
200 args.fWriteView,
201 triangleGP,
202 GrPrimitiveType::kTriangles,
203 args.fXferBarrierFlags,
204 args.fColorLoadOp,
205 stencil));
Chris Daltonebb37e72021-01-27 17:59:45 -0700206}
207
Chris Dalton2f733ec2021-06-01 12:11:57 -0600208void GrPathInnerTriangulateOp::prePreparePrograms(const GrTessellationShader::ProgramArgs& args,
Chris Daltonebb37e72021-01-27 17:59:45 -0700209 GrAppliedClip&& appliedClip) {
210 SkASSERT(!fFanTriangulator);
211 SkASSERT(!fFanPolys);
212 SkASSERT(!fPipelineForFills);
213 SkASSERT(!fTessellator);
214 SkASSERT(!fStencilCurvesProgram);
215 SkASSERT(fFanPrograms.empty());
Chris Dalton031d76b2021-06-08 16:32:00 -0600216 SkASSERT(!fCoverHullsProgram);
Chris Daltonebb37e72021-01-27 17:59:45 -0700217
218 if (fPath.countVerbs() <= 0) {
219 return;
220 }
221
Chris Dalton031d76b2021-06-08 16:32:00 -0600222 // If using wireframe, we have to fall back on a standard Redbook "stencil then cover" algorithm
Chris Dalton57ab06c2021-04-22 12:57:28 -0600223 // instead of bypassing the stencil buffer to fill the fan directly.
Chris Dalton917f9192021-06-08 14:32:37 -0600224 bool forceRedbookStencilPass = (fPathFlags & (PathFlags::kStencilOnly | PathFlags::kWireframe));
225 bool doFill = !(fPathFlags & PathFlags::kStencilOnly);
Chris Daltonebb37e72021-01-27 17:59:45 -0700226
227 bool isLinear;
228 fFanTriangulator = args.fArena->make<GrInnerFanTriangulator>(fPath, args.fArena);
229 fFanPolys = fFanTriangulator->pathToPolys(&fFanBreadcrumbs, &isLinear);
230
231 // Create a pipeline for stencil passes if needed.
232 const GrPipeline* pipelineForStencils = nullptr;
233 if (forceRedbookStencilPass || !isLinear) { // Curves always get stencilled.
Chris Dalton2f733ec2021-06-01 12:11:57 -0600234 pipelineForStencils = GrPathTessellationShader::MakeStencilOnlyPipeline(
Chris Dalton917f9192021-06-08 14:32:37 -0600235 args, fAAType, fPathFlags, appliedClip.hardClip());
Chris Daltonebb37e72021-01-27 17:59:45 -0700236 }
237
238 // Create a pipeline for fill passes if needed.
239 if (doFill) {
Chris Dalton2f733ec2021-06-01 12:11:57 -0600240 fPipelineForFills = GrTessellationShader::MakePipeline(args, fAAType,
241 std::move(appliedClip),
242 std::move(fProcessors));
Chris Daltonebb37e72021-01-27 17:59:45 -0700243 }
244
245 // Pass 1: Tessellate the outer curves into the stencil buffer.
246 if (!isLinear) {
Chris Dalton26666bd2021-06-08 16:25:46 -0600247 fTessellator = GrPathCurveTessellator::Make(args.fArena, fViewMatrix,
248 SK_PMColor4fTRANSPARENT,
Chris Daltond2b8ba32021-06-09 00:12:59 -0600249 GrPathCurveTessellator::DrawInnerFan::kNo,
Chris Dalton198ac152021-06-09 13:49:43 -0600250 fPath.countVerbs(), *pipelineForStencils,
251 *args.fCaps);
Chris Dalton2f733ec2021-06-01 12:11:57 -0600252 const GrUserStencilSettings* stencilPathSettings =
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600253 GrPathTessellationShader::StencilPathSettings(GrFillRuleForSkPath(fPath));
Chris Dalton2f733ec2021-06-01 12:11:57 -0600254 fStencilCurvesProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(),
255 pipelineForStencils,
256 stencilPathSettings);
Chris Daltonebb37e72021-01-27 17:59:45 -0700257 }
258
259 // Pass 2: Fill the path's inner fan with a stencil test against the curves.
260 if (fFanPolys) {
261 if (forceRedbookStencilPass) {
Chris Dalton031d76b2021-06-08 16:32:00 -0600262 // Use a standard Redbook "stencil then cover" algorithm instead of bypassing the
263 // stencil buffer to fill the fan directly.
Chris Dalton2f733ec2021-06-01 12:11:57 -0600264 const GrUserStencilSettings* stencilPathSettings =
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600265 GrPathTessellationShader::StencilPathSettings(GrFillRuleForSkPath(fPath));
Chris Dalton09bc8af2021-07-19 11:02:39 -0600266 this->pushFanProgram(args, pipelineForStencils, SK_PMColor4fTRANSPARENT,
267 stencilPathSettings);
Chris Daltonebb37e72021-01-27 17:59:45 -0700268 if (doFill) {
Chris Dalton09bc8af2021-07-19 11:02:39 -0600269 this->pushFanProgram(args, fPipelineForFills, fColor,
270 GrPathTessellationShader::TestAndResetStencilSettings());
Chris Daltonebb37e72021-01-27 17:59:45 -0700271 }
272 } else if (isLinear) {
273 // There are no outer curves! Ignore stencil and fill the path directly.
274 SkASSERT(!pipelineForStencils);
Chris Dalton09bc8af2021-07-19 11:02:39 -0600275 this->pushFanProgram(args, fPipelineForFills, fColor, &GrUserStencilSettings::kUnused);
Chris Daltonebb37e72021-01-27 17:59:45 -0700276 } else if (!fPipelineForFills->hasStencilClip()) {
277 // These are a twist on the standard Redbook stencil settings that allow us to fill the
278 // inner polygon directly to the final render target. By the time these programs
279 // execute, the outer curves will already be stencilled in. So if the stencil value is
280 // zero, then it means the sample in question is not affected by any curves and we can
281 // fill it in directly. If the stencil value is nonzero, then we don't fill and instead
282 // continue the standard Redbook counting process.
283 constexpr static GrUserStencilSettings kFillOrIncrDecrStencil(
284 GrUserStencilSettings::StaticInitSeparate<
285 0x0000, 0x0000,
286 GrUserStencilTest::kEqual, GrUserStencilTest::kEqual,
287 0xffff, 0xffff,
288 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
289 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
290 0xffff, 0xffff>());
291
292 constexpr static GrUserStencilSettings kFillOrInvertStencil(
293 GrUserStencilSettings::StaticInit<
294 0x0000,
295 GrUserStencilTest::kEqual,
296 0xffff,
297 GrUserStencilOp::kKeep,
298 // "Zero" instead of "Invert" because the fan only touches any given pixel once.
299 GrUserStencilOp::kZero,
300 0xffff>());
301
302 auto* stencil = (fPath.getFillType() == SkPathFillType::kWinding)
303 ? &kFillOrIncrDecrStencil
304 : &kFillOrInvertStencil;
Chris Dalton09bc8af2021-07-19 11:02:39 -0600305 this->pushFanProgram(args, fPipelineForFills, fColor, stencil);
Chris Daltonebb37e72021-01-27 17:59:45 -0700306 } else {
307 // This is the same idea as above, but we use two passes instead of one because there is
308 // a stencil clip. The stencil test isn't expressive enough to do the above tests and
309 // also check the clip bit in a single pass.
310 constexpr static GrUserStencilSettings kFillIfZeroAndInClip(
311 GrUserStencilSettings::StaticInit<
312 0x0000,
313 GrUserStencilTest::kEqualIfInClip,
314 0xffff,
315 GrUserStencilOp::kKeep,
316 GrUserStencilOp::kKeep,
317 0xffff>());
318
319 constexpr static GrUserStencilSettings kIncrDecrStencilIfNonzero(
320 GrUserStencilSettings::StaticInitSeparate<
321 0x0000, 0x0000,
322 // No need to check the clip because the previous stencil pass will have only
323 // written to samples already inside the clip.
324 GrUserStencilTest::kNotEqual, GrUserStencilTest::kNotEqual,
325 0xffff, 0xffff,
326 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
327 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
328 0xffff, 0xffff>());
329
330 constexpr static GrUserStencilSettings kInvertStencilIfNonZero(
331 GrUserStencilSettings::StaticInit<
332 0x0000,
333 // No need to check the clip because the previous stencil pass will have only
334 // written to samples already inside the clip.
335 GrUserStencilTest::kNotEqual,
336 0xffff,
337 // "Zero" instead of "Invert" because the fan only touches any given pixel once.
338 GrUserStencilOp::kZero,
339 GrUserStencilOp::kKeep,
340 0xffff>());
341
342 // Pass 2a: Directly fill fan samples whose stencil values (from curves) are zero.
Chris Dalton09bc8af2021-07-19 11:02:39 -0600343 this->pushFanProgram(args, fPipelineForFills, fColor, &kFillIfZeroAndInClip);
Chris Daltonebb37e72021-01-27 17:59:45 -0700344
345 // Pass 2b: Redbook counting on fan samples whose stencil values (from curves) != 0.
346 auto* stencil = (fPath.getFillType() == SkPathFillType::kWinding)
347 ? &kIncrDecrStencilIfNonzero
348 : &kInvertStencilIfNonZero;
Chris Dalton09bc8af2021-07-19 11:02:39 -0600349 this->pushFanProgram(args, pipelineForStencils, SK_PMColor4fTRANSPARENT, stencil);
Chris Daltonebb37e72021-01-27 17:59:45 -0700350 }
351 }
352
353 // Pass 3: Draw convex hulls around each curve.
354 if (doFill && !isLinear) {
355 // By the time this program executes, every pixel will be filled in except the ones touched
356 // by curves. We issue a final cover pass over the curves by drawing their convex hulls.
357 // This will fill in any remaining samples and reset the stencil values back to zero.
358 SkASSERT(fTessellator);
Chris Daltona05ccc32021-06-29 19:42:13 -0600359 auto* hullShader = args.fArena->make<HullShader>(fViewMatrix, fColor,
360 *args.fCaps->shaderCaps());
Chris Dalton031d76b2021-06-08 16:32:00 -0600361 fCoverHullsProgram = GrTessellationShader::MakeProgram(
Chris Daltonebb37e72021-01-27 17:59:45 -0700362 args, hullShader, fPipelineForFills,
Chris Dalton2f733ec2021-06-01 12:11:57 -0600363 GrPathTessellationShader::TestAndResetStencilSettings());
Chris Daltonebb37e72021-01-27 17:59:45 -0700364 }
365}
366
367void GrPathInnerTriangulateOp::onPrePrepare(GrRecordingContext* context,
368 const GrSurfaceProxyView& writeView,
369 GrAppliedClip* clip,
John Stiles52cb1d02021-06-02 11:58:05 -0400370 const GrDstProxyView& dstProxyView,
Chris Daltonebb37e72021-01-27 17:59:45 -0700371 GrXferBarrierFlags renderPassXferBarriers,
372 GrLoadOp colorLoadOp) {
373 this->prePreparePrograms({context->priv().recordTimeAllocator(), writeView, &dstProxyView,
374 renderPassXferBarriers, colorLoadOp, context->priv().caps()},
375 (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
Chris Daltonebb37e72021-01-27 17:59:45 -0700389void GrPathInnerTriangulateOp::onPrepare(GrOpFlushState* flushState) {
390 if (!fFanTriangulator) {
391 this->prePreparePrograms({flushState->allocator(), flushState->writeView(),
392 &flushState->dstProxyView(), flushState->renderPassBarriers(),
393 flushState->colorLoadOp(), &flushState->caps()},
394 flushState->detachAppliedClip());
395 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 Dalton569c01b2021-05-25 10:11:46 -0600407 fTessellator->prepare(flushState, this->bounds(), fPath, &fFanBreadcrumbs);
Chris Daltonebb37e72021-01-27 17:59:45 -0700408 }
Chris Daltona05ccc32021-06-29 19:42:13 -0600409
410 if (!flushState->caps().shaderCaps()->vertexIDSupport()) {
411 constexpr static float kStripOrderIDs[4] = {0, 1, 3, 2};
412
413 GR_DEFINE_STATIC_UNIQUE_KEY(gHullVertexBufferKey);
414
415 fHullVertexBufferIfNoIDSupport = flushState->resourceProvider()->findOrMakeStaticBuffer(
416 GrGpuBufferType::kVertex, sizeof(kStripOrderIDs), kStripOrderIDs,
417 gHullVertexBufferKey);
418 }
Chris Daltonebb37e72021-01-27 17:59:45 -0700419}
420
421void GrPathInnerTriangulateOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
422 if (fStencilCurvesProgram) {
423 SkASSERT(fTessellator);
424 flushState->bindPipelineAndScissorClip(*fStencilCurvesProgram, this->bounds());
425 fTessellator->draw(flushState);
Chris Daltond9bdc322021-06-01 19:22:05 -0600426 if (flushState->caps().requiresManualFBBarrierAfterTessellatedStencilDraw()) {
427 flushState->gpu()->insertManualFramebufferBarrier(); // http://skbug.com/9739
428 }
Chris Daltonebb37e72021-01-27 17:59:45 -0700429 }
430
431 for (const GrProgramInfo* fanProgram : fFanPrograms) {
432 SkASSERT(fFanBuffer);
433 flushState->bindPipelineAndScissorClip(*fanProgram, this->bounds());
Robert Phillips787fd9d2021-03-22 14:48:09 -0400434 flushState->bindTextures(fanProgram->geomProc(), nullptr, fanProgram->pipeline());
Chris Daltonebb37e72021-01-27 17:59:45 -0700435 flushState->bindBuffers(nullptr, nullptr, fFanBuffer);
436 flushState->draw(fFanVertexCount, fBaseFanVertex);
437 }
438
Chris Dalton031d76b2021-06-08 16:32:00 -0600439 if (fCoverHullsProgram) {
Chris Daltonebb37e72021-01-27 17:59:45 -0700440 SkASSERT(fTessellator);
Chris Dalton031d76b2021-06-08 16:32:00 -0600441 flushState->bindPipelineAndScissorClip(*fCoverHullsProgram, this->bounds());
442 flushState->bindTextures(fCoverHullsProgram->geomProc(), nullptr, *fPipelineForFills);
Chris Daltona05ccc32021-06-29 19:42:13 -0600443 fTessellator->drawHullInstances(flushState, fHullVertexBufferIfNoIDSupport);
Chris Daltonebb37e72021-01-27 17:59:45 -0700444 }
445}