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.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(RenderStepID renderStepID,bool infinitySupport,DepthStencilSettings depthStencilSettings,StaticBufferManager * bufferManager)81 TessellateWedgesRenderStep::TessellateWedgesRenderStep(RenderStepID renderStepID,
82 bool infinitySupport,
83 DepthStencilSettings depthStencilSettings,
84 StaticBufferManager* bufferManager)
85 : RenderStep(renderStepID,
86 Flags::kRequiresMSAA |
87 (depthStencilSettings.fDepthWriteEnabled ? Flags::kPerformsShading
88 : Flags::kNone),
89 /*uniforms=*/{{"localToDevice", SkSLType::kFloat4x4}},
90 PrimitiveType::kTriangles,
91 depthStencilSettings,
92 /*vertexAttrs=*/ {{"resolveLevel_and_idx",
93 VertexAttribType::kFloat2, SkSLType::kFloat2}},
94 /*instanceAttrs=*/kAttributes[infinitySupport])
95 , fInfinitySupport(infinitySupport) {
96 SkASSERT(this->instanceStride() ==
97 PatchStride(infinitySupport ? kAttribs : kAttribsWithCurveType));
98
99 // Initialize the static buffers we'll use when recording draw calls.
100 // NOTE: Each instance of this RenderStep gets its own copy of the data. If this ends up causing
101 // problems, we can modify StaticBufferManager to de-duplicate requests.
102 const size_t vertexSize = FixedCountWedges::VertexBufferSize();
103 auto vertexData = bufferManager->getVertexWriter(vertexSize, &fVertexBuffer);
104 if (vertexData) {
105 FixedCountWedges::WriteVertexBuffer(std::move(vertexData), vertexSize);
106 } // otherwise static buffer creation failed, so do nothing; Context initialization will fail.
107
108 const size_t indexSize = FixedCountWedges::IndexBufferSize();
109 auto indexData = bufferManager->getIndexWriter(indexSize, &fIndexBuffer);
110 if (indexData) {
111 FixedCountWedges::WriteIndexBuffer(std::move(indexData), indexSize);
112 } // otherwise static buffer creation failed, so do nothing; Context initialization will fail.
113 }
114
~TessellateWedgesRenderStep()115 TessellateWedgesRenderStep::~TessellateWedgesRenderStep() {}
116
vertexSkSL() const117 std::string TessellateWedgesRenderStep::vertexSkSL() const {
118 return SkSL::String::printf(
119 "float2 localCoord;\n"
120 "if (resolveLevel_and_idx.x < 0) {\n"
121 // A negative resolve level means this is the fan point.
122 "localCoord = fanPointAttrib;\n"
123 "} else {\n"
124 // TODO: Approximate perspective scaling to match how PatchWriter is configured
125 // (or provide explicit tessellation level in instance data instead of
126 // replicating work)
127 "float2x2 vectorXform = float2x2(localToDevice[0].xy, localToDevice[1].xy);\n"
128 "localCoord = tessellate_filled_curve("
129 "vectorXform, resolveLevel_and_idx.x, resolveLevel_and_idx.y, p01, p23, %s);\n"
130 "}\n"
131 "float4 devPosition = localToDevice * float4(localCoord, 0.0, 1.0);\n"
132 "devPosition.z = depth;\n"
133 "stepLocalCoords = localCoord;\n",
134 fInfinitySupport ? "curve_type_using_inf_support(p23)" : "curveType");
135 }
136
writeVertices(DrawWriter * dw,const DrawParams & params,skvx::uint2 ssboIndices) const137 void TessellateWedgesRenderStep::writeVertices(DrawWriter* dw,
138 const DrawParams& params,
139 skvx::uint2 ssboIndices) const {
140 SkPath path = params.geometry().shape().asPath(); // TODO: Iterate the Shape directly
141
142 int patchReserveCount = FixedCountWedges::PreallocCount(path.countVerbs());
143 Writer writer{fInfinitySupport ? kAttribs : kAttribsWithCurveType,
144 *dw,
145 fVertexBuffer,
146 fIndexBuffer,
147 patchReserveCount};
148 writer.updatePaintDepthAttrib(params.order().depthAsFloat());
149 writer.updateSsboIndexAttrib(ssboIndices);
150
151 // The vector xform approximates how the control points are transformed by the shader to
152 // more accurately compute how many *parametric* segments are needed.
153 // TODO: This doesn't account for perspective division yet, which will require updating the
154 // approximate transform based on each verb's control points' bounding box.
155 SkASSERT(params.transform().type() < Transform::Type::kPerspective);
156 writer.setShaderTransform(wangs_formula::VectorXform{params.transform().matrix()},
157 params.transform().maxScaleFactor());
158
159 // TODO: Essentially the same as PathWedgeTessellator::write_patches but with a different
160 // PatchWriter template.
161 // For wedges, we iterate over each contour explicitly, using a fan point position that is in
162 // the midpoint of the current contour.
163 MidpointContourParser parser{path};
164 while (parser.parseNextContour()) {
165 writer.updateFanPointAttrib(parser.currentMidpoint());
166 SkPoint lastPoint = {0, 0};
167 SkPoint startPoint = {0, 0};
168 for (auto [verb, pts, w] : parser.currentContour()) {
169 switch (verb) {
170 case SkPathVerb::kMove:
171 startPoint = lastPoint = pts[0];
172 break;
173 case SkPathVerb::kLine:
174 // Unlike curve tessellation, wedges have to handle lines as part of the patch,
175 // effectively forming a single triangle with the fan point.
176 writer.writeLine(pts[0], pts[1]);
177 lastPoint = pts[1];
178 break;
179 case SkPathVerb::kQuad:
180 writer.writeQuadratic(pts);
181 lastPoint = pts[2];
182 break;
183 case SkPathVerb::kConic:
184 writer.writeConic(pts, *w);
185 lastPoint = pts[2];
186 break;
187 case SkPathVerb::kCubic:
188 writer.writeCubic(pts);
189 lastPoint = pts[3];
190 break;
191 default: break;
192 }
193 }
194
195 // Explicitly close the contour with another line segment, which also differs from curve
196 // tessellation since that approach's triangle step automatically closes the contour.
197 if (lastPoint != startPoint) {
198 writer.writeLine(lastPoint, startPoint);
199 }
200 }
201 }
202
writeUniformsAndTextures(const DrawParams & params,PipelineDataGatherer * gatherer) const203 void TessellateWedgesRenderStep::writeUniformsAndTextures(const DrawParams& params,
204 PipelineDataGatherer* gatherer) const {
205 SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, this->uniforms());)
206
207 gatherer->write(params.transform().matrix());
208 }
209
210 } // namespace skgpu::graphite
211