xref: /aosp_15_r20/external/skia/src/gpu/ganesh/ops/PathStencilCoverOp.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2021 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/PathStencilCoverOp.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathTypes.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAlignedStorage.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkOnce.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMatrixPriv.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkSLTypeShared.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/BufferWriter.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ResourceKey.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAppliedClip.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrEagerVertexAllocator.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGeometryProcessor.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpFlushState.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPipeline.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorAnalysis.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProgramInfo.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRenderTargetProxy.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrResourceProvider.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrShaderCaps.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrShaderVar.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxyView.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/FillPathFlags.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelper.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/tessellate/GrPathTessellationShader.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/tessellate/AffineMatrix.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
46*c8dee2aaSAndroid Build Coastguard Worker #include <array>
47*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
48*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
49*c8dee2aaSAndroid Build Coastguard Worker 
50*c8dee2aaSAndroid Build Coastguard Worker class GrDstProxyView;
51*c8dee2aaSAndroid Build Coastguard Worker enum class GrXferBarrierFlags;
52*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu {
53*c8dee2aaSAndroid Build Coastguard Worker class KeyBuilder;
54*c8dee2aaSAndroid Build Coastguard Worker }
55*c8dee2aaSAndroid Build Coastguard Worker struct GrUserStencilSettings;
56*c8dee2aaSAndroid Build Coastguard Worker 
57*c8dee2aaSAndroid Build Coastguard Worker namespace {
58*c8dee2aaSAndroid Build Coastguard Worker 
59*c8dee2aaSAndroid Build Coastguard Worker // Fills a path's bounding box, with subpixel outset to avoid possible T-junctions with extreme
60*c8dee2aaSAndroid Build Coastguard Worker // edges of the path.
61*c8dee2aaSAndroid Build Coastguard Worker // NOTE: The emitted geometry may not be axis-aligned, depending on the view matrix.
62*c8dee2aaSAndroid Build Coastguard Worker class BoundingBoxShader : public GrGeometryProcessor {
63*c8dee2aaSAndroid Build Coastguard Worker public:
BoundingBoxShader(SkPMColor4f color,const GrShaderCaps & shaderCaps)64*c8dee2aaSAndroid Build Coastguard Worker     BoundingBoxShader(SkPMColor4f color, const GrShaderCaps& shaderCaps)
65*c8dee2aaSAndroid Build Coastguard Worker             : GrGeometryProcessor(kTessellate_BoundingBoxShader_ClassID)
66*c8dee2aaSAndroid Build Coastguard Worker             , fColor(color) {
67*c8dee2aaSAndroid Build Coastguard Worker         if (!shaderCaps.fVertexIDSupport) {
68*c8dee2aaSAndroid Build Coastguard Worker             constexpr static Attribute kUnitCoordAttrib("unitCoord", kFloat2_GrVertexAttribType,
69*c8dee2aaSAndroid Build Coastguard Worker                                                         SkSLType::kFloat2);
70*c8dee2aaSAndroid Build Coastguard Worker             this->setVertexAttributesWithImplicitOffsets(&kUnitCoordAttrib, 1);
71*c8dee2aaSAndroid Build Coastguard Worker         }
72*c8dee2aaSAndroid Build Coastguard Worker         constexpr static Attribute kInstanceAttribs[] = {
73*c8dee2aaSAndroid Build Coastguard Worker             {"matrix2d", kFloat4_GrVertexAttribType, SkSLType::kFloat4},
74*c8dee2aaSAndroid Build Coastguard Worker             {"translate", kFloat2_GrVertexAttribType, SkSLType::kFloat2},
75*c8dee2aaSAndroid Build Coastguard Worker             {"pathBounds", kFloat4_GrVertexAttribType, SkSLType::kFloat4}
76*c8dee2aaSAndroid Build Coastguard Worker         };
77*c8dee2aaSAndroid Build Coastguard Worker         this->setInstanceAttributesWithImplicitOffsets(kInstanceAttribs,
78*c8dee2aaSAndroid Build Coastguard Worker                                                        std::size(kInstanceAttribs));
79*c8dee2aaSAndroid Build Coastguard Worker     }
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker private:
name() const82*c8dee2aaSAndroid Build Coastguard Worker     const char* name() const final { return "tessellate_BoundingBoxShader"; }
addToKey(const GrShaderCaps &,skgpu::KeyBuilder *) const83*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const final {}
84*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const final;
85*c8dee2aaSAndroid Build Coastguard Worker 
86*c8dee2aaSAndroid Build Coastguard Worker     const SkPMColor4f fColor;
87*c8dee2aaSAndroid Build Coastguard Worker };
88*c8dee2aaSAndroid Build Coastguard Worker 
makeProgramImpl(const GrShaderCaps &) const89*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrGeometryProcessor::ProgramImpl> BoundingBoxShader::makeProgramImpl(
90*c8dee2aaSAndroid Build Coastguard Worker         const GrShaderCaps&) const {
91*c8dee2aaSAndroid Build Coastguard Worker     class Impl : public ProgramImpl {
92*c8dee2aaSAndroid Build Coastguard Worker     public:
93*c8dee2aaSAndroid Build Coastguard Worker         void setData(const GrGLSLProgramDataManager& pdman,
94*c8dee2aaSAndroid Build Coastguard Worker                      const GrShaderCaps&,
95*c8dee2aaSAndroid Build Coastguard Worker                      const GrGeometryProcessor& gp) override {
96*c8dee2aaSAndroid Build Coastguard Worker             const SkPMColor4f& color = gp.cast<BoundingBoxShader>().fColor;
97*c8dee2aaSAndroid Build Coastguard Worker             pdman.set4f(fColorUniform, color.fR, color.fG, color.fB, color.fA);
98*c8dee2aaSAndroid Build Coastguard Worker         }
99*c8dee2aaSAndroid Build Coastguard Worker 
100*c8dee2aaSAndroid Build Coastguard Worker     private:
101*c8dee2aaSAndroid Build Coastguard Worker         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
102*c8dee2aaSAndroid Build Coastguard Worker             args.fVaryingHandler->emitAttributes(args.fGeomProc);
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker             // Vertex shader.
105*c8dee2aaSAndroid Build Coastguard Worker             if (args.fShaderCaps->fVertexIDSupport) {
106*c8dee2aaSAndroid Build Coastguard Worker                 // If we don't have sk_VertexID support then "unitCoord" already came in as a vertex
107*c8dee2aaSAndroid Build Coastguard Worker                 // attrib.
108*c8dee2aaSAndroid Build Coastguard Worker                 args.fVertBuilder->codeAppend(
109*c8dee2aaSAndroid Build Coastguard Worker                 "float2 unitCoord = float2(sk_VertexID & 1, sk_VertexID >> 1);");
110*c8dee2aaSAndroid Build Coastguard Worker             }
111*c8dee2aaSAndroid Build Coastguard Worker             args.fVertBuilder->codeAppend(
112*c8dee2aaSAndroid Build Coastguard Worker             // Bloat the bounding box by 1/4px to be certain we will reset every stencil value.
113*c8dee2aaSAndroid Build Coastguard Worker             "float2x2 M_ = inverse(float2x2(matrix2d.xy, matrix2d.zw));"
114*c8dee2aaSAndroid Build Coastguard Worker             "float2 bloat = float2(abs(M_[0]) + abs(M_[1])) * .25;"
115*c8dee2aaSAndroid Build Coastguard Worker 
116*c8dee2aaSAndroid Build Coastguard Worker             // Find the vertex position.
117*c8dee2aaSAndroid Build Coastguard Worker             "float2 localcoord = mix(pathBounds.xy - bloat, pathBounds.zw + bloat, unitCoord);"
118*c8dee2aaSAndroid Build Coastguard Worker             "float2 vertexpos = float2x2(matrix2d.xy, matrix2d.zw) * localcoord + translate;"
119*c8dee2aaSAndroid Build Coastguard Worker             );
120*c8dee2aaSAndroid Build Coastguard Worker             gpArgs->fLocalCoordVar.set(SkSLType::kFloat2, "localcoord");
121*c8dee2aaSAndroid Build Coastguard Worker             gpArgs->fPositionVar.set(SkSLType::kFloat2, "vertexpos");
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker             // Fragment shader.
124*c8dee2aaSAndroid Build Coastguard Worker             const char* color;
125*c8dee2aaSAndroid Build Coastguard Worker             fColorUniform = args.fUniformHandler->addUniform(nullptr, kFragment_GrShaderFlag,
126*c8dee2aaSAndroid Build Coastguard Worker                                                              SkSLType::kHalf4, "color", &color);
127*c8dee2aaSAndroid Build Coastguard Worker             args.fFragBuilder->codeAppendf("half4 %s = %s;", args.fOutputColor, color);
128*c8dee2aaSAndroid Build Coastguard Worker             args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
129*c8dee2aaSAndroid Build Coastguard Worker         }
130*c8dee2aaSAndroid Build Coastguard Worker 
131*c8dee2aaSAndroid Build Coastguard Worker         GrGLSLUniformHandler::UniformHandle fColorUniform;
132*c8dee2aaSAndroid Build Coastguard Worker     };
133*c8dee2aaSAndroid Build Coastguard Worker 
134*c8dee2aaSAndroid Build Coastguard Worker     return std::make_unique<Impl>();
135*c8dee2aaSAndroid Build Coastguard Worker }
136*c8dee2aaSAndroid Build Coastguard Worker 
137*c8dee2aaSAndroid Build Coastguard Worker }  // anonymous namespace
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh {
140*c8dee2aaSAndroid Build Coastguard Worker 
visitProxies(const GrVisitProxyFunc & func) const141*c8dee2aaSAndroid Build Coastguard Worker void PathStencilCoverOp::visitProxies(const GrVisitProxyFunc& func) const {
142*c8dee2aaSAndroid Build Coastguard Worker     if (fCoverBBoxProgram) {
143*c8dee2aaSAndroid Build Coastguard Worker         fCoverBBoxProgram->pipeline().visitProxies(func);
144*c8dee2aaSAndroid Build Coastguard Worker     } else {
145*c8dee2aaSAndroid Build Coastguard Worker         fProcessors.visitProxies(func);
146*c8dee2aaSAndroid Build Coastguard Worker     }
147*c8dee2aaSAndroid Build Coastguard Worker }
148*c8dee2aaSAndroid Build Coastguard Worker 
fixedFunctionFlags() const149*c8dee2aaSAndroid Build Coastguard Worker GrDrawOp::FixedFunctionFlags PathStencilCoverOp::fixedFunctionFlags() const {
150*c8dee2aaSAndroid Build Coastguard Worker     auto flags = FixedFunctionFlags::kUsesStencil;
151*c8dee2aaSAndroid Build Coastguard Worker     if (fAAType != GrAAType::kNone) {
152*c8dee2aaSAndroid Build Coastguard Worker         flags |= FixedFunctionFlags::kUsesHWAA;
153*c8dee2aaSAndroid Build Coastguard Worker     }
154*c8dee2aaSAndroid Build Coastguard Worker     return flags;
155*c8dee2aaSAndroid Build Coastguard Worker }
156*c8dee2aaSAndroid Build Coastguard Worker 
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrClampType clampType)157*c8dee2aaSAndroid Build Coastguard Worker GrProcessorSet::Analysis PathStencilCoverOp::finalize(const GrCaps& caps,
158*c8dee2aaSAndroid Build Coastguard Worker                                                       const GrAppliedClip* clip,
159*c8dee2aaSAndroid Build Coastguard Worker                                                       GrClampType clampType) {
160*c8dee2aaSAndroid Build Coastguard Worker     return fProcessors.finalize(fColor, GrProcessorAnalysisCoverage::kNone, clip, nullptr, caps,
161*c8dee2aaSAndroid Build Coastguard Worker                                 clampType, &fColor);
162*c8dee2aaSAndroid Build Coastguard Worker }
163*c8dee2aaSAndroid Build Coastguard Worker 
prePreparePrograms(const GrTessellationShader::ProgramArgs & args,GrAppliedClip && appliedClip)164*c8dee2aaSAndroid Build Coastguard Worker void PathStencilCoverOp::prePreparePrograms(const GrTessellationShader::ProgramArgs& args,
165*c8dee2aaSAndroid Build Coastguard Worker                                             GrAppliedClip&& appliedClip) {
166*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!fTessellator);
167*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!fStencilFanProgram);
168*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!fStencilPathProgram);
169*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!fCoverBBoxProgram);
170*c8dee2aaSAndroid Build Coastguard Worker 
171*c8dee2aaSAndroid Build Coastguard Worker     // We transform paths on the CPU. This allows for better batching.
172*c8dee2aaSAndroid Build Coastguard Worker     const SkMatrix& shaderMatrix = SkMatrix::I();
173*c8dee2aaSAndroid Build Coastguard Worker     auto pipelineFlags = (fPathFlags & FillPathFlags::kWireframe)
174*c8dee2aaSAndroid Build Coastguard Worker             ? GrPipeline::InputFlags::kWireframe
175*c8dee2aaSAndroid Build Coastguard Worker             : GrPipeline::InputFlags::kNone;
176*c8dee2aaSAndroid Build Coastguard Worker     const GrPipeline* stencilPipeline = GrPathTessellationShader::MakeStencilOnlyPipeline(
177*c8dee2aaSAndroid Build Coastguard Worker             args, fAAType, appliedClip.hardClip(), pipelineFlags);
178*c8dee2aaSAndroid Build Coastguard Worker     const GrUserStencilSettings* stencilSettings = GrPathTessellationShader::StencilPathSettings(
179*c8dee2aaSAndroid Build Coastguard Worker                     GrFillRuleForPathFillType(this->pathFillType()));
180*c8dee2aaSAndroid Build Coastguard Worker 
181*c8dee2aaSAndroid Build Coastguard Worker     if (fTotalCombinedPathVerbCnt > 50 &&
182*c8dee2aaSAndroid Build Coastguard Worker         this->bounds().height() * this->bounds().width() > 256 * 256) {
183*c8dee2aaSAndroid Build Coastguard Worker         // Large complex paths do better with a dedicated triangle shader for the inner fan.
184*c8dee2aaSAndroid Build Coastguard Worker         // This takes less PCI bus bandwidth (6 floats per triangle instead of 8) and allows us
185*c8dee2aaSAndroid Build Coastguard Worker         // to make sure it has an efficient middle-out topology.
186*c8dee2aaSAndroid Build Coastguard Worker         auto shader = GrPathTessellationShader::MakeSimpleTriangleShader(args.fArena,
187*c8dee2aaSAndroid Build Coastguard Worker                                                                          shaderMatrix,
188*c8dee2aaSAndroid Build Coastguard Worker                                                                          SK_PMColor4fTRANSPARENT);
189*c8dee2aaSAndroid Build Coastguard Worker         fStencilFanProgram = GrTessellationShader::MakeProgram(args,
190*c8dee2aaSAndroid Build Coastguard Worker                                                                shader,
191*c8dee2aaSAndroid Build Coastguard Worker                                                                stencilPipeline,
192*c8dee2aaSAndroid Build Coastguard Worker                                                                stencilSettings);
193*c8dee2aaSAndroid Build Coastguard Worker         fTessellator = PathCurveTessellator::Make(args.fArena,
194*c8dee2aaSAndroid Build Coastguard Worker                                                   args.fCaps->shaderCaps()->fInfinitySupport);
195*c8dee2aaSAndroid Build Coastguard Worker     } else {
196*c8dee2aaSAndroid Build Coastguard Worker         fTessellator = PathWedgeTessellator::Make(args.fArena,
197*c8dee2aaSAndroid Build Coastguard Worker                                                   args.fCaps->shaderCaps()->fInfinitySupport);
198*c8dee2aaSAndroid Build Coastguard Worker     }
199*c8dee2aaSAndroid Build Coastguard Worker     auto* tessShader = GrPathTessellationShader::Make(*args.fCaps->shaderCaps(),
200*c8dee2aaSAndroid Build Coastguard Worker                                                       args.fArena,
201*c8dee2aaSAndroid Build Coastguard Worker                                                       shaderMatrix,
202*c8dee2aaSAndroid Build Coastguard Worker                                                       SK_PMColor4fTRANSPARENT,
203*c8dee2aaSAndroid Build Coastguard Worker                                                       fTessellator->patchAttribs());
204*c8dee2aaSAndroid Build Coastguard Worker     fStencilPathProgram = GrTessellationShader::MakeProgram(args,
205*c8dee2aaSAndroid Build Coastguard Worker                                                             tessShader,
206*c8dee2aaSAndroid Build Coastguard Worker                                                             stencilPipeline,
207*c8dee2aaSAndroid Build Coastguard Worker                                                             stencilSettings);
208*c8dee2aaSAndroid Build Coastguard Worker 
209*c8dee2aaSAndroid Build Coastguard Worker     if (!(fPathFlags & FillPathFlags::kStencilOnly)) {
210*c8dee2aaSAndroid Build Coastguard Worker         // Create a program that draws a bounding box over the path and fills its stencil coverage
211*c8dee2aaSAndroid Build Coastguard Worker         // into the color buffer.
212*c8dee2aaSAndroid Build Coastguard Worker         auto* bboxShader = args.fArena->make<BoundingBoxShader>(fColor, *args.fCaps->shaderCaps());
213*c8dee2aaSAndroid Build Coastguard Worker         auto* bboxPipeline = GrTessellationShader::MakePipeline(args, fAAType,
214*c8dee2aaSAndroid Build Coastguard Worker                                                                 std::move(appliedClip),
215*c8dee2aaSAndroid Build Coastguard Worker                                                                 std::move(fProcessors));
216*c8dee2aaSAndroid Build Coastguard Worker         auto* bboxStencil = GrPathTessellationShader::TestAndResetStencilSettings(
217*c8dee2aaSAndroid Build Coastguard Worker                 SkPathFillType_IsInverse(this->pathFillType()));
218*c8dee2aaSAndroid Build Coastguard Worker         fCoverBBoxProgram = GrSimpleMeshDrawOpHelper::CreateProgramInfo(
219*c8dee2aaSAndroid Build Coastguard Worker                 args.fCaps,
220*c8dee2aaSAndroid Build Coastguard Worker                 args.fArena,
221*c8dee2aaSAndroid Build Coastguard Worker                 bboxPipeline,
222*c8dee2aaSAndroid Build Coastguard Worker                 args.fWriteView,
223*c8dee2aaSAndroid Build Coastguard Worker                 args.fUsesMSAASurface,
224*c8dee2aaSAndroid Build Coastguard Worker                 bboxShader,
225*c8dee2aaSAndroid Build Coastguard Worker                 GrPrimitiveType::kTriangleStrip,
226*c8dee2aaSAndroid Build Coastguard Worker                 args.fXferBarrierFlags,
227*c8dee2aaSAndroid Build Coastguard Worker                 args.fColorLoadOp,
228*c8dee2aaSAndroid Build Coastguard Worker                 bboxStencil);
229*c8dee2aaSAndroid Build Coastguard Worker     }
230*c8dee2aaSAndroid Build Coastguard Worker }
231*c8dee2aaSAndroid Build Coastguard Worker 
onPrePrepare(GrRecordingContext * context,const GrSurfaceProxyView & writeView,GrAppliedClip * clip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)232*c8dee2aaSAndroid Build Coastguard Worker void PathStencilCoverOp::onPrePrepare(GrRecordingContext* context,
233*c8dee2aaSAndroid Build Coastguard Worker                                       const GrSurfaceProxyView& writeView, GrAppliedClip* clip,
234*c8dee2aaSAndroid Build Coastguard Worker                                       const GrDstProxyView& dstProxyView,
235*c8dee2aaSAndroid Build Coastguard Worker                                       GrXferBarrierFlags renderPassXferBarriers,
236*c8dee2aaSAndroid Build Coastguard Worker                                       GrLoadOp colorLoadOp) {
237*c8dee2aaSAndroid Build Coastguard Worker     // DMSAA is not supported on DDL.
238*c8dee2aaSAndroid Build Coastguard Worker     bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1;
239*c8dee2aaSAndroid Build Coastguard Worker     this->prePreparePrograms({context->priv().recordTimeAllocator(), writeView, usesMSAASurface,
240*c8dee2aaSAndroid Build Coastguard Worker                              &dstProxyView, renderPassXferBarriers, colorLoadOp,
241*c8dee2aaSAndroid Build Coastguard Worker                              context->priv().caps()},
242*c8dee2aaSAndroid Build Coastguard Worker                              (clip) ? std::move(*clip) : GrAppliedClip::Disabled());
243*c8dee2aaSAndroid Build Coastguard Worker     if (fStencilFanProgram) {
244*c8dee2aaSAndroid Build Coastguard Worker         context->priv().recordProgramInfo(fStencilFanProgram);
245*c8dee2aaSAndroid Build Coastguard Worker     }
246*c8dee2aaSAndroid Build Coastguard Worker     if (fStencilPathProgram) {
247*c8dee2aaSAndroid Build Coastguard Worker         context->priv().recordProgramInfo(fStencilPathProgram);
248*c8dee2aaSAndroid Build Coastguard Worker     }
249*c8dee2aaSAndroid Build Coastguard Worker     if (fCoverBBoxProgram) {
250*c8dee2aaSAndroid Build Coastguard Worker         context->priv().recordProgramInfo(fCoverBBoxProgram);
251*c8dee2aaSAndroid Build Coastguard Worker     }
252*c8dee2aaSAndroid Build Coastguard Worker }
253*c8dee2aaSAndroid Build Coastguard Worker 
254*c8dee2aaSAndroid Build Coastguard Worker SKGPU_DECLARE_STATIC_UNIQUE_KEY(gUnitQuadBufferKey);
255*c8dee2aaSAndroid Build Coastguard Worker 
onPrepare(GrOpFlushState * flushState)256*c8dee2aaSAndroid Build Coastguard Worker void PathStencilCoverOp::onPrepare(GrOpFlushState* flushState) {
257*c8dee2aaSAndroid Build Coastguard Worker     if (!fTessellator) {
258*c8dee2aaSAndroid Build Coastguard Worker         this->prePreparePrograms({flushState->allocator(), flushState->writeView(),
259*c8dee2aaSAndroid Build Coastguard Worker                                  flushState->usesMSAASurface(), &flushState->dstProxyView(),
260*c8dee2aaSAndroid Build Coastguard Worker                                  flushState->renderPassBarriers(), flushState->colorLoadOp(),
261*c8dee2aaSAndroid Build Coastguard Worker                                  &flushState->caps()}, flushState->detachAppliedClip());
262*c8dee2aaSAndroid Build Coastguard Worker         if (!fTessellator) {
263*c8dee2aaSAndroid Build Coastguard Worker             return;
264*c8dee2aaSAndroid Build Coastguard Worker         }
265*c8dee2aaSAndroid Build Coastguard Worker     }
266*c8dee2aaSAndroid Build Coastguard Worker 
267*c8dee2aaSAndroid Build Coastguard Worker     if (fStencilFanProgram) {
268*c8dee2aaSAndroid Build Coastguard Worker         // The inner fan isn't built into the tessellator. Generate a standard Redbook fan with a
269*c8dee2aaSAndroid Build Coastguard Worker         // middle-out topology.
270*c8dee2aaSAndroid Build Coastguard Worker         GrEagerDynamicVertexAllocator vertexAlloc(flushState, &fFanBuffer, &fFanBaseVertex);
271*c8dee2aaSAndroid Build Coastguard Worker         // Path fans might have an extra edge from an implicit kClose at the end, but they also
272*c8dee2aaSAndroid Build Coastguard Worker         // always begin with kMove. So the max possible number of edges in a single path is equal to
273*c8dee2aaSAndroid Build Coastguard Worker         // the number of verbs. Therefore, the max number of combined fan edges in a path list is
274*c8dee2aaSAndroid Build Coastguard Worker         // the number of combined verbs from the paths in the list.
275*c8dee2aaSAndroid Build Coastguard Worker         // A single n-sided polygon is fanned by n-2 triangles. Multiple polygons with a combined
276*c8dee2aaSAndroid Build Coastguard Worker         // edge count of n are fanned by strictly fewer triangles.
277*c8dee2aaSAndroid Build Coastguard Worker         int maxTrianglesInFans = std::max(fTotalCombinedPathVerbCnt - 2, 0);
278*c8dee2aaSAndroid Build Coastguard Worker         int fanTriangleCount = 0;
279*c8dee2aaSAndroid Build Coastguard Worker         if (VertexWriter triangleVertexWriter =
280*c8dee2aaSAndroid Build Coastguard Worker                     vertexAlloc.lockWriter(sizeof(SkPoint), maxTrianglesInFans * 3)) {
281*c8dee2aaSAndroid Build Coastguard Worker             for (auto [pathMatrix, path, color] : *fPathDrawList) {
282*c8dee2aaSAndroid Build Coastguard Worker                 tess::AffineMatrix m(pathMatrix);
283*c8dee2aaSAndroid Build Coastguard Worker                 for (tess::PathMiddleOutFanIter it(path); !it.done();) {
284*c8dee2aaSAndroid Build Coastguard Worker                     for (auto [p0, p1, p2] : it.nextStack()) {
285*c8dee2aaSAndroid Build Coastguard Worker                         triangleVertexWriter << m.map2Points(p0, p1) << m.mapPoint(p2);
286*c8dee2aaSAndroid Build Coastguard Worker                         ++fanTriangleCount;
287*c8dee2aaSAndroid Build Coastguard Worker                     }
288*c8dee2aaSAndroid Build Coastguard Worker                 }
289*c8dee2aaSAndroid Build Coastguard Worker             }
290*c8dee2aaSAndroid Build Coastguard Worker 
291*c8dee2aaSAndroid Build Coastguard Worker 
292*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fanTriangleCount <= maxTrianglesInFans);
293*c8dee2aaSAndroid Build Coastguard Worker             fFanVertexCount = fanTriangleCount * 3;
294*c8dee2aaSAndroid Build Coastguard Worker             vertexAlloc.unlock(fFanVertexCount);
295*c8dee2aaSAndroid Build Coastguard Worker         }
296*c8dee2aaSAndroid Build Coastguard Worker     }
297*c8dee2aaSAndroid Build Coastguard Worker 
298*c8dee2aaSAndroid Build Coastguard Worker     auto tessShader = &fStencilPathProgram->geomProc().cast<GrPathTessellationShader>();
299*c8dee2aaSAndroid Build Coastguard Worker     fTessellator->prepare(flushState,
300*c8dee2aaSAndroid Build Coastguard Worker                           tessShader->viewMatrix(),
301*c8dee2aaSAndroid Build Coastguard Worker                           *fPathDrawList,
302*c8dee2aaSAndroid Build Coastguard Worker                           fTotalCombinedPathVerbCnt);
303*c8dee2aaSAndroid Build Coastguard Worker 
304*c8dee2aaSAndroid Build Coastguard Worker     if (fCoverBBoxProgram) {
305*c8dee2aaSAndroid Build Coastguard Worker         size_t instanceStride = fCoverBBoxProgram->geomProc().instanceStride();
306*c8dee2aaSAndroid Build Coastguard Worker         VertexWriter vertexWriter = flushState->makeVertexWriter(instanceStride,
307*c8dee2aaSAndroid Build Coastguard Worker                                                                  fPathCount,
308*c8dee2aaSAndroid Build Coastguard Worker                                                                  &fBBoxBuffer,
309*c8dee2aaSAndroid Build Coastguard Worker                                                                  &fBBoxBaseInstance);
310*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGCODE(int pathCount = 0;)
311*c8dee2aaSAndroid Build Coastguard Worker         for (auto [pathMatrix, path, color] : *fPathDrawList) {
312*c8dee2aaSAndroid Build Coastguard Worker             SkDEBUGCODE(auto end = vertexWriter.mark(instanceStride));
313*c8dee2aaSAndroid Build Coastguard Worker             vertexWriter << pathMatrix.getScaleX()
314*c8dee2aaSAndroid Build Coastguard Worker                          << pathMatrix.getSkewY()
315*c8dee2aaSAndroid Build Coastguard Worker                          << pathMatrix.getSkewX()
316*c8dee2aaSAndroid Build Coastguard Worker                          << pathMatrix.getScaleY()
317*c8dee2aaSAndroid Build Coastguard Worker                          << pathMatrix.getTranslateX()
318*c8dee2aaSAndroid Build Coastguard Worker                          << pathMatrix.getTranslateY();
319*c8dee2aaSAndroid Build Coastguard Worker             if (path.isInverseFillType()) {
320*c8dee2aaSAndroid Build Coastguard Worker                 // Fill the entire backing store to make sure we clear every stencil value back to
321*c8dee2aaSAndroid Build Coastguard Worker                 // 0. If there is a scissor it will have already clipped the stencil draw.
322*c8dee2aaSAndroid Build Coastguard Worker                 auto rtBounds =
323*c8dee2aaSAndroid Build Coastguard Worker                         flushState->writeView().asRenderTargetProxy()->backingStoreBoundsRect();
324*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(rtBounds == fOriginalDrawBounds);
325*c8dee2aaSAndroid Build Coastguard Worker                 SkRect pathSpaceRTBounds;
326*c8dee2aaSAndroid Build Coastguard Worker                 if (SkMatrixPriv::InverseMapRect(pathMatrix, &pathSpaceRTBounds, rtBounds)) {
327*c8dee2aaSAndroid Build Coastguard Worker                     vertexWriter << pathSpaceRTBounds;
328*c8dee2aaSAndroid Build Coastguard Worker                 } else {
329*c8dee2aaSAndroid Build Coastguard Worker                     vertexWriter << path.getBounds();
330*c8dee2aaSAndroid Build Coastguard Worker                 }
331*c8dee2aaSAndroid Build Coastguard Worker             } else {
332*c8dee2aaSAndroid Build Coastguard Worker                 vertexWriter << path.getBounds();
333*c8dee2aaSAndroid Build Coastguard Worker             }
334*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(vertexWriter.mark() == end);
335*c8dee2aaSAndroid Build Coastguard Worker             SkDEBUGCODE(++pathCount;)
336*c8dee2aaSAndroid Build Coastguard Worker         }
337*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(pathCount == fPathCount);
338*c8dee2aaSAndroid Build Coastguard Worker     }
339*c8dee2aaSAndroid Build Coastguard Worker 
340*c8dee2aaSAndroid Build Coastguard Worker     if (!flushState->caps().shaderCaps()->fVertexIDSupport) {
341*c8dee2aaSAndroid Build Coastguard Worker         constexpr static SkPoint kUnitQuad[4] = {{0,0}, {0,1}, {1,0}, {1,1}};
342*c8dee2aaSAndroid Build Coastguard Worker 
343*c8dee2aaSAndroid Build Coastguard Worker         SKGPU_DEFINE_STATIC_UNIQUE_KEY(gUnitQuadBufferKey);
344*c8dee2aaSAndroid Build Coastguard Worker 
345*c8dee2aaSAndroid Build Coastguard Worker         fBBoxVertexBufferIfNoIDSupport = flushState->resourceProvider()->findOrMakeStaticBuffer(
346*c8dee2aaSAndroid Build Coastguard Worker                 GrGpuBufferType::kVertex, sizeof(kUnitQuad), kUnitQuad, gUnitQuadBufferKey);
347*c8dee2aaSAndroid Build Coastguard Worker     }
348*c8dee2aaSAndroid Build Coastguard Worker }
349*c8dee2aaSAndroid Build Coastguard Worker 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)350*c8dee2aaSAndroid Build Coastguard Worker void PathStencilCoverOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
351*c8dee2aaSAndroid Build Coastguard Worker     if (!fTessellator) {
352*c8dee2aaSAndroid Build Coastguard Worker         return;
353*c8dee2aaSAndroid Build Coastguard Worker     }
354*c8dee2aaSAndroid Build Coastguard Worker 
355*c8dee2aaSAndroid Build Coastguard Worker     if (fCoverBBoxProgram &&
356*c8dee2aaSAndroid Build Coastguard Worker         fCoverBBoxProgram->geomProc().hasVertexAttributes() &&
357*c8dee2aaSAndroid Build Coastguard Worker         !fBBoxVertexBufferIfNoIDSupport) {
358*c8dee2aaSAndroid Build Coastguard Worker         return;
359*c8dee2aaSAndroid Build Coastguard Worker     }
360*c8dee2aaSAndroid Build Coastguard Worker 
361*c8dee2aaSAndroid Build Coastguard Worker     // Stencil the inner fan, if any.
362*c8dee2aaSAndroid Build Coastguard Worker     if (fFanVertexCount > 0) {
363*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fStencilFanProgram);
364*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fFanBuffer);
365*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindPipelineAndScissorClip(*fStencilFanProgram, this->bounds());
366*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindBuffers(nullptr, nullptr, fFanBuffer);
367*c8dee2aaSAndroid Build Coastguard Worker         flushState->draw(fFanVertexCount, fFanBaseVertex);
368*c8dee2aaSAndroid Build Coastguard Worker     }
369*c8dee2aaSAndroid Build Coastguard Worker 
370*c8dee2aaSAndroid Build Coastguard Worker     // Stencil the rest of the path.
371*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fStencilPathProgram);
372*c8dee2aaSAndroid Build Coastguard Worker     flushState->bindPipelineAndScissorClip(*fStencilPathProgram, this->bounds());
373*c8dee2aaSAndroid Build Coastguard Worker     fTessellator->draw(flushState);
374*c8dee2aaSAndroid Build Coastguard Worker 
375*c8dee2aaSAndroid Build Coastguard Worker     // Fill in the bounding box (if not in stencil-only mode).
376*c8dee2aaSAndroid Build Coastguard Worker     if (fCoverBBoxProgram) {
377*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindPipelineAndScissorClip(*fCoverBBoxProgram, this->bounds());
378*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindTextures(fCoverBBoxProgram->geomProc(), nullptr,
379*c8dee2aaSAndroid Build Coastguard Worker                                  fCoverBBoxProgram->pipeline());
380*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindBuffers(nullptr, fBBoxBuffer, fBBoxVertexBufferIfNoIDSupport);
381*c8dee2aaSAndroid Build Coastguard Worker         flushState->drawInstanced(fPathCount, fBBoxBaseInstance, 4, 0);
382*c8dee2aaSAndroid Build Coastguard Worker     }
383*c8dee2aaSAndroid Build Coastguard Worker }
384*c8dee2aaSAndroid Build Coastguard Worker 
385*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu::ganesh
386