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