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