1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2023 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/PerEdgeAAQuadRenderStep.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkM44.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkEnumBitMask.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkVx.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/DrawWriter.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/EdgeAAQuad.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/Geometry.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/Rect.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/Transform_graphite.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/render/CommonDepthStencilSettings.h"
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
31*c8dee2aaSAndroid Build Coastguard Worker #include <string_view>
32*c8dee2aaSAndroid Build Coastguard Worker
33*c8dee2aaSAndroid Build Coastguard Worker // This RenderStep is specialized to draw filled rectangles with per-edge AA.
34*c8dee2aaSAndroid Build Coastguard Worker //
35*c8dee2aaSAndroid Build Coastguard Worker // Each of these "primitives" is represented by a single instance. The instance attributes are
36*c8dee2aaSAndroid Build Coastguard Worker // flexible enough to describe per-edge AA quads without relying on uniforms to define its
37*c8dee2aaSAndroid Build Coastguard Worker // operation. The attributes encode shape as follows:
38*c8dee2aaSAndroid Build Coastguard Worker //
39*c8dee2aaSAndroid Build Coastguard Worker // float4 edgeFlags - per-edge AA defined by each component: aa != 0.
40*c8dee2aaSAndroid Build Coastguard Worker // float4 quadXs - these values provide the X coordinates of the quadrilateral in top-left CW order.
41*c8dee2aaSAndroid Build Coastguard Worker // float4 quadYs - these values provide the Y coordinates of the quadrilateral.
42*c8dee2aaSAndroid Build Coastguard Worker //
43*c8dee2aaSAndroid Build Coastguard Worker // From the other direction, per-edge AA quads produce instance values like:
44*c8dee2aaSAndroid Build Coastguard Worker // - [aa(t,r,b,l) ? 255 : 0] [xs(tl,tr,br,bl)] [ys(tl,tr,br,bl)]
45*c8dee2aaSAndroid Build Coastguard Worker //
46*c8dee2aaSAndroid Build Coastguard Worker // From this encoding, data can be unpacked for each corner, which are equivalent under
47*c8dee2aaSAndroid Build Coastguard Worker // rotational symmetry. Per-edge quads are always mitered and fill the interior, but the
48*c8dee2aaSAndroid Build Coastguard Worker // vertices are placed such that the edge coverage ramps can collapse to 0 area on non-AA edges.
49*c8dee2aaSAndroid Build Coastguard Worker //
50*c8dee2aaSAndroid Build Coastguard Worker // The vertices that describe each corner are placed so that edges and miters calculate
51*c8dee2aaSAndroid Build Coastguard Worker // coverage by interpolating a varying and then clamping in the fragment shader. Triangles that
52*c8dee2aaSAndroid Build Coastguard Worker // cover the inner and outer curves calculate distance to the curve within the fragment shader.
53*c8dee2aaSAndroid Build Coastguard Worker //
54*c8dee2aaSAndroid Build Coastguard Worker // See https://docs.google.com/presentation/d/1MCPstNsSlDBhR8CrsJo0r-cZNbu-sEJEvU9W94GOJoY/edit?usp=sharing
55*c8dee2aaSAndroid Build Coastguard Worker // for diagrams and explanation of how the geometry is defined.
56*c8dee2aaSAndroid Build Coastguard Worker //
57*c8dee2aaSAndroid Build Coastguard Worker // PerEdgeAAQuadRenderStep uses the common technique of approximating distance to the level set by
58*c8dee2aaSAndroid Build Coastguard Worker // one expansion of the Taylor's series for the level set's equation. Given a level set function
59*c8dee2aaSAndroid Build Coastguard Worker // C(x,y), this amounts to calculating C(px,py)/|∇C(px,py)|. For the straight edges the level set
60*c8dee2aaSAndroid Build Coastguard Worker // is linear and calculated in the vertex shader and then interpolated exactly over the rectangle.
61*c8dee2aaSAndroid Build Coastguard Worker // This provides distances to all four exterior edges within the fragment shader and allows it to
62*c8dee2aaSAndroid Build Coastguard Worker // reconstruct a relative position per elliptical corner. Unfortunately this requires the fragment
63*c8dee2aaSAndroid Build Coastguard Worker // shader to calculate the length of the gradient for straight edges instead of interpolating
64*c8dee2aaSAndroid Build Coastguard Worker // exact device-space distance.
65*c8dee2aaSAndroid Build Coastguard Worker //
66*c8dee2aaSAndroid Build Coastguard Worker // Unlike AnalyticRRectRenderStep, for per-edge AA quads it's valid to have each pixel calculate a
67*c8dee2aaSAndroid Build Coastguard Worker // single corner's coverage that's controlled via the vertex shader. Any bias is a constant 1/2,
68*c8dee2aaSAndroid Build Coastguard Worker // so this is also added in the vertex shader.
69*c8dee2aaSAndroid Build Coastguard Worker //
70*c8dee2aaSAndroid Build Coastguard Worker // Analytic derivatives are used so that a single pipeline can be used regardless of HW derivative
71*c8dee2aaSAndroid Build Coastguard Worker // support or for geometry that would prove difficult for forward differencing. The device-space
72*c8dee2aaSAndroid Build Coastguard Worker // gradient for ellipses is calculated per-pixel by transforming a per-pixel local gradient vector
73*c8dee2aaSAndroid Build Coastguard Worker // with the Jacobian of the inverse local-to-device transform:
74*c8dee2aaSAndroid Build Coastguard Worker //
75*c8dee2aaSAndroid Build Coastguard Worker // (px,py) is the projected point of (u,v) transformed by a 3x3 matrix, M:
76*c8dee2aaSAndroid Build Coastguard Worker // [x(u,v) / w(u,v)] [x] [m00 m01 m02] [u]
77*c8dee2aaSAndroid Build Coastguard Worker // (px,py) = [y(u,v) / w(u,v)] where [y] = [m10 m11 m12]X[v] = M*(u,v,1)
78*c8dee2aaSAndroid Build Coastguard Worker // [w] [m20 m21 m22] [1]
79*c8dee2aaSAndroid Build Coastguard Worker //
80*c8dee2aaSAndroid Build Coastguard Worker // C(px,py) can be defined in terms of a local Cl(u,v) as C(px,py) = Cl(p^-1(px,py)), where p^-1 =
81*c8dee2aaSAndroid Build Coastguard Worker //
82*c8dee2aaSAndroid Build Coastguard Worker // [x'(px,py) / w'(px,py)] [x'] [m00' m01' * m02'] [px]
83*c8dee2aaSAndroid Build Coastguard Worker // (u,v) = [y'(px,py) / w'(px,py)] where [y'] = [m10' m11' * m12']X[py] = M^-1*(px,py,0,1)
84*c8dee2aaSAndroid Build Coastguard Worker // [w'] [m20' m21' * m22'] [ 1]
85*c8dee2aaSAndroid Build Coastguard Worker //
86*c8dee2aaSAndroid Build Coastguard Worker // Note that if the 3x3 M was arrived by dropping the 3rd row and column from a 4x4 since we assume
87*c8dee2aaSAndroid Build Coastguard Worker // a local 3rd coordinate of 0, M^-1 is not equal to the 4x4 inverse with dropped rows and columns.
88*c8dee2aaSAndroid Build Coastguard Worker //
89*c8dee2aaSAndroid Build Coastguard Worker // Using the chain rule, then ∇C(px,py)
90*c8dee2aaSAndroid Build Coastguard Worker // = ∇Cl(u,v)X[1/w'(px,py) 0 -x'(px,py)/w'(px,py)^2] [m00' m01']
91*c8dee2aaSAndroid Build Coastguard Worker // [ 0 1/w'(px,py) -y'(px,py)/w'(px,py)^2]X[m10' m11']
92*c8dee2aaSAndroid Build Coastguard Worker // [m20' m21']
93*c8dee2aaSAndroid Build Coastguard Worker //
94*c8dee2aaSAndroid Build Coastguard Worker // = 1/w'(px,py)*∇Cl(u,v)X[1 0 -x'(px,py)/w'(px,py)] [m00' m01']
95*c8dee2aaSAndroid Build Coastguard Worker // [0 1 -y'(px,py)/w'(px,py)]X[m10' m11']
96*c8dee2aaSAndroid Build Coastguard Worker // [m20' m21']
97*c8dee2aaSAndroid Build Coastguard Worker //
98*c8dee2aaSAndroid Build Coastguard Worker // = w(u,v)*∇Cl(u,v)X[1 0 0 -u] [m00' m01']
99*c8dee2aaSAndroid Build Coastguard Worker // [0 1 0 -v]X[m10' m11']
100*c8dee2aaSAndroid Build Coastguard Worker // [m20' m21']
101*c8dee2aaSAndroid Build Coastguard Worker //
102*c8dee2aaSAndroid Build Coastguard Worker // = w(u,v)*∇Cl(u,v)X[m00'-m20'u m01'-m21'u]
103*c8dee2aaSAndroid Build Coastguard Worker // [m10'-m20'v m11'-m21'v]
104*c8dee2aaSAndroid Build Coastguard Worker //
105*c8dee2aaSAndroid Build Coastguard Worker // The vertex shader calculates the rightmost 2x2 matrix and interpolates it across the shape since
106*c8dee2aaSAndroid Build Coastguard Worker // each component is linear in (u,v). ∇Cl(u,v) is evaluated per pixel in the fragment shader and
107*c8dee2aaSAndroid Build Coastguard Worker // depends on which corner and edge being evaluated. w(u,v) is the device-space W coordinate, so
108*c8dee2aaSAndroid Build Coastguard Worker // its reciprocal is provided in sk_FragCoord.w.
109*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
110*c8dee2aaSAndroid Build Coastguard Worker
111*c8dee2aaSAndroid Build Coastguard Worker using AAFlags = EdgeAAQuad::Flags;
112*c8dee2aaSAndroid Build Coastguard Worker
is_clockwise(const EdgeAAQuad & quad)113*c8dee2aaSAndroid Build Coastguard Worker static bool is_clockwise(const EdgeAAQuad& quad) {
114*c8dee2aaSAndroid Build Coastguard Worker if (quad.isRect()) {
115*c8dee2aaSAndroid Build Coastguard Worker return true; // by construction, these are always locally clockwise
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker
118*c8dee2aaSAndroid Build Coastguard Worker // This assumes that each corner has a consistent winding, which is the case for convex inputs,
119*c8dee2aaSAndroid Build Coastguard Worker // which is an assumption of the per-edge AA API. Check the sign of cross product between the
120*c8dee2aaSAndroid Build Coastguard Worker // first two edges.
121*c8dee2aaSAndroid Build Coastguard Worker const skvx::float4& xs = quad.xs();
122*c8dee2aaSAndroid Build Coastguard Worker const skvx::float4& ys = quad.ys();
123*c8dee2aaSAndroid Build Coastguard Worker
124*c8dee2aaSAndroid Build Coastguard Worker float winding = (xs[0] - xs[3])*(ys[1] - ys[0]) - (ys[0] - ys[3])*(xs[1] - xs[0]);
125*c8dee2aaSAndroid Build Coastguard Worker if (winding == 0.f) {
126*c8dee2aaSAndroid Build Coastguard Worker // The input possibly forms a triangle with duplicate vertices, so check the opposite corner
127*c8dee2aaSAndroid Build Coastguard Worker winding = (xs[2] - xs[1])*(ys[3] - ys[2]) - (ys[2] - ys[1])*(xs[3] - xs[2]);
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker
130*c8dee2aaSAndroid Build Coastguard Worker // At this point if winding is < 0, the quad's vertices are CCW. If it's still 0, the vertices
131*c8dee2aaSAndroid Build Coastguard Worker // form a line, in which case the vertex shader constructs a correct CW winding. Otherwise,
132*c8dee2aaSAndroid Build Coastguard Worker // the quad or triangle vertices produce a positive winding and are CW.
133*c8dee2aaSAndroid Build Coastguard Worker return winding >= 0.f;
134*c8dee2aaSAndroid Build Coastguard Worker }
135*c8dee2aaSAndroid Build Coastguard Worker
136*c8dee2aaSAndroid Build Coastguard Worker // Represents the per-vertex attributes used in each instance.
137*c8dee2aaSAndroid Build Coastguard Worker struct Vertex {
138*c8dee2aaSAndroid Build Coastguard Worker SkV2 fNormal;
139*c8dee2aaSAndroid Build Coastguard Worker };
140*c8dee2aaSAndroid Build Coastguard Worker
141*c8dee2aaSAndroid Build Coastguard Worker // Allowed values for the center weight instance value (selected at record time based on style
142*c8dee2aaSAndroid Build Coastguard Worker // and transform), and are defined such that when (insance-weight > vertex-weight) is true, the
143*c8dee2aaSAndroid Build Coastguard Worker // vertex should be snapped to the center instead of its regular calculation.
144*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kCornerVertexCount = 4; // sk_VertexID is divided by this in SkSL
145*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kVertexCount = 4 * kCornerVertexCount;
146*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kIndexCount = 29;
147*c8dee2aaSAndroid Build Coastguard Worker
write_index_buffer(VertexWriter writer)148*c8dee2aaSAndroid Build Coastguard Worker static void write_index_buffer(VertexWriter writer) {
149*c8dee2aaSAndroid Build Coastguard Worker static constexpr uint16_t kTL = 0 * kCornerVertexCount;
150*c8dee2aaSAndroid Build Coastguard Worker static constexpr uint16_t kTR = 1 * kCornerVertexCount;
151*c8dee2aaSAndroid Build Coastguard Worker static constexpr uint16_t kBR = 2 * kCornerVertexCount;
152*c8dee2aaSAndroid Build Coastguard Worker static constexpr uint16_t kBL = 3 * kCornerVertexCount;
153*c8dee2aaSAndroid Build Coastguard Worker
154*c8dee2aaSAndroid Build Coastguard Worker static const uint16_t kIndices[kIndexCount] = {
155*c8dee2aaSAndroid Build Coastguard Worker // Exterior AA ramp outset
156*c8dee2aaSAndroid Build Coastguard Worker kTL+1,kTL+2,kTL+3,kTR+0,kTR+3,kTR+1,
157*c8dee2aaSAndroid Build Coastguard Worker kTR+1,kTR+2,kTR+3,kBR+0,kBR+3,kBR+1,
158*c8dee2aaSAndroid Build Coastguard Worker kBR+1,kBR+2,kBR+3,kBL+0,kBL+3,kBL+1,
159*c8dee2aaSAndroid Build Coastguard Worker kBL+1,kBL+2,kBL+3,kTL+0,kTL+3,kTL+1,
160*c8dee2aaSAndroid Build Coastguard Worker kTL+3,
161*c8dee2aaSAndroid Build Coastguard Worker // Fill triangles
162*c8dee2aaSAndroid Build Coastguard Worker kTL+3,kTR+3,kBL+3,kBR+3
163*c8dee2aaSAndroid Build Coastguard Worker };
164*c8dee2aaSAndroid Build Coastguard Worker
165*c8dee2aaSAndroid Build Coastguard Worker if (writer) {
166*c8dee2aaSAndroid Build Coastguard Worker writer << kIndices;
167*c8dee2aaSAndroid Build Coastguard Worker } // otherwise static buffer creation failed, so do nothing; Context initialization will fail.
168*c8dee2aaSAndroid Build Coastguard Worker }
169*c8dee2aaSAndroid Build Coastguard Worker
write_vertex_buffer(VertexWriter writer)170*c8dee2aaSAndroid Build Coastguard Worker static void write_vertex_buffer(VertexWriter writer) {
171*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kHR2 = 0.5f * SK_FloatSqrt2; // "half root 2"
172*c8dee2aaSAndroid Build Coastguard Worker
173*c8dee2aaSAndroid Build Coastguard Worker // This template is repeated 4 times in the vertex buffer, for each of the four corners.
174*c8dee2aaSAndroid Build Coastguard Worker // The vertex ID is used to lookup per-corner instance properties such as positions,
175*c8dee2aaSAndroid Build Coastguard Worker // but otherwise this vertex data produces a consistent clockwise mesh from
176*c8dee2aaSAndroid Build Coastguard Worker // TL -> TR -> BR -> BL.
177*c8dee2aaSAndroid Build Coastguard Worker static constexpr Vertex kCornerTemplate[kCornerVertexCount] = {
178*c8dee2aaSAndroid Build Coastguard Worker // Normals for device-space AA outsets from outer curve
179*c8dee2aaSAndroid Build Coastguard Worker { {1.0f, 0.0f} },
180*c8dee2aaSAndroid Build Coastguard Worker { {kHR2, kHR2} },
181*c8dee2aaSAndroid Build Coastguard Worker { {0.0f, 1.0f} },
182*c8dee2aaSAndroid Build Coastguard Worker
183*c8dee2aaSAndroid Build Coastguard Worker // Normal for outer anchor (zero length to signal no local or device-space normal outset)
184*c8dee2aaSAndroid Build Coastguard Worker { {0.0f, 0.0f} },
185*c8dee2aaSAndroid Build Coastguard Worker };
186*c8dee2aaSAndroid Build Coastguard Worker
187*c8dee2aaSAndroid Build Coastguard Worker if (writer) {
188*c8dee2aaSAndroid Build Coastguard Worker writer << kCornerTemplate // TL
189*c8dee2aaSAndroid Build Coastguard Worker << kCornerTemplate // TR
190*c8dee2aaSAndroid Build Coastguard Worker << kCornerTemplate // BR
191*c8dee2aaSAndroid Build Coastguard Worker << kCornerTemplate; // BL
192*c8dee2aaSAndroid Build Coastguard Worker } // otherwise static buffer creation failed, so do nothing; Context initialization will fail.
193*c8dee2aaSAndroid Build Coastguard Worker }
194*c8dee2aaSAndroid Build Coastguard Worker
PerEdgeAAQuadRenderStep(StaticBufferManager * bufferManager)195*c8dee2aaSAndroid Build Coastguard Worker PerEdgeAAQuadRenderStep::PerEdgeAAQuadRenderStep(StaticBufferManager* bufferManager)
196*c8dee2aaSAndroid Build Coastguard Worker : RenderStep("PerEdgeAAQuadRenderStep",
197*c8dee2aaSAndroid Build Coastguard Worker "",
198*c8dee2aaSAndroid Build Coastguard Worker Flags::kPerformsShading | Flags::kEmitsCoverage | Flags::kOutsetBoundsForAA |
199*c8dee2aaSAndroid Build Coastguard Worker Flags::kUseNonAAInnerFill,
200*c8dee2aaSAndroid Build Coastguard Worker /*uniforms=*/{},
201*c8dee2aaSAndroid Build Coastguard Worker PrimitiveType::kTriangleStrip,
202*c8dee2aaSAndroid Build Coastguard Worker kDirectDepthGreaterPass,
203*c8dee2aaSAndroid Build Coastguard Worker /*vertexAttrs=*/{
204*c8dee2aaSAndroid Build Coastguard Worker {"normal", VertexAttribType::kFloat2, SkSLType::kFloat2},
205*c8dee2aaSAndroid Build Coastguard Worker },
206*c8dee2aaSAndroid Build Coastguard Worker /*instanceAttrs=*/
207*c8dee2aaSAndroid Build Coastguard Worker {{"edgeFlags", VertexAttribType::kUByte4_norm, SkSLType::kFloat4},
208*c8dee2aaSAndroid Build Coastguard Worker {"quadXs", VertexAttribType::kFloat4, SkSLType::kFloat4},
209*c8dee2aaSAndroid Build Coastguard Worker {"quadYs", VertexAttribType::kFloat4, SkSLType::kFloat4},
210*c8dee2aaSAndroid Build Coastguard Worker
211*c8dee2aaSAndroid Build Coastguard Worker // TODO: pack depth and ssbo index into one 32-bit attribute, if we can
212*c8dee2aaSAndroid Build Coastguard Worker // go without needing both render step and paint ssbo index attributes.
213*c8dee2aaSAndroid Build Coastguard Worker {"depth", VertexAttribType::kFloat, SkSLType::kFloat},
214*c8dee2aaSAndroid Build Coastguard Worker {"ssboIndices", VertexAttribType::kUInt2, SkSLType::kUInt2},
215*c8dee2aaSAndroid Build Coastguard Worker
216*c8dee2aaSAndroid Build Coastguard Worker {"mat0", VertexAttribType::kFloat3, SkSLType::kFloat3},
217*c8dee2aaSAndroid Build Coastguard Worker {"mat1", VertexAttribType::kFloat3, SkSLType::kFloat3},
218*c8dee2aaSAndroid Build Coastguard Worker {"mat2", VertexAttribType::kFloat3, SkSLType::kFloat3}},
219*c8dee2aaSAndroid Build Coastguard Worker /*varyings=*/{
220*c8dee2aaSAndroid Build Coastguard Worker // Device-space distance to LTRB edges of quad.
221*c8dee2aaSAndroid Build Coastguard Worker {"edgeDistances", SkSLType::kFloat4}, // distance to LTRB edges
222*c8dee2aaSAndroid Build Coastguard Worker }) {
223*c8dee2aaSAndroid Build Coastguard Worker // Initialize the static buffers we'll use when recording draw calls.
224*c8dee2aaSAndroid Build Coastguard Worker // NOTE: Each instance of this RenderStep gets its own copy of the data. Since there should only
225*c8dee2aaSAndroid Build Coastguard Worker // ever be one PerEdgeAAQuadRenderStep at a time, this shouldn't be an issue.
226*c8dee2aaSAndroid Build Coastguard Worker write_vertex_buffer(bufferManager->getVertexWriter(sizeof(Vertex) * kVertexCount,
227*c8dee2aaSAndroid Build Coastguard Worker &fVertexBuffer));
228*c8dee2aaSAndroid Build Coastguard Worker write_index_buffer(bufferManager->getIndexWriter(sizeof(uint16_t) * kIndexCount,
229*c8dee2aaSAndroid Build Coastguard Worker &fIndexBuffer));
230*c8dee2aaSAndroid Build Coastguard Worker }
231*c8dee2aaSAndroid Build Coastguard Worker
~PerEdgeAAQuadRenderStep()232*c8dee2aaSAndroid Build Coastguard Worker PerEdgeAAQuadRenderStep::~PerEdgeAAQuadRenderStep() {}
233*c8dee2aaSAndroid Build Coastguard Worker
vertexSkSL() const234*c8dee2aaSAndroid Build Coastguard Worker std::string PerEdgeAAQuadRenderStep::vertexSkSL() const {
235*c8dee2aaSAndroid Build Coastguard Worker // Returns the body of a vertex function, which must define a float4 devPosition variable and
236*c8dee2aaSAndroid Build Coastguard Worker // must write to an already-defined float2 stepLocalCoords variable.
237*c8dee2aaSAndroid Build Coastguard Worker return "float4 devPosition = per_edge_aa_quad_vertex_fn("
238*c8dee2aaSAndroid Build Coastguard Worker // Vertex Attributes
239*c8dee2aaSAndroid Build Coastguard Worker "normal, "
240*c8dee2aaSAndroid Build Coastguard Worker // Instance Attributes
241*c8dee2aaSAndroid Build Coastguard Worker "edgeFlags, quadXs, quadYs, depth, "
242*c8dee2aaSAndroid Build Coastguard Worker "float3x3(mat0, mat1, mat2), "
243*c8dee2aaSAndroid Build Coastguard Worker // Varyings
244*c8dee2aaSAndroid Build Coastguard Worker "edgeDistances, "
245*c8dee2aaSAndroid Build Coastguard Worker // Render Step
246*c8dee2aaSAndroid Build Coastguard Worker "stepLocalCoords);\n";
247*c8dee2aaSAndroid Build Coastguard Worker }
248*c8dee2aaSAndroid Build Coastguard Worker
fragmentCoverageSkSL() const249*c8dee2aaSAndroid Build Coastguard Worker const char* PerEdgeAAQuadRenderStep::fragmentCoverageSkSL() const {
250*c8dee2aaSAndroid Build Coastguard Worker // The returned SkSL must write its coverage into a 'half4 outputCoverage' variable (defined in
251*c8dee2aaSAndroid Build Coastguard Worker // the calling code) with the actual coverage splatted out into all four channels.
252*c8dee2aaSAndroid Build Coastguard Worker return "outputCoverage = per_edge_aa_quad_coverage_fn(sk_FragCoord, edgeDistances);";
253*c8dee2aaSAndroid Build Coastguard Worker }
254*c8dee2aaSAndroid Build Coastguard Worker
writeVertices(DrawWriter * writer,const DrawParams & params,skvx::uint2 ssboIndices) const255*c8dee2aaSAndroid Build Coastguard Worker void PerEdgeAAQuadRenderStep::writeVertices(DrawWriter* writer,
256*c8dee2aaSAndroid Build Coastguard Worker const DrawParams& params,
257*c8dee2aaSAndroid Build Coastguard Worker skvx::uint2 ssboIndices) const {
258*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(params.geometry().isEdgeAAQuad());
259*c8dee2aaSAndroid Build Coastguard Worker const EdgeAAQuad& quad = params.geometry().edgeAAQuad();
260*c8dee2aaSAndroid Build Coastguard Worker
261*c8dee2aaSAndroid Build Coastguard Worker DrawWriter::Instances instance{*writer, fVertexBuffer, fIndexBuffer, kIndexCount};
262*c8dee2aaSAndroid Build Coastguard Worker auto vw = instance.append(1);
263*c8dee2aaSAndroid Build Coastguard Worker
264*c8dee2aaSAndroid Build Coastguard Worker // Empty fills should not have been recorded at all.
265*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(Rect bounds = params.geometry().bounds());
266*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!bounds.isEmptyNegativeOrNaN());
267*c8dee2aaSAndroid Build Coastguard Worker
268*c8dee2aaSAndroid Build Coastguard Worker constexpr uint8_t kAAOn = 255;
269*c8dee2aaSAndroid Build Coastguard Worker constexpr uint8_t kAAOff = 0;
270*c8dee2aaSAndroid Build Coastguard Worker auto edgeSigns = skvx::byte4{quad.edgeFlags() & AAFlags::kLeft ? kAAOn : kAAOff,
271*c8dee2aaSAndroid Build Coastguard Worker quad.edgeFlags() & AAFlags::kTop ? kAAOn : kAAOff,
272*c8dee2aaSAndroid Build Coastguard Worker quad.edgeFlags() & AAFlags::kRight ? kAAOn : kAAOff,
273*c8dee2aaSAndroid Build Coastguard Worker quad.edgeFlags() & AAFlags::kBottom ? kAAOn : kAAOff};
274*c8dee2aaSAndroid Build Coastguard Worker
275*c8dee2aaSAndroid Build Coastguard Worker // The vertex shader expects points to be in clockwise order. EdgeAAQuad is the only
276*c8dee2aaSAndroid Build Coastguard Worker // shape that *might* have counter-clockwise input.
277*c8dee2aaSAndroid Build Coastguard Worker if (is_clockwise(quad)) {
278*c8dee2aaSAndroid Build Coastguard Worker vw << edgeSigns << quad.xs() << quad.ys();
279*c8dee2aaSAndroid Build Coastguard Worker } else {
280*c8dee2aaSAndroid Build Coastguard Worker vw << skvx::shuffle<2,1,0,3>(edgeSigns) // swap left and right AA bits
281*c8dee2aaSAndroid Build Coastguard Worker << skvx::shuffle<1,0,3,2>(quad.xs()) // swap TL with TR, and BL with BR
282*c8dee2aaSAndroid Build Coastguard Worker << skvx::shuffle<1,0,3,2>(quad.ys()); // ""
283*c8dee2aaSAndroid Build Coastguard Worker }
284*c8dee2aaSAndroid Build Coastguard Worker
285*c8dee2aaSAndroid Build Coastguard Worker // All instance types share the remaining instance attribute definitions
286*c8dee2aaSAndroid Build Coastguard Worker const SkM44& m = params.transform().matrix();
287*c8dee2aaSAndroid Build Coastguard Worker
288*c8dee2aaSAndroid Build Coastguard Worker vw << params.order().depthAsFloat()
289*c8dee2aaSAndroid Build Coastguard Worker << ssboIndices
290*c8dee2aaSAndroid Build Coastguard Worker << m.rc(0,0) << m.rc(1,0) << m.rc(3,0) // mat0
291*c8dee2aaSAndroid Build Coastguard Worker << m.rc(0,1) << m.rc(1,1) << m.rc(3,1) // mat1
292*c8dee2aaSAndroid Build Coastguard Worker << m.rc(0,3) << m.rc(1,3) << m.rc(3,3); // mat2
293*c8dee2aaSAndroid Build Coastguard Worker }
294*c8dee2aaSAndroid Build Coastguard Worker
writeUniformsAndTextures(const DrawParams &,PipelineDataGatherer *) const295*c8dee2aaSAndroid Build Coastguard Worker void PerEdgeAAQuadRenderStep::writeUniformsAndTextures(const DrawParams&,
296*c8dee2aaSAndroid Build Coastguard Worker PipelineDataGatherer*) const {
297*c8dee2aaSAndroid Build Coastguard Worker // All data is uploaded as instance attributes, so no uniforms are needed.
298*c8dee2aaSAndroid Build Coastguard Worker }
299*c8dee2aaSAndroid Build Coastguard Worker
300*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
301