xref: /aosp_15_r20/external/skia/src/gpu/graphite/render/TessellateWedgesRenderStep.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2022 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/graphite/render/TessellateWedgesRenderStep.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathTypes.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkPoint_impl.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkSpan_impl.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkSLTypeShared.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/BufferWriter.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Attribute.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/BufferManager.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawOrder.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawParams.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawTypes.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PipelineData.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/Geometry.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/Shape.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/Transform_graphite.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/render/DynamicInstancesPatchAllocator.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/tessellate/FixedCountBufferUtils.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/tessellate/MidpointContourParser.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/tessellate/PatchWriter.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/tessellate/Tessellation.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/tessellate/WangsFormula.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLString.h"
34*c8dee2aaSAndroid Build Coastguard Worker 
35*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
38*c8dee2aaSAndroid Build Coastguard Worker 
39*c8dee2aaSAndroid Build Coastguard Worker namespace {
40*c8dee2aaSAndroid Build Coastguard Worker 
41*c8dee2aaSAndroid Build Coastguard Worker using namespace skgpu::tess;
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker // Only kFanPoint, no stroke params, since this is for filled wedges.
44*c8dee2aaSAndroid Build Coastguard Worker // No color or wide color attribs, since it might always be part of the PaintParams
45*c8dee2aaSAndroid Build Coastguard Worker // or we'll add a color-only fast path to RenderStep later.
46*c8dee2aaSAndroid Build Coastguard Worker // No explicit curve type on platforms that support infinity.
47*c8dee2aaSAndroid Build Coastguard Worker static constexpr PatchAttribs kAttribs = PatchAttribs::kFanPoint |
48*c8dee2aaSAndroid Build Coastguard Worker                                          PatchAttribs::kPaintDepth |
49*c8dee2aaSAndroid Build Coastguard Worker                                          PatchAttribs::kSsboIndex;
50*c8dee2aaSAndroid Build Coastguard Worker static constexpr PatchAttribs kAttribsWithCurveType = kAttribs | PatchAttribs::kExplicitCurveType;
51*c8dee2aaSAndroid Build Coastguard Worker 
52*c8dee2aaSAndroid Build Coastguard Worker using Writer = PatchWriter<DynamicInstancesPatchAllocator<FixedCountWedges>,
53*c8dee2aaSAndroid Build Coastguard Worker                            Required<PatchAttribs::kFanPoint>,
54*c8dee2aaSAndroid Build Coastguard Worker                            Required<PatchAttribs::kPaintDepth>,
55*c8dee2aaSAndroid Build Coastguard Worker                            Required<PatchAttribs::kSsboIndex>,
56*c8dee2aaSAndroid Build Coastguard Worker                            Optional<PatchAttribs::kExplicitCurveType>>;
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker // The order of the attribute declarations must match the order used by
59*c8dee2aaSAndroid Build Coastguard Worker // PatchWriter::emitPatchAttribs, i.e.:
60*c8dee2aaSAndroid Build Coastguard Worker //     join << fanPoint << stroke << color << depth << curveType << ssboIndices
61*c8dee2aaSAndroid Build Coastguard Worker static constexpr Attribute kBaseAttributes[] = {
62*c8dee2aaSAndroid Build Coastguard Worker         {"p01", VertexAttribType::kFloat4, SkSLType::kFloat4},
63*c8dee2aaSAndroid Build Coastguard Worker         {"p23", VertexAttribType::kFloat4, SkSLType::kFloat4},
64*c8dee2aaSAndroid Build Coastguard Worker         {"fanPointAttrib", VertexAttribType::kFloat2, SkSLType::kFloat2},
65*c8dee2aaSAndroid Build Coastguard Worker         {"depth", VertexAttribType::kFloat, SkSLType::kFloat},
66*c8dee2aaSAndroid Build Coastguard Worker         {"ssboIndices", VertexAttribType::kUInt2, SkSLType::kUInt2}};
67*c8dee2aaSAndroid Build Coastguard Worker 
68*c8dee2aaSAndroid Build Coastguard Worker static constexpr Attribute kAttributesWithCurveType[] = {
69*c8dee2aaSAndroid Build Coastguard Worker         {"p01", VertexAttribType::kFloat4, SkSLType::kFloat4},
70*c8dee2aaSAndroid Build Coastguard Worker         {"p23", VertexAttribType::kFloat4, SkSLType::kFloat4},
71*c8dee2aaSAndroid Build Coastguard Worker         {"fanPointAttrib", VertexAttribType::kFloat2, SkSLType::kFloat2},
72*c8dee2aaSAndroid Build Coastguard Worker         {"depth", VertexAttribType::kFloat, SkSLType::kFloat},
73*c8dee2aaSAndroid Build Coastguard Worker         {"curveType", VertexAttribType::kFloat, SkSLType::kFloat},
74*c8dee2aaSAndroid Build Coastguard Worker         {"ssboIndices", VertexAttribType::kUInt2, SkSLType::kUInt2}};
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkSpan<const Attribute> kAttributes[2] = {kAttributesWithCurveType,
77*c8dee2aaSAndroid Build Coastguard Worker                                                            kBaseAttributes};
78*c8dee2aaSAndroid Build Coastguard Worker 
79*c8dee2aaSAndroid Build Coastguard Worker }  // namespace
80*c8dee2aaSAndroid Build Coastguard Worker 
TessellateWedgesRenderStep(std::string_view variantName,bool infinitySupport,DepthStencilSettings depthStencilSettings,StaticBufferManager * bufferManager)81*c8dee2aaSAndroid Build Coastguard Worker TessellateWedgesRenderStep::TessellateWedgesRenderStep(std::string_view variantName,
82*c8dee2aaSAndroid Build Coastguard Worker                                                        bool infinitySupport,
83*c8dee2aaSAndroid Build Coastguard Worker                                                        DepthStencilSettings depthStencilSettings,
84*c8dee2aaSAndroid Build Coastguard Worker                                                        StaticBufferManager* bufferManager)
85*c8dee2aaSAndroid Build Coastguard Worker         : RenderStep("TessellateWedgesRenderStep",
86*c8dee2aaSAndroid Build Coastguard Worker                      variantName,
87*c8dee2aaSAndroid Build Coastguard Worker                      Flags::kRequiresMSAA |
88*c8dee2aaSAndroid Build Coastguard Worker                      (depthStencilSettings.fDepthWriteEnabled ? Flags::kPerformsShading
89*c8dee2aaSAndroid Build Coastguard Worker                                                               : Flags::kNone),
90*c8dee2aaSAndroid Build Coastguard Worker                      /*uniforms=*/{{"localToDevice", SkSLType::kFloat4x4}},
91*c8dee2aaSAndroid Build Coastguard Worker                      PrimitiveType::kTriangles,
92*c8dee2aaSAndroid Build Coastguard Worker                      depthStencilSettings,
93*c8dee2aaSAndroid Build Coastguard Worker                      /*vertexAttrs=*/  {{"resolveLevel_and_idx",
94*c8dee2aaSAndroid Build Coastguard Worker                                          VertexAttribType::kFloat2, SkSLType::kFloat2}},
95*c8dee2aaSAndroid Build Coastguard Worker                      /*instanceAttrs=*/kAttributes[infinitySupport])
96*c8dee2aaSAndroid Build Coastguard Worker         , fInfinitySupport(infinitySupport) {
97*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(this->instanceStride() ==
98*c8dee2aaSAndroid Build Coastguard Worker              PatchStride(infinitySupport ? kAttribs : kAttribsWithCurveType));
99*c8dee2aaSAndroid Build Coastguard Worker 
100*c8dee2aaSAndroid Build Coastguard Worker     // Initialize the static buffers we'll use when recording draw calls.
101*c8dee2aaSAndroid Build Coastguard Worker     // NOTE: Each instance of this RenderStep gets its own copy of the data. If this ends up causing
102*c8dee2aaSAndroid Build Coastguard Worker     // problems, we can modify StaticBufferManager to de-duplicate requests.
103*c8dee2aaSAndroid Build Coastguard Worker     const size_t vertexSize = FixedCountWedges::VertexBufferSize();
104*c8dee2aaSAndroid Build Coastguard Worker     auto vertexData = bufferManager->getVertexWriter(vertexSize, &fVertexBuffer);
105*c8dee2aaSAndroid Build Coastguard Worker     if (vertexData) {
106*c8dee2aaSAndroid Build Coastguard Worker         FixedCountWedges::WriteVertexBuffer(std::move(vertexData), vertexSize);
107*c8dee2aaSAndroid Build Coastguard Worker     } // otherwise static buffer creation failed, so do nothing; Context initialization will fail.
108*c8dee2aaSAndroid Build Coastguard Worker 
109*c8dee2aaSAndroid Build Coastguard Worker     const size_t indexSize = FixedCountWedges::IndexBufferSize();
110*c8dee2aaSAndroid Build Coastguard Worker     auto indexData = bufferManager->getIndexWriter(indexSize, &fIndexBuffer);
111*c8dee2aaSAndroid Build Coastguard Worker     if (indexData) {
112*c8dee2aaSAndroid Build Coastguard Worker         FixedCountWedges::WriteIndexBuffer(std::move(indexData), indexSize);
113*c8dee2aaSAndroid Build Coastguard Worker     } // otherwise static buffer creation failed, so do nothing; Context initialization will fail.
114*c8dee2aaSAndroid Build Coastguard Worker }
115*c8dee2aaSAndroid Build Coastguard Worker 
~TessellateWedgesRenderStep()116*c8dee2aaSAndroid Build Coastguard Worker TessellateWedgesRenderStep::~TessellateWedgesRenderStep() {}
117*c8dee2aaSAndroid Build Coastguard Worker 
vertexSkSL() const118*c8dee2aaSAndroid Build Coastguard Worker std::string TessellateWedgesRenderStep::vertexSkSL() const {
119*c8dee2aaSAndroid Build Coastguard Worker     return SkSL::String::printf(
120*c8dee2aaSAndroid Build Coastguard Worker             R"(
121*c8dee2aaSAndroid Build Coastguard Worker                 float2 localCoord;
122*c8dee2aaSAndroid Build Coastguard Worker                 if (resolveLevel_and_idx.x < 0) {
123*c8dee2aaSAndroid Build Coastguard Worker                     // A negative resolve level means this is the fan point.
124*c8dee2aaSAndroid Build Coastguard Worker                     localCoord = fanPointAttrib;
125*c8dee2aaSAndroid Build Coastguard Worker                 } else {
126*c8dee2aaSAndroid Build Coastguard Worker                     // TODO: Approximate perspective scaling to match how PatchWriter is configured
127*c8dee2aaSAndroid Build Coastguard Worker                     // (or provide explicit tessellation level in instance data instead of
128*c8dee2aaSAndroid Build Coastguard Worker                     // replicating work)
129*c8dee2aaSAndroid Build Coastguard Worker                     float2x2 vectorXform = float2x2(localToDevice[0].xy, localToDevice[1].xy);
130*c8dee2aaSAndroid Build Coastguard Worker                     localCoord = tessellate_filled_curve(
131*c8dee2aaSAndroid Build Coastguard Worker                         vectorXform, resolveLevel_and_idx.x, resolveLevel_and_idx.y, p01, p23, %s);
132*c8dee2aaSAndroid Build Coastguard Worker                 }
133*c8dee2aaSAndroid Build Coastguard Worker                 float4 devPosition = localToDevice * float4(localCoord, 0.0, 1.0);
134*c8dee2aaSAndroid Build Coastguard Worker                 devPosition.z = depth;
135*c8dee2aaSAndroid Build Coastguard Worker                 stepLocalCoords = localCoord;
136*c8dee2aaSAndroid Build Coastguard Worker             )",
137*c8dee2aaSAndroid Build Coastguard Worker             fInfinitySupport ? "curve_type_using_inf_support(p23)" : "curveType");
138*c8dee2aaSAndroid Build Coastguard Worker }
139*c8dee2aaSAndroid Build Coastguard Worker 
writeVertices(DrawWriter * dw,const DrawParams & params,skvx::uint2 ssboIndices) const140*c8dee2aaSAndroid Build Coastguard Worker void TessellateWedgesRenderStep::writeVertices(DrawWriter* dw,
141*c8dee2aaSAndroid Build Coastguard Worker                                                const DrawParams& params,
142*c8dee2aaSAndroid Build Coastguard Worker                                                skvx::uint2 ssboIndices) const {
143*c8dee2aaSAndroid Build Coastguard Worker     SkPath path = params.geometry().shape().asPath(); // TODO: Iterate the Shape directly
144*c8dee2aaSAndroid Build Coastguard Worker 
145*c8dee2aaSAndroid Build Coastguard Worker     int patchReserveCount = FixedCountWedges::PreallocCount(path.countVerbs());
146*c8dee2aaSAndroid Build Coastguard Worker     Writer writer{fInfinitySupport ? kAttribs : kAttribsWithCurveType,
147*c8dee2aaSAndroid Build Coastguard Worker                   *dw,
148*c8dee2aaSAndroid Build Coastguard Worker                   fVertexBuffer,
149*c8dee2aaSAndroid Build Coastguard Worker                   fIndexBuffer,
150*c8dee2aaSAndroid Build Coastguard Worker                   patchReserveCount};
151*c8dee2aaSAndroid Build Coastguard Worker     writer.updatePaintDepthAttrib(params.order().depthAsFloat());
152*c8dee2aaSAndroid Build Coastguard Worker     writer.updateSsboIndexAttrib(ssboIndices);
153*c8dee2aaSAndroid Build Coastguard Worker 
154*c8dee2aaSAndroid Build Coastguard Worker     // The vector xform approximates how the control points are transformed by the shader to
155*c8dee2aaSAndroid Build Coastguard Worker     // more accurately compute how many *parametric* segments are needed.
156*c8dee2aaSAndroid Build Coastguard Worker     // TODO: This doesn't account for perspective division yet, which will require updating the
157*c8dee2aaSAndroid Build Coastguard Worker     // approximate transform based on each verb's control points' bounding box.
158*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(params.transform().type() < Transform::Type::kPerspective);
159*c8dee2aaSAndroid Build Coastguard Worker     writer.setShaderTransform(wangs_formula::VectorXform{params.transform().matrix()},
160*c8dee2aaSAndroid Build Coastguard Worker                               params.transform().maxScaleFactor());
161*c8dee2aaSAndroid Build Coastguard Worker 
162*c8dee2aaSAndroid Build Coastguard Worker     // TODO: Essentially the same as PathWedgeTessellator::write_patches but with a different
163*c8dee2aaSAndroid Build Coastguard Worker     // PatchWriter template.
164*c8dee2aaSAndroid Build Coastguard Worker     // For wedges, we iterate over each contour explicitly, using a fan point position that is in
165*c8dee2aaSAndroid Build Coastguard Worker     // the midpoint of the current contour.
166*c8dee2aaSAndroid Build Coastguard Worker     MidpointContourParser parser{path};
167*c8dee2aaSAndroid Build Coastguard Worker     while (parser.parseNextContour()) {
168*c8dee2aaSAndroid Build Coastguard Worker         writer.updateFanPointAttrib(parser.currentMidpoint());
169*c8dee2aaSAndroid Build Coastguard Worker         SkPoint lastPoint = {0, 0};
170*c8dee2aaSAndroid Build Coastguard Worker         SkPoint startPoint = {0, 0};
171*c8dee2aaSAndroid Build Coastguard Worker         for (auto [verb, pts, w] : parser.currentContour()) {
172*c8dee2aaSAndroid Build Coastguard Worker             switch (verb) {
173*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kMove:
174*c8dee2aaSAndroid Build Coastguard Worker                     startPoint = lastPoint = pts[0];
175*c8dee2aaSAndroid Build Coastguard Worker                     break;
176*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kLine:
177*c8dee2aaSAndroid Build Coastguard Worker                     // Unlike curve tessellation, wedges have to handle lines as part of the patch,
178*c8dee2aaSAndroid Build Coastguard Worker                     // effectively forming a single triangle with the fan point.
179*c8dee2aaSAndroid Build Coastguard Worker                     writer.writeLine(pts[0], pts[1]);
180*c8dee2aaSAndroid Build Coastguard Worker                     lastPoint = pts[1];
181*c8dee2aaSAndroid Build Coastguard Worker                     break;
182*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kQuad:
183*c8dee2aaSAndroid Build Coastguard Worker                     writer.writeQuadratic(pts);
184*c8dee2aaSAndroid Build Coastguard Worker                     lastPoint = pts[2];
185*c8dee2aaSAndroid Build Coastguard Worker                     break;
186*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kConic:
187*c8dee2aaSAndroid Build Coastguard Worker                     writer.writeConic(pts, *w);
188*c8dee2aaSAndroid Build Coastguard Worker                     lastPoint = pts[2];
189*c8dee2aaSAndroid Build Coastguard Worker                     break;
190*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kCubic:
191*c8dee2aaSAndroid Build Coastguard Worker                     writer.writeCubic(pts);
192*c8dee2aaSAndroid Build Coastguard Worker                     lastPoint = pts[3];
193*c8dee2aaSAndroid Build Coastguard Worker                     break;
194*c8dee2aaSAndroid Build Coastguard Worker                 default: break;
195*c8dee2aaSAndroid Build Coastguard Worker             }
196*c8dee2aaSAndroid Build Coastguard Worker         }
197*c8dee2aaSAndroid Build Coastguard Worker 
198*c8dee2aaSAndroid Build Coastguard Worker         // Explicitly close the contour with another line segment, which also differs from curve
199*c8dee2aaSAndroid Build Coastguard Worker         // tessellation since that approach's triangle step automatically closes the contour.
200*c8dee2aaSAndroid Build Coastguard Worker         if (lastPoint != startPoint) {
201*c8dee2aaSAndroid Build Coastguard Worker             writer.writeLine(lastPoint, startPoint);
202*c8dee2aaSAndroid Build Coastguard Worker         }
203*c8dee2aaSAndroid Build Coastguard Worker     }
204*c8dee2aaSAndroid Build Coastguard Worker }
205*c8dee2aaSAndroid Build Coastguard Worker 
writeUniformsAndTextures(const DrawParams & params,PipelineDataGatherer * gatherer) const206*c8dee2aaSAndroid Build Coastguard Worker void TessellateWedgesRenderStep::writeUniformsAndTextures(const DrawParams& params,
207*c8dee2aaSAndroid Build Coastguard Worker                                                           PipelineDataGatherer* gatherer) const {
208*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, this->uniforms());)
209*c8dee2aaSAndroid Build Coastguard Worker 
210*c8dee2aaSAndroid Build Coastguard Worker     gatherer->write(params.transform().matrix());
211*c8dee2aaSAndroid Build Coastguard Worker }
212*c8dee2aaSAndroid Build Coastguard Worker 
213*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu::graphite
214