xref: /aosp_15_r20/external/skia/src/gpu/ganesh/ops/StrokeTessellateOp.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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