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