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/TessellateCurvesRenderStep.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/SkSpan_impl.h"
15 #include "src/base/SkEnumBitMask.h"
16 #include "src/core/SkPathPriv.h"
17 #include "src/core/SkSLTypeShared.h"
18 #include "src/gpu/BufferWriter.h"
19 #include "src/gpu/graphite/Attribute.h"
20 #include "src/gpu/graphite/BufferManager.h"
21 #include "src/gpu/graphite/DrawOrder.h"
22 #include "src/gpu/graphite/DrawParams.h"
23 #include "src/gpu/graphite/DrawTypes.h"
24 #include "src/gpu/graphite/PipelineData.h"
25 #include "src/gpu/graphite/geom/Geometry.h"
26 #include "src/gpu/graphite/geom/Shape.h"
27 #include "src/gpu/graphite/geom/Transform_graphite.h"
28 #include "src/gpu/graphite/render/CommonDepthStencilSettings.h"
29 #include "src/gpu/graphite/render/DynamicInstancesPatchAllocator.h"
30 #include "src/gpu/tessellate/FixedCountBufferUtils.h"
31 #include "src/gpu/tessellate/PatchWriter.h"
32 #include "src/gpu/tessellate/Tessellation.h"
33 #include "src/gpu/tessellate/WangsFormula.h"
34 #include "src/sksl/SkSLString.h"
35
36 #include <cstddef>
37 #include <string_view>
38 #include <utility>
39
40 namespace skgpu::graphite {
41
42 namespace {
43
44 using namespace skgpu::tess;
45
46 // No fan point or stroke params, since this is for filled curves (not strokes or wedges)
47 // No explicit curve type on platforms that support infinity.
48 // No color or wide color attribs, since it might always be part of the PaintParams
49 // or we'll add a color-only fast path to RenderStep later.
50 static constexpr PatchAttribs kAttribs = PatchAttribs::kPaintDepth |
51 PatchAttribs::kSsboIndex;
52 static constexpr PatchAttribs kAttribsWithCurveType = kAttribs | PatchAttribs::kExplicitCurveType;
53 using Writer = PatchWriter<DynamicInstancesPatchAllocator<FixedCountCurves>,
54 Required<PatchAttribs::kPaintDepth>,
55 Required<PatchAttribs::kSsboIndex>,
56 Optional<PatchAttribs::kExplicitCurveType>,
57 AddTrianglesWhenChopping,
58 DiscardFlatCurves>;
59
60 // The order of the attribute declarations must match the order used by
61 // PatchWriter::emitPatchAttribs, i.e.:
62 // join << fanPoint << stroke << color << depth << curveType << ssboIndices
63 static constexpr Attribute kBaseAttributes[] = {
64 {"p01", VertexAttribType::kFloat4, SkSLType::kFloat4},
65 {"p23", VertexAttribType::kFloat4, SkSLType::kFloat4},
66 {"depth", VertexAttribType::kFloat, SkSLType::kFloat},
67 {"ssboIndices", VertexAttribType::kUInt2, SkSLType::kUInt2}};
68
69 static constexpr Attribute kAttributesWithCurveType[] = {
70 {"p01", VertexAttribType::kFloat4, SkSLType::kFloat4},
71 {"p23", VertexAttribType::kFloat4, SkSLType::kFloat4},
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
TessellateCurvesRenderStep(bool evenOdd,bool infinitySupport,StaticBufferManager * bufferManager)81 TessellateCurvesRenderStep::TessellateCurvesRenderStep(bool evenOdd,
82 bool infinitySupport,
83 StaticBufferManager* bufferManager)
84 : RenderStep("TessellateCurvesRenderStep",
85 evenOdd ? "even-odd" : "winding",
86 Flags::kRequiresMSAA,
87 /*uniforms=*/{{"localToDevice", SkSLType::kFloat4x4}},
88 PrimitiveType::kTriangles,
89 evenOdd ? kEvenOddStencilPass : kWindingStencilPass,
90 /*vertexAttrs=*/ {{"resolveLevel_and_idx",
91 VertexAttribType::kFloat2, SkSLType::kFloat2}},
92 /*instanceAttrs=*/kAttributes[infinitySupport])
93 , fInfinitySupport(infinitySupport) {
94 SkASSERT(this->instanceStride() ==
95 PatchStride(infinitySupport ? kAttribs : kAttribsWithCurveType));
96
97 // Initialize the static buffers we'll use when recording draw calls.
98 // NOTE: Each instance of this RenderStep gets its own copy of the data. If this ends up causing
99 // problems, we can modify StaticBufferManager to de-duplicate requests.
100 const size_t vertexSize = FixedCountCurves::VertexBufferSize();
101 auto vertexData = bufferManager->getVertexWriter(vertexSize, &fVertexBuffer);
102 if (vertexData) {
103 FixedCountCurves::WriteVertexBuffer(std::move(vertexData), vertexSize);
104 } // otherwise static buffer creation failed, so do nothing; Context initialization will fail.
105
106 const size_t indexSize = FixedCountCurves::IndexBufferSize();
107 auto indexData = bufferManager->getIndexWriter(indexSize, &fIndexBuffer);
108 if (indexData) {
109 FixedCountCurves::WriteIndexBuffer(std::move(indexData), indexSize);
110 } // ""
111 }
112
~TessellateCurvesRenderStep()113 TessellateCurvesRenderStep::~TessellateCurvesRenderStep() {}
114
vertexSkSL() const115 std::string TessellateCurvesRenderStep::vertexSkSL() const {
116 return SkSL::String::printf(
117 R"(
118 // TODO: Approximate perspective scaling to match how PatchWriter is configured (or
119 // provide explicit tessellation level in instance data instead of replicating
120 // work).
121 float2x2 vectorXform = float2x2(localToDevice[0].xy, localToDevice[1].xy);
122 float2 localCoord = tessellate_filled_curve(
123 vectorXform, resolveLevel_and_idx.x, resolveLevel_and_idx.y, p01, p23, %s);
124 float4 devPosition = localToDevice * float4(localCoord, 0.0, 1.0);
125 devPosition.z = depth;
126 stepLocalCoords = localCoord;
127 )",
128 fInfinitySupport ? "curve_type_using_inf_support(p23)" : "curveType");
129 }
130
writeVertices(DrawWriter * dw,const DrawParams & params,skvx::uint2 ssboIndices) const131 void TessellateCurvesRenderStep::writeVertices(DrawWriter* dw,
132 const DrawParams& params,
133 skvx::uint2 ssboIndices) const {
134 SkPath path = params.geometry().shape().asPath(); // TODO: Iterate the Shape directly
135
136 int patchReserveCount = FixedCountCurves::PreallocCount(path.countVerbs());
137 Writer writer{fInfinitySupport ? kAttribs : kAttribsWithCurveType,
138 *dw,
139 fVertexBuffer,
140 fIndexBuffer,
141 patchReserveCount};
142 writer.updatePaintDepthAttrib(params.order().depthAsFloat());
143 writer.updateSsboIndexAttrib(ssboIndices);
144
145 // The vector xform approximates how the control points are transformed by the shader to
146 // more accurately compute how many *parametric* segments are needed.
147 // TODO: This doesn't account for perspective division yet, which will require updating the
148 // approximate transform based on each verb's control points' bounding box.
149 SkASSERT(params.transform().type() < Transform::Type::kPerspective);
150 writer.setShaderTransform(wangs_formula::VectorXform{params.transform().matrix()},
151 params.transform().maxScaleFactor());
152
153 // TODO: For filled curves, the path verb loop is simple enough that it's not too big a deal
154 // to copy the logic from PathCurveTessellator::write_patches. It may be required if we end
155 // up switching to a shape iterator in graphite vs. a path iterator in ganesh, or if
156 // graphite does not control point transformation on the CPU. On the other hand, if we
157 // provide a templated WritePatches function, the iterator could also be a template arg in
158 // addition to PatchWriter's traits. Whatever pattern we choose will be based more on what's
159 // best for the wedge and stroke case, which have more complex loops.
160 for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
161 switch (verb) {
162 case SkPathVerb::kQuad: writer.writeQuadratic(pts); break;
163 case SkPathVerb::kConic: writer.writeConic(pts, *w); break;
164 case SkPathVerb::kCubic: writer.writeCubic(pts); break;
165 default: break;
166 }
167 }
168 }
169
writeUniformsAndTextures(const DrawParams & params,PipelineDataGatherer * gatherer) const170 void TessellateCurvesRenderStep::writeUniformsAndTextures(const DrawParams& params,
171 PipelineDataGatherer* gatherer) const {
172 SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, this->uniforms());)
173
174 gatherer->write(params.transform().matrix());
175 }
176
177 } // namespace skgpu::graphite
178