1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2020 Google LLC.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/StrokeTessellateOp.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAppliedClip.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpFlushState.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPaint.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorAnalysis.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProgramInfo.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRenderTargetProxy.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrShaderCaps.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxyView.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrUserStencilSettings.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/tessellate/GrStrokeTessellationShader.h"
27*c8dee2aaSAndroid Build Coastguard Worker
28*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh {
31*c8dee2aaSAndroid Build Coastguard Worker
StrokeTessellateOp(GrAAType aaType,const SkMatrix & viewMatrix,const SkPath & path,const SkStrokeRec & stroke,GrPaint && paint)32*c8dee2aaSAndroid Build Coastguard Worker StrokeTessellateOp::StrokeTessellateOp(GrAAType aaType, const SkMatrix& viewMatrix,
33*c8dee2aaSAndroid Build Coastguard Worker const SkPath& path, const SkStrokeRec& stroke,
34*c8dee2aaSAndroid Build Coastguard Worker GrPaint&& paint)
35*c8dee2aaSAndroid Build Coastguard Worker : GrDrawOp(ClassID())
36*c8dee2aaSAndroid Build Coastguard Worker , fAAType(aaType)
37*c8dee2aaSAndroid Build Coastguard Worker , fViewMatrix(viewMatrix)
38*c8dee2aaSAndroid Build Coastguard Worker , fPathStrokeList(path, stroke, paint.getColor4f())
39*c8dee2aaSAndroid Build Coastguard Worker , fTotalCombinedVerbCnt(path.countVerbs())
40*c8dee2aaSAndroid Build Coastguard Worker , fProcessors(std::move(paint)) {
41*c8dee2aaSAndroid Build Coastguard Worker if (!this->headColor().fitsInBytes()) {
42*c8dee2aaSAndroid Build Coastguard Worker fPatchAttribs |= PatchAttribs::kWideColorIfEnabled;
43*c8dee2aaSAndroid Build Coastguard Worker }
44*c8dee2aaSAndroid Build Coastguard Worker SkRect devBounds = path.getBounds();
45*c8dee2aaSAndroid Build Coastguard Worker if (!this->headStroke().isHairlineStyle()) {
46*c8dee2aaSAndroid Build Coastguard Worker // Non-hairlines inflate in local path space (pre-transform).
47*c8dee2aaSAndroid Build Coastguard Worker float r = stroke.getInflationRadius();
48*c8dee2aaSAndroid Build Coastguard Worker devBounds.outset(r, r);
49*c8dee2aaSAndroid Build Coastguard Worker }
50*c8dee2aaSAndroid Build Coastguard Worker viewMatrix.mapRect(&devBounds, devBounds);
51*c8dee2aaSAndroid Build Coastguard Worker if (this->headStroke().isHairlineStyle()) {
52*c8dee2aaSAndroid Build Coastguard Worker // Hairlines inflate in device space (post-transform).
53*c8dee2aaSAndroid Build Coastguard Worker float r = SkStrokeRec::GetInflationRadius(stroke.getJoin(), stroke.getMiter(),
54*c8dee2aaSAndroid Build Coastguard Worker stroke.getCap(), 1);
55*c8dee2aaSAndroid Build Coastguard Worker devBounds.outset(r, r);
56*c8dee2aaSAndroid Build Coastguard Worker }
57*c8dee2aaSAndroid Build Coastguard Worker this->setBounds(devBounds, HasAABloat::kNo, IsHairline::kNo);
58*c8dee2aaSAndroid Build Coastguard Worker }
59*c8dee2aaSAndroid Build Coastguard Worker
visitProxies(const GrVisitProxyFunc & func) const60*c8dee2aaSAndroid Build Coastguard Worker void StrokeTessellateOp::visitProxies(const GrVisitProxyFunc& func) const {
61*c8dee2aaSAndroid Build Coastguard Worker if (fFillProgram) {
62*c8dee2aaSAndroid Build Coastguard Worker fFillProgram->visitFPProxies(func);
63*c8dee2aaSAndroid Build Coastguard Worker } else if (fStencilProgram) {
64*c8dee2aaSAndroid Build Coastguard Worker fStencilProgram->visitFPProxies(func);
65*c8dee2aaSAndroid Build Coastguard Worker } else {
66*c8dee2aaSAndroid Build Coastguard Worker fProcessors.visitProxies(func);
67*c8dee2aaSAndroid Build Coastguard Worker }
68*c8dee2aaSAndroid Build Coastguard Worker }
69*c8dee2aaSAndroid Build Coastguard Worker
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrClampType clampType)70*c8dee2aaSAndroid Build Coastguard Worker GrProcessorSet::Analysis StrokeTessellateOp::finalize(const GrCaps& caps,
71*c8dee2aaSAndroid Build Coastguard Worker const GrAppliedClip* clip,
72*c8dee2aaSAndroid Build Coastguard Worker GrClampType clampType) {
73*c8dee2aaSAndroid Build Coastguard Worker // Make sure the finalize happens before combining. We might change fNeedsStencil here.
74*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fPathStrokeList.fNext == nullptr);
75*c8dee2aaSAndroid Build Coastguard Worker if (!caps.shaderCaps()->fInfinitySupport) {
76*c8dee2aaSAndroid Build Coastguard Worker // The GPU can't infer curve type based in infinity, so we need to send in an attrib
77*c8dee2aaSAndroid Build Coastguard Worker // explicitly stating the curve type.
78*c8dee2aaSAndroid Build Coastguard Worker fPatchAttribs |= PatchAttribs::kExplicitCurveType;
79*c8dee2aaSAndroid Build Coastguard Worker }
80*c8dee2aaSAndroid Build Coastguard Worker const GrProcessorSet::Analysis& analysis = fProcessors.finalize(
81*c8dee2aaSAndroid Build Coastguard Worker this->headColor(), GrProcessorAnalysisCoverage::kNone, clip,
82*c8dee2aaSAndroid Build Coastguard Worker &GrUserStencilSettings::kUnused, caps, clampType, &this->headColor());
83*c8dee2aaSAndroid Build Coastguard Worker fNeedsStencil = !analysis.unaffectedByDstValue();
84*c8dee2aaSAndroid Build Coastguard Worker return analysis;
85*c8dee2aaSAndroid Build Coastguard Worker }
86*c8dee2aaSAndroid Build Coastguard Worker
onCombineIfPossible(GrOp * grOp,SkArenaAlloc * alloc,const GrCaps & caps)87*c8dee2aaSAndroid Build Coastguard Worker GrOp::CombineResult StrokeTessellateOp::onCombineIfPossible(GrOp* grOp, SkArenaAlloc* alloc,
88*c8dee2aaSAndroid Build Coastguard Worker const GrCaps& caps) {
89*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(grOp->classID() == this->classID());
90*c8dee2aaSAndroid Build Coastguard Worker auto* op = static_cast<StrokeTessellateOp*>(grOp);
91*c8dee2aaSAndroid Build Coastguard Worker
92*c8dee2aaSAndroid Build Coastguard Worker // This must be called after finalize(). fNeedsStencil can change in finalize().
93*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fProcessors.isFinalized());
94*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(op->fProcessors.isFinalized());
95*c8dee2aaSAndroid Build Coastguard Worker
96*c8dee2aaSAndroid Build Coastguard Worker if (fNeedsStencil ||
97*c8dee2aaSAndroid Build Coastguard Worker op->fNeedsStencil ||
98*c8dee2aaSAndroid Build Coastguard Worker fViewMatrix != op->fViewMatrix ||
99*c8dee2aaSAndroid Build Coastguard Worker fAAType != op->fAAType ||
100*c8dee2aaSAndroid Build Coastguard Worker fProcessors != op->fProcessors ||
101*c8dee2aaSAndroid Build Coastguard Worker this->headStroke().isHairlineStyle() != op->headStroke().isHairlineStyle()) {
102*c8dee2aaSAndroid Build Coastguard Worker return CombineResult::kCannotCombine;
103*c8dee2aaSAndroid Build Coastguard Worker }
104*c8dee2aaSAndroid Build Coastguard Worker
105*c8dee2aaSAndroid Build Coastguard Worker auto combinedAttribs = fPatchAttribs | op->fPatchAttribs;
106*c8dee2aaSAndroid Build Coastguard Worker if (!(combinedAttribs & PatchAttribs::kStrokeParams) &&
107*c8dee2aaSAndroid Build Coastguard Worker !tess::StrokesHaveEqualParams(this->headStroke(), op->headStroke())) {
108*c8dee2aaSAndroid Build Coastguard Worker // The paths have different stroke properties. We will need to enable dynamic stroke if we
109*c8dee2aaSAndroid Build Coastguard Worker // still decide to combine them.
110*c8dee2aaSAndroid Build Coastguard Worker if (this->headStroke().isHairlineStyle()) {
111*c8dee2aaSAndroid Build Coastguard Worker return CombineResult::kCannotCombine; // Dynamic hairlines aren't supported.
112*c8dee2aaSAndroid Build Coastguard Worker }
113*c8dee2aaSAndroid Build Coastguard Worker combinedAttribs |= PatchAttribs::kStrokeParams;
114*c8dee2aaSAndroid Build Coastguard Worker }
115*c8dee2aaSAndroid Build Coastguard Worker if (!(combinedAttribs & PatchAttribs::kColor) && this->headColor() != op->headColor()) {
116*c8dee2aaSAndroid Build Coastguard Worker // The paths have different colors. We will need to enable dynamic color if we still decide
117*c8dee2aaSAndroid Build Coastguard Worker // to combine them.
118*c8dee2aaSAndroid Build Coastguard Worker combinedAttribs |= PatchAttribs::kColor;
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker
121*c8dee2aaSAndroid Build Coastguard Worker // Don't actually enable new dynamic state on ops that already have lots of verbs.
122*c8dee2aaSAndroid Build Coastguard Worker constexpr static SkTFlagsMask<PatchAttribs> kDynamicStatesMask(PatchAttribs::kStrokeParams |
123*c8dee2aaSAndroid Build Coastguard Worker PatchAttribs::kColor);
124*c8dee2aaSAndroid Build Coastguard Worker PatchAttribs neededDynamicStates = combinedAttribs & kDynamicStatesMask;
125*c8dee2aaSAndroid Build Coastguard Worker if (neededDynamicStates != PatchAttribs::kNone) {
126*c8dee2aaSAndroid Build Coastguard Worker if (!this->shouldUseDynamicStates(neededDynamicStates) ||
127*c8dee2aaSAndroid Build Coastguard Worker !op->shouldUseDynamicStates(neededDynamicStates)) {
128*c8dee2aaSAndroid Build Coastguard Worker return CombineResult::kCannotCombine;
129*c8dee2aaSAndroid Build Coastguard Worker }
130*c8dee2aaSAndroid Build Coastguard Worker }
131*c8dee2aaSAndroid Build Coastguard Worker
132*c8dee2aaSAndroid Build Coastguard Worker fPatchAttribs = combinedAttribs;
133*c8dee2aaSAndroid Build Coastguard Worker
134*c8dee2aaSAndroid Build Coastguard Worker // Concat the op's PathStrokeList. Since the head element is allocated inside the op, we need to
135*c8dee2aaSAndroid Build Coastguard Worker // copy it.
136*c8dee2aaSAndroid Build Coastguard Worker auto* headCopy = alloc->make<PathStrokeList>(std::move(op->fPathStrokeList));
137*c8dee2aaSAndroid Build Coastguard Worker *fPathStrokeTail = headCopy;
138*c8dee2aaSAndroid Build Coastguard Worker fPathStrokeTail = (op->fPathStrokeTail == &op->fPathStrokeList.fNext) ? &headCopy->fNext
139*c8dee2aaSAndroid Build Coastguard Worker : op->fPathStrokeTail;
140*c8dee2aaSAndroid Build Coastguard Worker
141*c8dee2aaSAndroid Build Coastguard Worker fTotalCombinedVerbCnt += op->fTotalCombinedVerbCnt;
142*c8dee2aaSAndroid Build Coastguard Worker return CombineResult::kMerged;
143*c8dee2aaSAndroid Build Coastguard Worker }
144*c8dee2aaSAndroid Build Coastguard Worker
145*c8dee2aaSAndroid Build Coastguard Worker // Marks every stencil value as "1".
146*c8dee2aaSAndroid Build Coastguard Worker constexpr static GrUserStencilSettings kMarkStencil(
147*c8dee2aaSAndroid Build Coastguard Worker GrUserStencilSettings::StaticInit<
148*c8dee2aaSAndroid Build Coastguard Worker 0x0001,
149*c8dee2aaSAndroid Build Coastguard Worker GrUserStencilTest::kLessIfInClip, // Match kTestAndResetStencil.
150*c8dee2aaSAndroid Build Coastguard Worker 0x0000, // Always fail.
151*c8dee2aaSAndroid Build Coastguard Worker GrUserStencilOp::kZero,
152*c8dee2aaSAndroid Build Coastguard Worker GrUserStencilOp::kReplace,
153*c8dee2aaSAndroid Build Coastguard Worker 0xffff>());
154*c8dee2aaSAndroid Build Coastguard Worker
155*c8dee2aaSAndroid Build Coastguard Worker // Passes if the stencil value is nonzero. Also resets the stencil value to zero on pass. This is
156*c8dee2aaSAndroid Build Coastguard Worker // formulated to match kMarkStencil everywhere except the ref and compare mask. This will allow us
157*c8dee2aaSAndroid Build Coastguard Worker // to use the same pipeline for both stencil and fill if dynamic stencil state is supported.
158*c8dee2aaSAndroid Build Coastguard Worker constexpr static GrUserStencilSettings kTestAndResetStencil(
159*c8dee2aaSAndroid Build Coastguard Worker GrUserStencilSettings::StaticInit<
160*c8dee2aaSAndroid Build Coastguard Worker 0x0000,
161*c8dee2aaSAndroid Build Coastguard Worker GrUserStencilTest::kLessIfInClip, // i.e., "not equal to zero, if in clip".
162*c8dee2aaSAndroid Build Coastguard Worker 0x0001,
163*c8dee2aaSAndroid Build Coastguard Worker GrUserStencilOp::kZero,
164*c8dee2aaSAndroid Build Coastguard Worker GrUserStencilOp::kReplace,
165*c8dee2aaSAndroid Build Coastguard Worker 0xffff>());
166*c8dee2aaSAndroid Build Coastguard Worker
prePrepareTessellator(GrTessellationShader::ProgramArgs && args,GrAppliedClip && clip)167*c8dee2aaSAndroid Build Coastguard Worker void StrokeTessellateOp::prePrepareTessellator(GrTessellationShader::ProgramArgs&& args,
168*c8dee2aaSAndroid Build Coastguard Worker GrAppliedClip&& clip) {
169*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fTessellator);
170*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fFillProgram);
171*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fStencilProgram);
172*c8dee2aaSAndroid Build Coastguard Worker // GrOp::setClippedBounds() should have been called by now.
173*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(SkRect::MakeIWH(args.fWriteView.width(),
174*c8dee2aaSAndroid Build Coastguard Worker args.fWriteView.height()).contains(this->bounds()));
175*c8dee2aaSAndroid Build Coastguard Worker
176*c8dee2aaSAndroid Build Coastguard Worker const GrCaps& caps = *args.fCaps;
177*c8dee2aaSAndroid Build Coastguard Worker SkArenaAlloc* arena = args.fArena;
178*c8dee2aaSAndroid Build Coastguard Worker
179*c8dee2aaSAndroid Build Coastguard Worker auto* pipeline = GrTessellationShader::MakePipeline(args, fAAType, std::move(clip),
180*c8dee2aaSAndroid Build Coastguard Worker std::move(fProcessors));
181*c8dee2aaSAndroid Build Coastguard Worker
182*c8dee2aaSAndroid Build Coastguard Worker fTessellator = arena->make<StrokeTessellator>(fPatchAttribs);
183*c8dee2aaSAndroid Build Coastguard Worker fTessellationShader = args.fArena->make<GrStrokeTessellationShader>(
184*c8dee2aaSAndroid Build Coastguard Worker *caps.shaderCaps(),
185*c8dee2aaSAndroid Build Coastguard Worker fPatchAttribs,
186*c8dee2aaSAndroid Build Coastguard Worker fViewMatrix,
187*c8dee2aaSAndroid Build Coastguard Worker this->headStroke(),
188*c8dee2aaSAndroid Build Coastguard Worker this->headColor());
189*c8dee2aaSAndroid Build Coastguard Worker
190*c8dee2aaSAndroid Build Coastguard Worker auto fillStencil = &GrUserStencilSettings::kUnused;
191*c8dee2aaSAndroid Build Coastguard Worker if (fNeedsStencil) {
192*c8dee2aaSAndroid Build Coastguard Worker fStencilProgram = GrTessellationShader::MakeProgram(args, fTessellationShader, pipeline,
193*c8dee2aaSAndroid Build Coastguard Worker &kMarkStencil);
194*c8dee2aaSAndroid Build Coastguard Worker fillStencil = &kTestAndResetStencil;
195*c8dee2aaSAndroid Build Coastguard Worker // TODO: Currently if we have a texture barrier for a dst read it will get put in before
196*c8dee2aaSAndroid Build Coastguard Worker // both the stencil draw and the fill draw. In reality we only really need the barrier
197*c8dee2aaSAndroid Build Coastguard Worker // once to guard the reads of the color buffer in the fill from the previous writes. Maybe
198*c8dee2aaSAndroid Build Coastguard Worker // we can investigate how to remove one of these barriers but it is probably not something
199*c8dee2aaSAndroid Build Coastguard Worker // that is required a lot and thus the extra barrier shouldn't be too much of a perf hit to
200*c8dee2aaSAndroid Build Coastguard Worker // general Skia use.
201*c8dee2aaSAndroid Build Coastguard Worker }
202*c8dee2aaSAndroid Build Coastguard Worker
203*c8dee2aaSAndroid Build Coastguard Worker fFillProgram = GrTessellationShader::MakeProgram(args, fTessellationShader, pipeline,
204*c8dee2aaSAndroid Build Coastguard Worker fillStencil);
205*c8dee2aaSAndroid Build Coastguard Worker }
206*c8dee2aaSAndroid Build Coastguard Worker
onPrePrepare(GrRecordingContext * context,const GrSurfaceProxyView & writeView,GrAppliedClip * clip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)207*c8dee2aaSAndroid Build Coastguard Worker void StrokeTessellateOp::onPrePrepare(GrRecordingContext* context,
208*c8dee2aaSAndroid Build Coastguard Worker const GrSurfaceProxyView& writeView, GrAppliedClip* clip,
209*c8dee2aaSAndroid Build Coastguard Worker const GrDstProxyView& dstProxyView,
210*c8dee2aaSAndroid Build Coastguard Worker GrXferBarrierFlags renderPassXferBarriers, GrLoadOp
211*c8dee2aaSAndroid Build Coastguard Worker colorLoadOp) {
212*c8dee2aaSAndroid Build Coastguard Worker // DMSAA is not supported on DDL.
213*c8dee2aaSAndroid Build Coastguard Worker bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1;
214*c8dee2aaSAndroid Build Coastguard Worker this->prePrepareTessellator({context->priv().recordTimeAllocator(), writeView, usesMSAASurface,
215*c8dee2aaSAndroid Build Coastguard Worker &dstProxyView, renderPassXferBarriers, colorLoadOp,
216*c8dee2aaSAndroid Build Coastguard Worker context->priv().caps()},
217*c8dee2aaSAndroid Build Coastguard Worker (clip) ? std::move(*clip) : GrAppliedClip::Disabled());
218*c8dee2aaSAndroid Build Coastguard Worker if (fStencilProgram) {
219*c8dee2aaSAndroid Build Coastguard Worker context->priv().recordProgramInfo(fStencilProgram);
220*c8dee2aaSAndroid Build Coastguard Worker }
221*c8dee2aaSAndroid Build Coastguard Worker if (fFillProgram) {
222*c8dee2aaSAndroid Build Coastguard Worker context->priv().recordProgramInfo(fFillProgram);
223*c8dee2aaSAndroid Build Coastguard Worker }
224*c8dee2aaSAndroid Build Coastguard Worker }
225*c8dee2aaSAndroid Build Coastguard Worker
onPrepare(GrOpFlushState * flushState)226*c8dee2aaSAndroid Build Coastguard Worker void StrokeTessellateOp::onPrepare(GrOpFlushState* flushState) {
227*c8dee2aaSAndroid Build Coastguard Worker if (!fTessellator) {
228*c8dee2aaSAndroid Build Coastguard Worker this->prePrepareTessellator({flushState->allocator(), flushState->writeView(),
229*c8dee2aaSAndroid Build Coastguard Worker flushState->usesMSAASurface(), &flushState->dstProxyView(),
230*c8dee2aaSAndroid Build Coastguard Worker flushState->renderPassBarriers(), flushState->colorLoadOp(),
231*c8dee2aaSAndroid Build Coastguard Worker &flushState->caps()}, flushState->detachAppliedClip());
232*c8dee2aaSAndroid Build Coastguard Worker }
233*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fTessellator);
234*c8dee2aaSAndroid Build Coastguard Worker fTessellator->prepare(flushState,
235*c8dee2aaSAndroid Build Coastguard Worker fViewMatrix,
236*c8dee2aaSAndroid Build Coastguard Worker &fPathStrokeList,
237*c8dee2aaSAndroid Build Coastguard Worker fTotalCombinedVerbCnt);
238*c8dee2aaSAndroid Build Coastguard Worker }
239*c8dee2aaSAndroid Build Coastguard Worker
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)240*c8dee2aaSAndroid Build Coastguard Worker void StrokeTessellateOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
241*c8dee2aaSAndroid Build Coastguard Worker if (fStencilProgram) {
242*c8dee2aaSAndroid Build Coastguard Worker flushState->bindPipelineAndScissorClip(*fStencilProgram, chainBounds);
243*c8dee2aaSAndroid Build Coastguard Worker flushState->bindTextures(fStencilProgram->geomProc(), nullptr, fStencilProgram->pipeline());
244*c8dee2aaSAndroid Build Coastguard Worker fTessellator->draw(flushState);
245*c8dee2aaSAndroid Build Coastguard Worker }
246*c8dee2aaSAndroid Build Coastguard Worker if (fFillProgram) {
247*c8dee2aaSAndroid Build Coastguard Worker flushState->bindPipelineAndScissorClip(*fFillProgram, chainBounds);
248*c8dee2aaSAndroid Build Coastguard Worker flushState->bindTextures(fFillProgram->geomProc(), nullptr, fFillProgram->pipeline());
249*c8dee2aaSAndroid Build Coastguard Worker fTessellator->draw(flushState);
250*c8dee2aaSAndroid Build Coastguard Worker }
251*c8dee2aaSAndroid Build Coastguard Worker }
252*c8dee2aaSAndroid Build Coastguard Worker
253*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::ganesh
254