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