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