blob: be9875a7d0248d1d47c243354c1c724fef7b929d [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
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/GrInnerFanTriangulator.h"
13#include "src/gpu/GrOpFlushState.h"
14#include "src/gpu/GrRecordingContextPriv.h"
Robert Phillips1a82a4e2021-07-01 10:27:44 -040015#include "src/gpu/GrResourceProvider.h"
Chris Dalton2f733ec2021-06-01 12:11:57 -060016#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
Chris Daltond9bdc322021-06-01 19:22:05 -060017#include "src/gpu/tessellate/GrPathCurveTessellator.h"
Chris Daltonebb37e72021-01-27 17:59:45 -070018#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
Chris Dalton3b412782021-06-01 13:40:03 -060019#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
Chris Daltonebb37e72021-01-27 17:59:45 -070020
Chris Dalton917f9192021-06-08 14:32:37 -060021using PathFlags = GrTessellationPathRenderer::PathFlags;
Chris Daltonebb37e72021-01-27 17:59:45 -070022
Chris Dalton2f733ec2021-06-01 12:11:57 -060023namespace {
24
25// Fills an array of convex hulls surrounding 4-point cubic or conic instances. This shader is used
Chris Dalton031d76b2021-06-08 16:32:00 -060026// for the "cover" pass after the curves have been fully stencilled.
Chris Dalton2f733ec2021-06-01 12:11:57 -060027class HullShader : public GrPathTessellationShader {
28public:
Chris Daltona05ccc32021-06-29 19:42:13 -060029 HullShader(const SkMatrix& viewMatrix, SkPMColor4f color, const GrShaderCaps& shaderCaps)
Chris Dalton2f733ec2021-06-01 12:11:57 -060030 : GrPathTessellationShader(kTessellate_HullShader_ClassID,
31 GrPrimitiveType::kTriangleStrip, 0, viewMatrix, color) {
Chris Dalton50516f32021-07-18 22:26:27 -060032 fInstanceAttribs.emplace_back("p01", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
33 fInstanceAttribs.emplace_back("p23", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
34 if (!shaderCaps.infinitySupport()) {
35 // A conic curve is written out with p3=[w,Infinity], but GPUs that don't support
36 // infinity can't detect this. On these platforms we also write out an extra float with
37 // each patch that explicitly tells the shader what type of curve it is.
38 fInstanceAttribs.emplace_back("curveType", kFloat_GrVertexAttribType, kFloat_GrSLType);
39 }
40 this->setInstanceAttributes(fInstanceAttribs.data(), fInstanceAttribs.count());
41 SkASSERT(fInstanceAttribs.count() <= kMaxInstanceAttribCount);
42
Chris Daltona05ccc32021-06-29 19:42:13 -060043 if (!shaderCaps.vertexIDSupport()) {
44 constexpr static Attribute kVertexIdxAttrib("vertexidx", kFloat_GrVertexAttribType,
45 kFloat_GrSLType);
46 this->setVertexAttributes(&kVertexIdxAttrib, 1);
47 }
Chris Dalton2f733ec2021-06-01 12:11:57 -060048 }
49
50private:
Chris Daltonb63711a2021-06-01 14:52:02 -060051 const char* name() const final { return "tessellate_HullShader"; }
Chris Dalton2f733ec2021-06-01 12:11:57 -060052 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
53 GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const final;
Chris Dalton50516f32021-07-18 22:26:27 -060054
55 constexpr static int kMaxInstanceAttribCount = 3;
56 SkSTArray<kMaxInstanceAttribCount, Attribute> fInstanceAttribs;
Chris Dalton2f733ec2021-06-01 12:11:57 -060057};
58
59GrGLSLGeometryProcessor* HullShader::createGLSLInstance(const GrShaderCaps&) const {
60 class Impl : public GrPathTessellationShader::Impl {
Chris Dalton69043032021-07-01 11:17:53 -060061 void emitVertexCode(const GrShaderCaps& shaderCaps, const GrPathTessellationShader&,
62 GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
Chris Dalton50516f32021-07-18 22:26:27 -060063 if (shaderCaps.infinitySupport()) {
64 v->insertFunction(R"(
65 bool is_conic_curve() { return isinf(p23.w); }
66 bool is_non_triangular_conic_curve() {
67 // We consider a conic non-triangular as long as its weight isn't infinity.
68 // NOTE: "isinf == false" works on Mac Radeon GLSL; "!isinf" can get the wrong
69 // answer.
70 return isinf(p23.z) == false;
71 })");
72 } else {
73 v->insertFunction(SkStringPrintf(R"(
74 bool is_conic_curve() { return curveType != %g; })", kCubicCurveType).c_str());
75 v->insertFunction(SkStringPrintf(R"(
76 bool is_non_triangular_conic_curve() {
77 return curveType == %g;
78 })", kConicCurveType).c_str());
79 }
Chris Dalton2f733ec2021-06-01 12:11:57 -060080 v->codeAppend(R"(
Chris Dalton202441f2021-06-30 22:48:30 -060081 float2 p0=p01.xy, p1=p01.zw, p2=p23.xy, p3=p23.zw;
Chris Dalton50516f32021-07-18 22:26:27 -060082 if (is_conic_curve()) {
83 // Conics are 3 points, with the weight in p3.
Chris Dalton202441f2021-06-30 22:48:30 -060084 float w = p3.x;
Chris Dalton50516f32021-07-18 22:26:27 -060085 p3 = p2; // Duplicate the endpoint for shared code that also runs on cubics.
86 if (is_non_triangular_conic_curve()) {
Chris Dalton2f733ec2021-06-01 12:11:57 -060087 // Convert the points to a trapeziodal hull that circumcscribes the conic.
Chris Dalton202441f2021-06-30 22:48:30 -060088 float2 p1w = p1 * w;
Chris Dalton2f733ec2021-06-01 12:11:57 -060089 float T = .51; // Bias outward a bit to ensure we cover the outermost samples.
Chris Dalton202441f2021-06-30 22:48:30 -060090 float2 c1 = mix(p0, p1w, T);
91 float2 c2 = mix(p2, p1w, T);
Chris Dalton2f733ec2021-06-01 12:11:57 -060092 float iw = 1 / mix(1, w, T);
Chris Dalton202441f2021-06-30 22:48:30 -060093 p2 = c2 * iw;
94 p1 = c1 * iw;
Chris Dalton2f733ec2021-06-01 12:11:57 -060095 }
96 }
97
98 // Translate the points to v0..3 where v0=0.
Chris Dalton202441f2021-06-30 22:48:30 -060099 float2 v1 = p1 - p0;
100 float2 v2 = p2 - p0;
101 float2 v3 = p3 - p0;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600102
103 // Reorder the points so v2 bisects v1 and v3.
Chris Dalton202441f2021-06-30 22:48:30 -0600104 if (sign(cross(v2, v1)) == sign(cross(v2, v3))) {
105 float2 tmp = p2;
106 if (sign(cross(v1, v2)) != sign(cross(v1, v3))) {
107 p2 = p1; // swap(p2, p1)
108 p1 = tmp;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600109 } else {
Chris Dalton202441f2021-06-30 22:48:30 -0600110 p2 = p3; // swap(p2, p3)
111 p3 = tmp;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600112 }
Chris Daltona05ccc32021-06-29 19:42:13 -0600113 })");
114
Chris Dalton69043032021-07-01 11:17:53 -0600115 if (shaderCaps.vertexIDSupport()) {
Chris Daltona05ccc32021-06-29 19:42:13 -0600116 // If we don't have sk_VertexID support then "vertexidx" already came in as a
117 // vertex attrib.
118 v->codeAppend(R"(
119 // sk_VertexID comes in fan order. Convert to strip order.
120 int vertexidx = sk_VertexID;
121 vertexidx ^= vertexidx >> 1;)");
Chris Dalton2f733ec2021-06-01 12:11:57 -0600122 }
123
Chris Daltona05ccc32021-06-29 19:42:13 -0600124 v->codeAppend(R"(
Chris Dalton2f733ec2021-06-01 12:11:57 -0600125 // Find the "turn direction" of each corner and net turn direction.
126 float vertexdir = 0;
127 float netdir = 0;
Chris Daltona05ccc32021-06-29 19:42:13 -0600128 float2 prev, next;
129 float dir;
130 float2 localcoord;
131 float2 nextcoord;)");
132
Chris Dalton2f733ec2021-06-01 12:11:57 -0600133 for (int i = 0; i < 4; ++i) {
Chris Daltona05ccc32021-06-29 19:42:13 -0600134 v->codeAppendf(R"(
Chris Dalton202441f2021-06-30 22:48:30 -0600135 prev = p%i - p%i;)", i, (i + 3) % 4);
Chris Daltona05ccc32021-06-29 19:42:13 -0600136 v->codeAppendf(R"(
Chris Dalton202441f2021-06-30 22:48:30 -0600137 next = p%i - p%i;)", (i + 1) % 4, i);
Chris Daltona05ccc32021-06-29 19:42:13 -0600138 v->codeAppendf(R"(
Chris Dalton202441f2021-06-30 22:48:30 -0600139 dir = sign(cross(prev, next));
Chris Daltona05ccc32021-06-29 19:42:13 -0600140 if (vertexidx == %i) {
Chris Dalton2f733ec2021-06-01 12:11:57 -0600141 vertexdir = dir;
Chris Dalton202441f2021-06-30 22:48:30 -0600142 localcoord = p%i;
143 nextcoord = p%i;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600144 }
Chris Daltona05ccc32021-06-29 19:42:13 -0600145 netdir += dir;)", i, i, (i + 1) % 4);
Chris Dalton2f733ec2021-06-01 12:11:57 -0600146 }
147
Chris Daltona05ccc32021-06-29 19:42:13 -0600148 v->codeAppend(R"(
Chris Dalton2f733ec2021-06-01 12:11:57 -0600149 // Remove the non-convex vertex, if any.
150 if (vertexdir != sign(netdir)) {
Chris Daltona05ccc32021-06-29 19:42:13 -0600151 localcoord = nextcoord;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600152 }
153
Chris Dalton2f733ec2021-06-01 12:11:57 -0600154 float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
155 gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
156 gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
157 }
158 };
159 return new Impl;
160}
161
162} // namespace
163
Robert Phillips294723d2021-06-17 09:23:58 -0400164void GrPathInnerTriangulateOp::visitProxies(const GrVisitProxyFunc& func) const {
Chris Daltonebb37e72021-01-27 17:59:45 -0700165 if (fPipelineForFills) {
Robert Phillips294723d2021-06-17 09:23:58 -0400166 fPipelineForFills->visitProxies(func);
Chris Daltonebb37e72021-01-27 17:59:45 -0700167 } else {
Robert Phillips294723d2021-06-17 09:23:58 -0400168 fProcessors.visitProxies(func);
Chris Daltonebb37e72021-01-27 17:59:45 -0700169 }
170}
171
172GrDrawOp::FixedFunctionFlags GrPathInnerTriangulateOp::fixedFunctionFlags() const {
173 auto flags = FixedFunctionFlags::kUsesStencil;
174 if (GrAAType::kNone != fAAType) {
175 flags |= FixedFunctionFlags::kUsesHWAA;
176 }
177 return flags;
178}
179
180GrProcessorSet::Analysis GrPathInnerTriangulateOp::finalize(const GrCaps& caps,
181 const GrAppliedClip* clip,
Chris Daltonebb37e72021-01-27 17:59:45 -0700182 GrClampType clampType) {
Chris Dalton57ab06c2021-04-22 12:57:28 -0600183 return fProcessors.finalize(fColor, GrProcessorAnalysisCoverage::kNone, clip, nullptr, caps,
184 clampType, &fColor);
Chris Daltonebb37e72021-01-27 17:59:45 -0700185}
186
Chris Daltona8c4de92021-07-26 21:46:28 +0000187void GrPathInnerTriangulateOp::pushFanStencilProgram(const GrTessellationShader::ProgramArgs& args,
188 const GrPipeline* pipelineForStencils,
189 const GrUserStencilSettings* stencil) {
190 SkASSERT(pipelineForStencils);
191 auto shader = GrPathTessellationShader::MakeSimpleTriangleShader(args.fArena, fViewMatrix,
192 SK_PMColor4fTRANSPARENT);
193 fFanPrograms.push_back(GrTessellationShader::MakeProgram(args, shader, pipelineForStencils,
194 stencil)); }
195
196void GrPathInnerTriangulateOp::pushFanFillProgram(const GrTessellationShader::ProgramArgs& args,
197 const GrUserStencilSettings* stencil) {
198 SkASSERT(fPipelineForFills);
199 auto shader = GrPathTessellationShader::MakeSimpleTriangleShader(args.fArena, fViewMatrix,
200 fColor);
201 fFanPrograms.push_back(GrTessellationShader::MakeProgram(args, shader, fPipelineForFills,
202 stencil));
Chris Daltonebb37e72021-01-27 17:59:45 -0700203}
204
Chris Dalton2f733ec2021-06-01 12:11:57 -0600205void GrPathInnerTriangulateOp::prePreparePrograms(const GrTessellationShader::ProgramArgs& args,
Chris Daltonebb37e72021-01-27 17:59:45 -0700206 GrAppliedClip&& appliedClip) {
207 SkASSERT(!fFanTriangulator);
208 SkASSERT(!fFanPolys);
209 SkASSERT(!fPipelineForFills);
210 SkASSERT(!fTessellator);
211 SkASSERT(!fStencilCurvesProgram);
212 SkASSERT(fFanPrograms.empty());
Chris Dalton031d76b2021-06-08 16:32:00 -0600213 SkASSERT(!fCoverHullsProgram);
Chris Daltonebb37e72021-01-27 17:59:45 -0700214
215 if (fPath.countVerbs() <= 0) {
216 return;
217 }
218
Chris Dalton031d76b2021-06-08 16:32:00 -0600219 // If using wireframe, we have to fall back on a standard Redbook "stencil then cover" algorithm
Chris Dalton57ab06c2021-04-22 12:57:28 -0600220 // instead of bypassing the stencil buffer to fill the fan directly.
Chris Dalton917f9192021-06-08 14:32:37 -0600221 bool forceRedbookStencilPass = (fPathFlags & (PathFlags::kStencilOnly | PathFlags::kWireframe));
222 bool doFill = !(fPathFlags & PathFlags::kStencilOnly);
Chris Daltonebb37e72021-01-27 17:59:45 -0700223
224 bool isLinear;
225 fFanTriangulator = args.fArena->make<GrInnerFanTriangulator>(fPath, args.fArena);
226 fFanPolys = fFanTriangulator->pathToPolys(&fFanBreadcrumbs, &isLinear);
227
228 // Create a pipeline for stencil passes if needed.
229 const GrPipeline* pipelineForStencils = nullptr;
230 if (forceRedbookStencilPass || !isLinear) { // Curves always get stencilled.
Chris Dalton2f733ec2021-06-01 12:11:57 -0600231 pipelineForStencils = GrPathTessellationShader::MakeStencilOnlyPipeline(
Chris Dalton917f9192021-06-08 14:32:37 -0600232 args, fAAType, fPathFlags, appliedClip.hardClip());
Chris Daltonebb37e72021-01-27 17:59:45 -0700233 }
234
235 // Create a pipeline for fill passes if needed.
236 if (doFill) {
Chris Dalton2f733ec2021-06-01 12:11:57 -0600237 fPipelineForFills = GrTessellationShader::MakePipeline(args, fAAType,
238 std::move(appliedClip),
239 std::move(fProcessors));
Chris Daltonebb37e72021-01-27 17:59:45 -0700240 }
241
242 // Pass 1: Tessellate the outer curves into the stencil buffer.
243 if (!isLinear) {
Chris Dalton26666bd2021-06-08 16:25:46 -0600244 fTessellator = GrPathCurveTessellator::Make(args.fArena, fViewMatrix,
245 SK_PMColor4fTRANSPARENT,
Chris Daltond2b8ba32021-06-09 00:12:59 -0600246 GrPathCurveTessellator::DrawInnerFan::kNo,
Chris Dalton198ac152021-06-09 13:49:43 -0600247 fPath.countVerbs(), *pipelineForStencils,
248 *args.fCaps);
Chris Dalton2f733ec2021-06-01 12:11:57 -0600249 const GrUserStencilSettings* stencilPathSettings =
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600250 GrPathTessellationShader::StencilPathSettings(GrFillRuleForSkPath(fPath));
Chris Dalton2f733ec2021-06-01 12:11:57 -0600251 fStencilCurvesProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(),
252 pipelineForStencils,
253 stencilPathSettings);
Chris Daltonebb37e72021-01-27 17:59:45 -0700254 }
255
256 // Pass 2: Fill the path's inner fan with a stencil test against the curves.
257 if (fFanPolys) {
258 if (forceRedbookStencilPass) {
Chris Dalton031d76b2021-06-08 16:32:00 -0600259 // Use a standard Redbook "stencil then cover" algorithm instead of bypassing the
260 // stencil buffer to fill the fan directly.
Chris Dalton2f733ec2021-06-01 12:11:57 -0600261 const GrUserStencilSettings* stencilPathSettings =
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600262 GrPathTessellationShader::StencilPathSettings(GrFillRuleForSkPath(fPath));
Chris Daltona8c4de92021-07-26 21:46:28 +0000263 this->pushFanStencilProgram(args, pipelineForStencils, stencilPathSettings);
Chris Daltonebb37e72021-01-27 17:59:45 -0700264 if (doFill) {
Chris Daltona8c4de92021-07-26 21:46:28 +0000265 this->pushFanFillProgram(args,
266 GrPathTessellationShader::TestAndResetStencilSettings());
Chris Daltonebb37e72021-01-27 17:59:45 -0700267 }
268 } else if (isLinear) {
269 // There are no outer curves! Ignore stencil and fill the path directly.
270 SkASSERT(!pipelineForStencils);
Chris Daltona8c4de92021-07-26 21:46:28 +0000271 this->pushFanFillProgram(args, &GrUserStencilSettings::kUnused);
Chris Daltonebb37e72021-01-27 17:59:45 -0700272 } else if (!fPipelineForFills->hasStencilClip()) {
273 // These are a twist on the standard Redbook stencil settings that allow us to fill the
274 // inner polygon directly to the final render target. By the time these programs
275 // execute, the outer curves will already be stencilled in. So if the stencil value is
276 // zero, then it means the sample in question is not affected by any curves and we can
277 // fill it in directly. If the stencil value is nonzero, then we don't fill and instead
278 // continue the standard Redbook counting process.
279 constexpr static GrUserStencilSettings kFillOrIncrDecrStencil(
280 GrUserStencilSettings::StaticInitSeparate<
281 0x0000, 0x0000,
282 GrUserStencilTest::kEqual, GrUserStencilTest::kEqual,
283 0xffff, 0xffff,
284 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
285 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
286 0xffff, 0xffff>());
287
288 constexpr static GrUserStencilSettings kFillOrInvertStencil(
289 GrUserStencilSettings::StaticInit<
290 0x0000,
291 GrUserStencilTest::kEqual,
292 0xffff,
293 GrUserStencilOp::kKeep,
294 // "Zero" instead of "Invert" because the fan only touches any given pixel once.
295 GrUserStencilOp::kZero,
296 0xffff>());
297
298 auto* stencil = (fPath.getFillType() == SkPathFillType::kWinding)
299 ? &kFillOrIncrDecrStencil
300 : &kFillOrInvertStencil;
Chris Daltona8c4de92021-07-26 21:46:28 +0000301 this->pushFanFillProgram(args, stencil);
Chris Daltonebb37e72021-01-27 17:59:45 -0700302 } else {
303 // This is the same idea as above, but we use two passes instead of one because there is
304 // a stencil clip. The stencil test isn't expressive enough to do the above tests and
305 // also check the clip bit in a single pass.
306 constexpr static GrUserStencilSettings kFillIfZeroAndInClip(
307 GrUserStencilSettings::StaticInit<
308 0x0000,
309 GrUserStencilTest::kEqualIfInClip,
310 0xffff,
311 GrUserStencilOp::kKeep,
312 GrUserStencilOp::kKeep,
313 0xffff>());
314
315 constexpr static GrUserStencilSettings kIncrDecrStencilIfNonzero(
316 GrUserStencilSettings::StaticInitSeparate<
317 0x0000, 0x0000,
318 // No need to check the clip because the previous stencil pass will have only
319 // written to samples already inside the clip.
320 GrUserStencilTest::kNotEqual, GrUserStencilTest::kNotEqual,
321 0xffff, 0xffff,
322 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
323 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
324 0xffff, 0xffff>());
325
326 constexpr static GrUserStencilSettings kInvertStencilIfNonZero(
327 GrUserStencilSettings::StaticInit<
328 0x0000,
329 // No need to check the clip because the previous stencil pass will have only
330 // written to samples already inside the clip.
331 GrUserStencilTest::kNotEqual,
332 0xffff,
333 // "Zero" instead of "Invert" because the fan only touches any given pixel once.
334 GrUserStencilOp::kZero,
335 GrUserStencilOp::kKeep,
336 0xffff>());
337
338 // Pass 2a: Directly fill fan samples whose stencil values (from curves) are zero.
Chris Daltona8c4de92021-07-26 21:46:28 +0000339 this->pushFanFillProgram(args, &kFillIfZeroAndInClip);
Chris Daltonebb37e72021-01-27 17:59:45 -0700340
341 // Pass 2b: Redbook counting on fan samples whose stencil values (from curves) != 0.
342 auto* stencil = (fPath.getFillType() == SkPathFillType::kWinding)
343 ? &kIncrDecrStencilIfNonzero
344 : &kInvertStencilIfNonZero;
Chris Daltona8c4de92021-07-26 21:46:28 +0000345 this->pushFanStencilProgram(args, pipelineForStencils, stencil);
Chris Daltonebb37e72021-01-27 17:59:45 -0700346 }
347 }
348
349 // Pass 3: Draw convex hulls around each curve.
350 if (doFill && !isLinear) {
351 // By the time this program executes, every pixel will be filled in except the ones touched
352 // by curves. We issue a final cover pass over the curves by drawing their convex hulls.
353 // This will fill in any remaining samples and reset the stencil values back to zero.
354 SkASSERT(fTessellator);
Chris Daltona05ccc32021-06-29 19:42:13 -0600355 auto* hullShader = args.fArena->make<HullShader>(fViewMatrix, fColor,
356 *args.fCaps->shaderCaps());
Chris Dalton031d76b2021-06-08 16:32:00 -0600357 fCoverHullsProgram = GrTessellationShader::MakeProgram(
Chris Daltonebb37e72021-01-27 17:59:45 -0700358 args, hullShader, fPipelineForFills,
Chris Dalton2f733ec2021-06-01 12:11:57 -0600359 GrPathTessellationShader::TestAndResetStencilSettings());
Chris Daltonebb37e72021-01-27 17:59:45 -0700360 }
361}
362
363void GrPathInnerTriangulateOp::onPrePrepare(GrRecordingContext* context,
364 const GrSurfaceProxyView& writeView,
365 GrAppliedClip* clip,
John Stiles52cb1d02021-06-02 11:58:05 -0400366 const GrDstProxyView& dstProxyView,
Chris Daltonebb37e72021-01-27 17:59:45 -0700367 GrXferBarrierFlags renderPassXferBarriers,
368 GrLoadOp colorLoadOp) {
369 this->prePreparePrograms({context->priv().recordTimeAllocator(), writeView, &dstProxyView,
370 renderPassXferBarriers, colorLoadOp, context->priv().caps()},
371 (clip) ? std::move(*clip) : GrAppliedClip::Disabled());
372 if (fStencilCurvesProgram) {
373 context->priv().recordProgramInfo(fStencilCurvesProgram);
374 }
375 for (const GrProgramInfo* fanProgram : fFanPrograms) {
376 context->priv().recordProgramInfo(fanProgram);
377 }
Chris Dalton031d76b2021-06-08 16:32:00 -0600378 if (fCoverHullsProgram) {
379 context->priv().recordProgramInfo(fCoverHullsProgram);
Chris Daltonebb37e72021-01-27 17:59:45 -0700380 }
381}
382
Chris Daltona05ccc32021-06-29 19:42:13 -0600383GR_DECLARE_STATIC_UNIQUE_KEY(gHullVertexBufferKey);
384
Chris Daltonebb37e72021-01-27 17:59:45 -0700385void GrPathInnerTriangulateOp::onPrepare(GrOpFlushState* flushState) {
386 if (!fFanTriangulator) {
387 this->prePreparePrograms({flushState->allocator(), flushState->writeView(),
388 &flushState->dstProxyView(), flushState->renderPassBarriers(),
389 flushState->colorLoadOp(), &flushState->caps()},
390 flushState->detachAppliedClip());
391 if (!fFanTriangulator) {
392 return;
393 }
394 }
395
396 if (fFanPolys) {
397 GrEagerDynamicVertexAllocator alloc(flushState, &fFanBuffer, &fBaseFanVertex);
398 fFanVertexCount = fFanTriangulator->polysToTriangles(fFanPolys, &alloc, &fFanBreadcrumbs);
399 }
400
401 if (fTessellator) {
402 // Must be called after polysToTriangles() in order for fFanBreadcrumbs to be complete.
Chris Dalton569c01b2021-05-25 10:11:46 -0600403 fTessellator->prepare(flushState, this->bounds(), fPath, &fFanBreadcrumbs);
Chris Daltonebb37e72021-01-27 17:59:45 -0700404 }
Chris Daltona05ccc32021-06-29 19:42:13 -0600405
406 if (!flushState->caps().shaderCaps()->vertexIDSupport()) {
407 constexpr static float kStripOrderIDs[4] = {0, 1, 3, 2};
408
409 GR_DEFINE_STATIC_UNIQUE_KEY(gHullVertexBufferKey);
410
411 fHullVertexBufferIfNoIDSupport = flushState->resourceProvider()->findOrMakeStaticBuffer(
412 GrGpuBufferType::kVertex, sizeof(kStripOrderIDs), kStripOrderIDs,
413 gHullVertexBufferKey);
414 }
Chris Daltonebb37e72021-01-27 17:59:45 -0700415}
416
417void GrPathInnerTriangulateOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
418 if (fStencilCurvesProgram) {
419 SkASSERT(fTessellator);
420 flushState->bindPipelineAndScissorClip(*fStencilCurvesProgram, this->bounds());
421 fTessellator->draw(flushState);
Chris Daltond9bdc322021-06-01 19:22:05 -0600422 if (flushState->caps().requiresManualFBBarrierAfterTessellatedStencilDraw()) {
423 flushState->gpu()->insertManualFramebufferBarrier(); // http://skbug.com/9739
424 }
Chris Daltonebb37e72021-01-27 17:59:45 -0700425 }
426
427 for (const GrProgramInfo* fanProgram : fFanPrograms) {
428 SkASSERT(fFanBuffer);
429 flushState->bindPipelineAndScissorClip(*fanProgram, this->bounds());
Robert Phillips787fd9d2021-03-22 14:48:09 -0400430 flushState->bindTextures(fanProgram->geomProc(), nullptr, fanProgram->pipeline());
Chris Daltonebb37e72021-01-27 17:59:45 -0700431 flushState->bindBuffers(nullptr, nullptr, fFanBuffer);
432 flushState->draw(fFanVertexCount, fBaseFanVertex);
433 }
434
Chris Dalton031d76b2021-06-08 16:32:00 -0600435 if (fCoverHullsProgram) {
Chris Daltonebb37e72021-01-27 17:59:45 -0700436 SkASSERT(fTessellator);
Chris Dalton031d76b2021-06-08 16:32:00 -0600437 flushState->bindPipelineAndScissorClip(*fCoverHullsProgram, this->bounds());
438 flushState->bindTextures(fCoverHullsProgram->geomProc(), nullptr, *fPipelineForFills);
Chris Daltona05ccc32021-06-29 19:42:13 -0600439 fTessellator->drawHullInstances(flushState, fHullVertexBufferIfNoIDSupport);
Chris Daltonebb37e72021-01-27 17:59:45 -0700440 }
441}