blob: e2463e544b19f5d8648fa426d09f7efce92f0405 [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 Daltona05ccc32021-06-29 19:42:13 -060016#include "src/gpu/glsl/GrGLSLProgramBuilder.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) {
33 constexpr static Attribute kPtsAttribs[] = {
34 {"input_points_0_1", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
35 {"input_points_2_3", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
36 this->setInstanceAttributes(kPtsAttribs, SK_ARRAY_COUNT(kPtsAttribs));
Chris Daltona05ccc32021-06-29 19:42:13 -060037 if (!shaderCaps.vertexIDSupport()) {
38 constexpr static Attribute kVertexIdxAttrib("vertexidx", kFloat_GrVertexAttribType,
39 kFloat_GrSLType);
40 this->setVertexAttributes(&kVertexIdxAttrib, 1);
41 }
Chris Dalton2f733ec2021-06-01 12:11:57 -060042 }
43
44private:
Chris Daltonb63711a2021-06-01 14:52:02 -060045 const char* name() const final { return "tessellate_HullShader"; }
Chris Dalton2f733ec2021-06-01 12:11:57 -060046 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
47 GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const final;
48};
49
50GrGLSLGeometryProcessor* HullShader::createGLSLInstance(const GrShaderCaps&) const {
51 class Impl : public GrPathTessellationShader::Impl {
Chris Daltond2b8ba32021-06-09 00:12:59 -060052 void emitVertexCode(const GrPathTessellationShader&, GrGLSLVertexBuilder* v,
53 GrGPArgs* gpArgs) override {
Chris Dalton2f733ec2021-06-01 12:11:57 -060054 v->codeAppend(R"(
55 float4x2 P = float4x2(input_points_0_1, input_points_2_3);
56 if (isinf(P[3].y)) { // Is the curve a conic?
57 float w = P[3].x;
58 if (isinf(w)) {
59 // A conic with w=Inf is an exact triangle.
60 P = float4x2(P[0], P[1], P[2], P[2]);
61 } else {
62 // Convert the points to a trapeziodal hull that circumcscribes the conic.
63 float2 p1w = P[1] * w;
64 float T = .51; // Bias outward a bit to ensure we cover the outermost samples.
65 float2 c1 = mix(P[0], p1w, T);
66 float2 c2 = mix(P[2], p1w, T);
67 float iw = 1 / mix(1, w, T);
68 P = float4x2(P[0], c1 * iw, c2 * iw, P[2]);
69 }
70 }
71
72 // Translate the points to v0..3 where v0=0.
73 float2 v1 = P[1] - P[0], v2 = P[2] - P[0], v3 = P[3] - P[0];
74
75 // Reorder the points so v2 bisects v1 and v3.
76 if (sign(determinant(float2x2(v2,v1))) == sign(determinant(float2x2(v2,v3)))) {
77 float2 tmp = P[2];
78 if (sign(determinant(float2x2(v1,v2))) != sign(determinant(float2x2(v1,v3)))) {
79 P[2] = P[1]; // swap(P2, P1)
80 P[1] = tmp;
81 } else {
82 P[2] = P[3]; // swap(P2, P3)
83 P[3] = tmp;
84 }
Chris Daltona05ccc32021-06-29 19:42:13 -060085 })");
86
87 if (v->getProgramBuilder()->caps()->shaderCaps()->vertexIDSupport()) {
88 // If we don't have sk_VertexID support then "vertexidx" already came in as a
89 // vertex attrib.
90 v->codeAppend(R"(
91 // sk_VertexID comes in fan order. Convert to strip order.
92 int vertexidx = sk_VertexID;
93 vertexidx ^= vertexidx >> 1;)");
Chris Dalton2f733ec2021-06-01 12:11:57 -060094 }
95
Chris Daltona05ccc32021-06-29 19:42:13 -060096 v->codeAppend(R"(
Chris Dalton2f733ec2021-06-01 12:11:57 -060097 // Find the "turn direction" of each corner and net turn direction.
98 float vertexdir = 0;
99 float netdir = 0;
Chris Daltona05ccc32021-06-29 19:42:13 -0600100 float2 prev, next;
101 float dir;
102 float2 localcoord;
103 float2 nextcoord;)");
104
Chris Dalton2f733ec2021-06-01 12:11:57 -0600105 for (int i = 0; i < 4; ++i) {
Chris Daltona05ccc32021-06-29 19:42:13 -0600106 v->codeAppendf(R"(
107 prev = P[%i] - P[%i];)", i, (i + 3) % 4);
108 v->codeAppendf(R"(
109 next = P[%i] - P[%i];)", (i + 1) % 4, i);
110 v->codeAppendf(R"(
111 dir = sign(determinant(float2x2(prev, next)));
112 if (vertexidx == %i) {
Chris Dalton2f733ec2021-06-01 12:11:57 -0600113 vertexdir = dir;
Chris Daltona05ccc32021-06-29 19:42:13 -0600114 localcoord = P[%i];
115 nextcoord = P[%i];
Chris Dalton2f733ec2021-06-01 12:11:57 -0600116 }
Chris Daltona05ccc32021-06-29 19:42:13 -0600117 netdir += dir;)", i, i, (i + 1) % 4);
Chris Dalton2f733ec2021-06-01 12:11:57 -0600118 }
119
Chris Daltona05ccc32021-06-29 19:42:13 -0600120 v->codeAppend(R"(
Chris Dalton2f733ec2021-06-01 12:11:57 -0600121 // Remove the non-convex vertex, if any.
122 if (vertexdir != sign(netdir)) {
Chris Daltona05ccc32021-06-29 19:42:13 -0600123 localcoord = nextcoord;
Chris Dalton2f733ec2021-06-01 12:11:57 -0600124 }
125
Chris Dalton2f733ec2021-06-01 12:11:57 -0600126 float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
127 gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
128 gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
129 }
130 };
131 return new Impl;
132}
133
134} // namespace
135
Robert Phillips294723d2021-06-17 09:23:58 -0400136void GrPathInnerTriangulateOp::visitProxies(const GrVisitProxyFunc& func) const {
Chris Daltonebb37e72021-01-27 17:59:45 -0700137 if (fPipelineForFills) {
Robert Phillips294723d2021-06-17 09:23:58 -0400138 fPipelineForFills->visitProxies(func);
Chris Daltonebb37e72021-01-27 17:59:45 -0700139 } else {
Robert Phillips294723d2021-06-17 09:23:58 -0400140 fProcessors.visitProxies(func);
Chris Daltonebb37e72021-01-27 17:59:45 -0700141 }
142}
143
144GrDrawOp::FixedFunctionFlags GrPathInnerTriangulateOp::fixedFunctionFlags() const {
145 auto flags = FixedFunctionFlags::kUsesStencil;
146 if (GrAAType::kNone != fAAType) {
147 flags |= FixedFunctionFlags::kUsesHWAA;
148 }
149 return flags;
150}
151
152GrProcessorSet::Analysis GrPathInnerTriangulateOp::finalize(const GrCaps& caps,
153 const GrAppliedClip* clip,
Chris Daltonebb37e72021-01-27 17:59:45 -0700154 GrClampType clampType) {
Chris Dalton57ab06c2021-04-22 12:57:28 -0600155 return fProcessors.finalize(fColor, GrProcessorAnalysisCoverage::kNone, clip, nullptr, caps,
156 clampType, &fColor);
Chris Daltonebb37e72021-01-27 17:59:45 -0700157}
158
Chris Dalton2f733ec2021-06-01 12:11:57 -0600159void GrPathInnerTriangulateOp::pushFanStencilProgram(const GrTessellationShader::ProgramArgs& args,
Chris Daltonebb37e72021-01-27 17:59:45 -0700160 const GrPipeline* pipelineForStencils,
161 const GrUserStencilSettings* stencil) {
162 SkASSERT(pipelineForStencils);
Chris Daltonb63711a2021-06-01 14:52:02 -0600163 auto shader = GrPathTessellationShader::MakeSimpleTriangleShader(args.fArena, fViewMatrix,
164 SK_PMColor4fTRANSPARENT);
Chris Dalton2f733ec2021-06-01 12:11:57 -0600165 fFanPrograms.push_back(GrTessellationShader::MakeProgram(args, shader, pipelineForStencils,
166 stencil)); }
Chris Daltonebb37e72021-01-27 17:59:45 -0700167
Chris Dalton2f733ec2021-06-01 12:11:57 -0600168void GrPathInnerTriangulateOp::pushFanFillProgram(const GrTessellationShader::ProgramArgs& args,
Chris Daltonebb37e72021-01-27 17:59:45 -0700169 const GrUserStencilSettings* stencil) {
170 SkASSERT(fPipelineForFills);
Chris Daltonb63711a2021-06-01 14:52:02 -0600171 auto shader = GrPathTessellationShader::MakeSimpleTriangleShader(args.fArena, fViewMatrix,
172 fColor);
Chris Dalton2f733ec2021-06-01 12:11:57 -0600173 fFanPrograms.push_back(GrTessellationShader::MakeProgram(args, shader, fPipelineForFills,
174 stencil));
Chris Daltonebb37e72021-01-27 17:59:45 -0700175}
176
Chris Dalton2f733ec2021-06-01 12:11:57 -0600177void GrPathInnerTriangulateOp::prePreparePrograms(const GrTessellationShader::ProgramArgs& args,
Chris Daltonebb37e72021-01-27 17:59:45 -0700178 GrAppliedClip&& appliedClip) {
179 SkASSERT(!fFanTriangulator);
180 SkASSERT(!fFanPolys);
181 SkASSERT(!fPipelineForFills);
182 SkASSERT(!fTessellator);
183 SkASSERT(!fStencilCurvesProgram);
184 SkASSERT(fFanPrograms.empty());
Chris Dalton031d76b2021-06-08 16:32:00 -0600185 SkASSERT(!fCoverHullsProgram);
Chris Daltonebb37e72021-01-27 17:59:45 -0700186
187 if (fPath.countVerbs() <= 0) {
188 return;
189 }
190
Chris Dalton031d76b2021-06-08 16:32:00 -0600191 // If using wireframe, we have to fall back on a standard Redbook "stencil then cover" algorithm
Chris Dalton57ab06c2021-04-22 12:57:28 -0600192 // instead of bypassing the stencil buffer to fill the fan directly.
Chris Dalton917f9192021-06-08 14:32:37 -0600193 bool forceRedbookStencilPass = (fPathFlags & (PathFlags::kStencilOnly | PathFlags::kWireframe));
194 bool doFill = !(fPathFlags & PathFlags::kStencilOnly);
Chris Daltonebb37e72021-01-27 17:59:45 -0700195
196 bool isLinear;
197 fFanTriangulator = args.fArena->make<GrInnerFanTriangulator>(fPath, args.fArena);
198 fFanPolys = fFanTriangulator->pathToPolys(&fFanBreadcrumbs, &isLinear);
199
200 // Create a pipeline for stencil passes if needed.
201 const GrPipeline* pipelineForStencils = nullptr;
202 if (forceRedbookStencilPass || !isLinear) { // Curves always get stencilled.
Chris Dalton2f733ec2021-06-01 12:11:57 -0600203 pipelineForStencils = GrPathTessellationShader::MakeStencilOnlyPipeline(
Chris Dalton917f9192021-06-08 14:32:37 -0600204 args, fAAType, fPathFlags, appliedClip.hardClip());
Chris Daltonebb37e72021-01-27 17:59:45 -0700205 }
206
207 // Create a pipeline for fill passes if needed.
208 if (doFill) {
Chris Dalton2f733ec2021-06-01 12:11:57 -0600209 fPipelineForFills = GrTessellationShader::MakePipeline(args, fAAType,
210 std::move(appliedClip),
211 std::move(fProcessors));
Chris Daltonebb37e72021-01-27 17:59:45 -0700212 }
213
214 // Pass 1: Tessellate the outer curves into the stencil buffer.
215 if (!isLinear) {
Chris Dalton26666bd2021-06-08 16:25:46 -0600216 fTessellator = GrPathCurveTessellator::Make(args.fArena, fViewMatrix,
217 SK_PMColor4fTRANSPARENT,
Chris Daltond2b8ba32021-06-09 00:12:59 -0600218 GrPathCurveTessellator::DrawInnerFan::kNo,
Chris Dalton198ac152021-06-09 13:49:43 -0600219 fPath.countVerbs(), *pipelineForStencils,
220 *args.fCaps);
Chris Dalton2f733ec2021-06-01 12:11:57 -0600221 const GrUserStencilSettings* stencilPathSettings =
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600222 GrPathTessellationShader::StencilPathSettings(GrFillRuleForSkPath(fPath));
Chris Dalton2f733ec2021-06-01 12:11:57 -0600223 fStencilCurvesProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(),
224 pipelineForStencils,
225 stencilPathSettings);
Chris Daltonebb37e72021-01-27 17:59:45 -0700226 }
227
228 // Pass 2: Fill the path's inner fan with a stencil test against the curves.
229 if (fFanPolys) {
230 if (forceRedbookStencilPass) {
Chris Dalton031d76b2021-06-08 16:32:00 -0600231 // Use a standard Redbook "stencil then cover" algorithm instead of bypassing the
232 // stencil buffer to fill the fan directly.
Chris Dalton2f733ec2021-06-01 12:11:57 -0600233 const GrUserStencilSettings* stencilPathSettings =
Chris Daltonbaae2dd2021-06-25 14:52:49 -0600234 GrPathTessellationShader::StencilPathSettings(GrFillRuleForSkPath(fPath));
Chris Dalton2f733ec2021-06-01 12:11:57 -0600235 this->pushFanStencilProgram(args, pipelineForStencils, stencilPathSettings);
Chris Daltonebb37e72021-01-27 17:59:45 -0700236 if (doFill) {
Chris Dalton2f733ec2021-06-01 12:11:57 -0600237 this->pushFanFillProgram(args,
238 GrPathTessellationShader::TestAndResetStencilSettings());
Chris Daltonebb37e72021-01-27 17:59:45 -0700239 }
240 } else if (isLinear) {
241 // There are no outer curves! Ignore stencil and fill the path directly.
242 SkASSERT(!pipelineForStencils);
243 this->pushFanFillProgram(args, &GrUserStencilSettings::kUnused);
244 } else if (!fPipelineForFills->hasStencilClip()) {
245 // These are a twist on the standard Redbook stencil settings that allow us to fill the
246 // inner polygon directly to the final render target. By the time these programs
247 // execute, the outer curves will already be stencilled in. So if the stencil value is
248 // zero, then it means the sample in question is not affected by any curves and we can
249 // fill it in directly. If the stencil value is nonzero, then we don't fill and instead
250 // continue the standard Redbook counting process.
251 constexpr static GrUserStencilSettings kFillOrIncrDecrStencil(
252 GrUserStencilSettings::StaticInitSeparate<
253 0x0000, 0x0000,
254 GrUserStencilTest::kEqual, GrUserStencilTest::kEqual,
255 0xffff, 0xffff,
256 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
257 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
258 0xffff, 0xffff>());
259
260 constexpr static GrUserStencilSettings kFillOrInvertStencil(
261 GrUserStencilSettings::StaticInit<
262 0x0000,
263 GrUserStencilTest::kEqual,
264 0xffff,
265 GrUserStencilOp::kKeep,
266 // "Zero" instead of "Invert" because the fan only touches any given pixel once.
267 GrUserStencilOp::kZero,
268 0xffff>());
269
270 auto* stencil = (fPath.getFillType() == SkPathFillType::kWinding)
271 ? &kFillOrIncrDecrStencil
272 : &kFillOrInvertStencil;
273 this->pushFanFillProgram(args, stencil);
274 } else {
275 // This is the same idea as above, but we use two passes instead of one because there is
276 // a stencil clip. The stencil test isn't expressive enough to do the above tests and
277 // also check the clip bit in a single pass.
278 constexpr static GrUserStencilSettings kFillIfZeroAndInClip(
279 GrUserStencilSettings::StaticInit<
280 0x0000,
281 GrUserStencilTest::kEqualIfInClip,
282 0xffff,
283 GrUserStencilOp::kKeep,
284 GrUserStencilOp::kKeep,
285 0xffff>());
286
287 constexpr static GrUserStencilSettings kIncrDecrStencilIfNonzero(
288 GrUserStencilSettings::StaticInitSeparate<
289 0x0000, 0x0000,
290 // No need to check the clip because the previous stencil pass will have only
291 // written to samples already inside the clip.
292 GrUserStencilTest::kNotEqual, GrUserStencilTest::kNotEqual,
293 0xffff, 0xffff,
294 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
295 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
296 0xffff, 0xffff>());
297
298 constexpr static GrUserStencilSettings kInvertStencilIfNonZero(
299 GrUserStencilSettings::StaticInit<
300 0x0000,
301 // No need to check the clip because the previous stencil pass will have only
302 // written to samples already inside the clip.
303 GrUserStencilTest::kNotEqual,
304 0xffff,
305 // "Zero" instead of "Invert" because the fan only touches any given pixel once.
306 GrUserStencilOp::kZero,
307 GrUserStencilOp::kKeep,
308 0xffff>());
309
310 // Pass 2a: Directly fill fan samples whose stencil values (from curves) are zero.
311 this->pushFanFillProgram(args, &kFillIfZeroAndInClip);
312
313 // Pass 2b: Redbook counting on fan samples whose stencil values (from curves) != 0.
314 auto* stencil = (fPath.getFillType() == SkPathFillType::kWinding)
315 ? &kIncrDecrStencilIfNonzero
316 : &kInvertStencilIfNonZero;
317 this->pushFanStencilProgram(args, pipelineForStencils, stencil);
318 }
319 }
320
321 // Pass 3: Draw convex hulls around each curve.
322 if (doFill && !isLinear) {
323 // By the time this program executes, every pixel will be filled in except the ones touched
324 // by curves. We issue a final cover pass over the curves by drawing their convex hulls.
325 // This will fill in any remaining samples and reset the stencil values back to zero.
326 SkASSERT(fTessellator);
Chris Daltona05ccc32021-06-29 19:42:13 -0600327 auto* hullShader = args.fArena->make<HullShader>(fViewMatrix, fColor,
328 *args.fCaps->shaderCaps());
Chris Dalton031d76b2021-06-08 16:32:00 -0600329 fCoverHullsProgram = GrTessellationShader::MakeProgram(
Chris Daltonebb37e72021-01-27 17:59:45 -0700330 args, hullShader, fPipelineForFills,
Chris Dalton2f733ec2021-06-01 12:11:57 -0600331 GrPathTessellationShader::TestAndResetStencilSettings());
Chris Daltonebb37e72021-01-27 17:59:45 -0700332 }
333}
334
335void GrPathInnerTriangulateOp::onPrePrepare(GrRecordingContext* context,
336 const GrSurfaceProxyView& writeView,
337 GrAppliedClip* clip,
John Stiles52cb1d02021-06-02 11:58:05 -0400338 const GrDstProxyView& dstProxyView,
Chris Daltonebb37e72021-01-27 17:59:45 -0700339 GrXferBarrierFlags renderPassXferBarriers,
340 GrLoadOp colorLoadOp) {
341 this->prePreparePrograms({context->priv().recordTimeAllocator(), writeView, &dstProxyView,
342 renderPassXferBarriers, colorLoadOp, context->priv().caps()},
343 (clip) ? std::move(*clip) : GrAppliedClip::Disabled());
344 if (fStencilCurvesProgram) {
345 context->priv().recordProgramInfo(fStencilCurvesProgram);
346 }
347 for (const GrProgramInfo* fanProgram : fFanPrograms) {
348 context->priv().recordProgramInfo(fanProgram);
349 }
Chris Dalton031d76b2021-06-08 16:32:00 -0600350 if (fCoverHullsProgram) {
351 context->priv().recordProgramInfo(fCoverHullsProgram);
Chris Daltonebb37e72021-01-27 17:59:45 -0700352 }
353}
354
Chris Daltona05ccc32021-06-29 19:42:13 -0600355GR_DECLARE_STATIC_UNIQUE_KEY(gHullVertexBufferKey);
356
Chris Daltonebb37e72021-01-27 17:59:45 -0700357void GrPathInnerTriangulateOp::onPrepare(GrOpFlushState* flushState) {
358 if (!fFanTriangulator) {
359 this->prePreparePrograms({flushState->allocator(), flushState->writeView(),
360 &flushState->dstProxyView(), flushState->renderPassBarriers(),
361 flushState->colorLoadOp(), &flushState->caps()},
362 flushState->detachAppliedClip());
363 if (!fFanTriangulator) {
364 return;
365 }
366 }
367
368 if (fFanPolys) {
369 GrEagerDynamicVertexAllocator alloc(flushState, &fFanBuffer, &fBaseFanVertex);
370 fFanVertexCount = fFanTriangulator->polysToTriangles(fFanPolys, &alloc, &fFanBreadcrumbs);
371 }
372
373 if (fTessellator) {
374 // Must be called after polysToTriangles() in order for fFanBreadcrumbs to be complete.
Chris Dalton569c01b2021-05-25 10:11:46 -0600375 fTessellator->prepare(flushState, this->bounds(), fPath, &fFanBreadcrumbs);
Chris Daltonebb37e72021-01-27 17:59:45 -0700376 }
Chris Daltona05ccc32021-06-29 19:42:13 -0600377
378 if (!flushState->caps().shaderCaps()->vertexIDSupport()) {
379 constexpr static float kStripOrderIDs[4] = {0, 1, 3, 2};
380
381 GR_DEFINE_STATIC_UNIQUE_KEY(gHullVertexBufferKey);
382
383 fHullVertexBufferIfNoIDSupport = flushState->resourceProvider()->findOrMakeStaticBuffer(
384 GrGpuBufferType::kVertex, sizeof(kStripOrderIDs), kStripOrderIDs,
385 gHullVertexBufferKey);
386 }
Chris Daltonebb37e72021-01-27 17:59:45 -0700387}
388
389void GrPathInnerTriangulateOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
390 if (fStencilCurvesProgram) {
391 SkASSERT(fTessellator);
392 flushState->bindPipelineAndScissorClip(*fStencilCurvesProgram, this->bounds());
393 fTessellator->draw(flushState);
Chris Daltond9bdc322021-06-01 19:22:05 -0600394 if (flushState->caps().requiresManualFBBarrierAfterTessellatedStencilDraw()) {
395 flushState->gpu()->insertManualFramebufferBarrier(); // http://skbug.com/9739
396 }
Chris Daltonebb37e72021-01-27 17:59:45 -0700397 }
398
399 for (const GrProgramInfo* fanProgram : fFanPrograms) {
400 SkASSERT(fFanBuffer);
401 flushState->bindPipelineAndScissorClip(*fanProgram, this->bounds());
Robert Phillips787fd9d2021-03-22 14:48:09 -0400402 flushState->bindTextures(fanProgram->geomProc(), nullptr, fanProgram->pipeline());
Chris Daltonebb37e72021-01-27 17:59:45 -0700403 flushState->bindBuffers(nullptr, nullptr, fFanBuffer);
404 flushState->draw(fFanVertexCount, fBaseFanVertex);
405 }
406
Chris Dalton031d76b2021-06-08 16:32:00 -0600407 if (fCoverHullsProgram) {
Chris Daltonebb37e72021-01-27 17:59:45 -0700408 SkASSERT(fTessellator);
Chris Dalton031d76b2021-06-08 16:32:00 -0600409 flushState->bindPipelineAndScissorClip(*fCoverHullsProgram, this->bounds());
410 flushState->bindTextures(fCoverHullsProgram->geomProc(), nullptr, *fPipelineForFills);
Chris Daltona05ccc32021-06-29 19:42:13 -0600411 fTessellator->drawHullInstances(flushState, fHullVertexBufferIfNoIDSupport);
Chris Daltonebb37e72021-01-27 17:59:45 -0700412 }
413}