1 | /* |
2 | * Copyright 2017 Google Inc. |
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/ccpr/GrVSCoverageProcessor.h" |
9 | |
10 | #include "src/gpu/GrOpsRenderPass.h" |
11 | #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
12 | #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" |
13 | |
14 | // This class implements the coverage processor with vertex shaders. |
15 | class GrVSCoverageProcessor::Impl : public GrGLSLGeometryProcessor { |
16 | public: |
17 | Impl(std::unique_ptr<Shader> shader, int numSides) |
18 | : fShader(std::move(shader)), fNumSides(numSides) {} |
19 | |
20 | private: |
21 | void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&) final {} |
22 | |
23 | void onEmitCode(EmitArgs&, GrGPArgs*) override; |
24 | |
25 | const std::unique_ptr<Shader> fShader; |
26 | const int fNumSides; |
27 | }; |
28 | |
29 | static constexpr int kInstanceAttribIdx_X = 0; // Transposed X values of all input points. |
30 | static constexpr int kInstanceAttribIdx_Y = 1; // Transposed Y values of all input points. |
31 | |
32 | // Vertex data tells the shader how to offset vertices for conservative raster, as well as how to |
33 | // calculate coverage values for corners and edges. |
34 | static constexpr int kVertexData_LeftNeighborIdShift = 10; |
35 | static constexpr int kVertexData_RightNeighborIdShift = 8; |
36 | static constexpr int kVertexData_BloatIdxShift = 6; |
37 | static constexpr int kVertexData_InvertNegativeCoverageBit = 1 << 5; |
38 | static constexpr int kVertexData_IsCornerBit = 1 << 4; |
39 | static constexpr int kVertexData_IsEdgeBit = 1 << 3; |
40 | static constexpr int kVertexData_IsHullBit = 1 << 2; |
41 | |
42 | static constexpr int32_t pack_vertex_data(int32_t leftNeighborID, int32_t rightNeighborID, |
43 | int32_t bloatIdx, int32_t cornerID, |
44 | int32_t = 0) { |
45 | return (leftNeighborID << kVertexData_LeftNeighborIdShift) | |
46 | (rightNeighborID << kVertexData_RightNeighborIdShift) | |
47 | (bloatIdx << kVertexData_BloatIdxShift) | |
48 | cornerID | extraData; |
49 | } |
50 | |
51 | static constexpr int32_t hull_vertex_data(int32_t cornerID, int32_t bloatIdx, int n) { |
52 | return pack_vertex_data((cornerID + n - 1) % n, (cornerID + 1) % n, bloatIdx, cornerID, |
53 | kVertexData_IsHullBit); |
54 | } |
55 | |
56 | static constexpr int32_t edge_vertex_data(int32_t edgeID, int32_t endptIdx, int32_t bloatIdx, |
57 | int n) { |
58 | return pack_vertex_data(0 == endptIdx ? (edgeID + 1) % n : edgeID, |
59 | 0 == endptIdx ? (edgeID + 1) % n : edgeID, |
60 | bloatIdx, 0 == endptIdx ? edgeID : (edgeID + 1) % n, |
61 | kVertexData_IsEdgeBit | |
62 | (!endptIdx ? kVertexData_InvertNegativeCoverageBit : 0)); |
63 | } |
64 | |
65 | static constexpr int32_t corner_vertex_data(int32_t leftID, int32_t cornerID, int32_t rightID, |
66 | int32_t bloatIdx) { |
67 | return pack_vertex_data(leftID, rightID, bloatIdx, cornerID, kVertexData_IsCornerBit); |
68 | } |
69 | |
70 | static constexpr int32_t kTriangleVertices[] = { |
71 | hull_vertex_data(0, 0, 3), |
72 | hull_vertex_data(0, 1, 3), |
73 | hull_vertex_data(0, 2, 3), |
74 | hull_vertex_data(1, 0, 3), |
75 | hull_vertex_data(1, 1, 3), |
76 | hull_vertex_data(1, 2, 3), |
77 | hull_vertex_data(2, 0, 3), |
78 | hull_vertex_data(2, 1, 3), |
79 | hull_vertex_data(2, 2, 3), |
80 | |
81 | edge_vertex_data(0, 0, 0, 3), |
82 | edge_vertex_data(0, 0, 1, 3), |
83 | edge_vertex_data(0, 0, 2, 3), |
84 | edge_vertex_data(0, 1, 0, 3), |
85 | edge_vertex_data(0, 1, 1, 3), |
86 | edge_vertex_data(0, 1, 2, 3), |
87 | |
88 | edge_vertex_data(1, 0, 0, 3), |
89 | edge_vertex_data(1, 0, 1, 3), |
90 | edge_vertex_data(1, 0, 2, 3), |
91 | edge_vertex_data(1, 1, 0, 3), |
92 | edge_vertex_data(1, 1, 1, 3), |
93 | edge_vertex_data(1, 1, 2, 3), |
94 | |
95 | edge_vertex_data(2, 0, 0, 3), |
96 | edge_vertex_data(2, 0, 1, 3), |
97 | edge_vertex_data(2, 0, 2, 3), |
98 | edge_vertex_data(2, 1, 0, 3), |
99 | edge_vertex_data(2, 1, 1, 3), |
100 | edge_vertex_data(2, 1, 2, 3), |
101 | |
102 | corner_vertex_data(2, 0, 1, 0), |
103 | corner_vertex_data(2, 0, 1, 1), |
104 | corner_vertex_data(2, 0, 1, 2), |
105 | corner_vertex_data(2, 0, 1, 3), |
106 | |
107 | corner_vertex_data(0, 1, 2, 0), |
108 | corner_vertex_data(0, 1, 2, 1), |
109 | corner_vertex_data(0, 1, 2, 2), |
110 | corner_vertex_data(0, 1, 2, 3), |
111 | |
112 | corner_vertex_data(1, 2, 0, 0), |
113 | corner_vertex_data(1, 2, 0, 1), |
114 | corner_vertex_data(1, 2, 0, 2), |
115 | corner_vertex_data(1, 2, 0, 3), |
116 | }; |
117 | |
118 | GR_DECLARE_STATIC_UNIQUE_KEY(gTriangleVertexBufferKey); |
119 | |
120 | static constexpr uint16_t kRestartStrip = 0xffff; |
121 | |
122 | static constexpr uint16_t kTriangleIndicesAsStrips[] = { |
123 | 1, 2, 0, 3, 8, kRestartStrip, // First corner and main body of the hull. |
124 | 4, 5, 3, 6, 8, 7, kRestartStrip, // Opposite side and corners of the hull. |
125 | 10, 9, 11, 14, 12, 13, kRestartStrip, // First edge. |
126 | 16, 15, 17, 20, 18, 19, kRestartStrip, // Second edge. |
127 | 22, 21, 23, 26, 24, 25, kRestartStrip, // Third edge. |
128 | 28, 27, 29, 30, kRestartStrip, // First corner. |
129 | 32, 31, 33, 34, kRestartStrip, // Second corner. |
130 | 36, 35, 37, 38 // Third corner. |
131 | }; |
132 | |
133 | static constexpr uint16_t kTriangleIndicesAsTris[] = { |
134 | // First corner and main body of the hull. |
135 | 1, 2, 0, |
136 | 2, 3, 0, |
137 | 0, 3, 8, // Main body. |
138 | |
139 | // Opposite side and corners of the hull. |
140 | 4, 5, 3, |
141 | 5, 6, 3, |
142 | 3, 6, 8, |
143 | 6, 7, 8, |
144 | |
145 | // First edge. |
146 | 10, 9, 11, |
147 | 9, 14, 11, |
148 | 11, 14, 12, |
149 | 14, 13, 12, |
150 | |
151 | // Second edge. |
152 | 16, 15, 17, |
153 | 15, 20, 17, |
154 | 17, 20, 18, |
155 | 20, 19, 18, |
156 | |
157 | // Third edge. |
158 | 22, 21, 23, |
159 | 21, 26, 23, |
160 | 23, 26, 24, |
161 | 26, 25, 24, |
162 | |
163 | // First corner. |
164 | 28, 27, 29, |
165 | 27, 30, 29, |
166 | |
167 | // Second corner. |
168 | 32, 31, 33, |
169 | 31, 34, 33, |
170 | |
171 | // Third corner. |
172 | 36, 35, 37, |
173 | 35, 38, 37, |
174 | }; |
175 | |
176 | GR_DECLARE_STATIC_UNIQUE_KEY(gTriangleIndexBufferKey); |
177 | |
178 | // Curves, including quadratics, are drawn with a four-sided hull. |
179 | static constexpr int32_t kCurveVertices[] = { |
180 | hull_vertex_data(0, 0, 4), |
181 | hull_vertex_data(0, 1, 4), |
182 | hull_vertex_data(0, 2, 4), |
183 | hull_vertex_data(1, 0, 4), |
184 | hull_vertex_data(1, 1, 4), |
185 | hull_vertex_data(1, 2, 4), |
186 | hull_vertex_data(2, 0, 4), |
187 | hull_vertex_data(2, 1, 4), |
188 | hull_vertex_data(2, 2, 4), |
189 | hull_vertex_data(3, 0, 4), |
190 | hull_vertex_data(3, 1, 4), |
191 | hull_vertex_data(3, 2, 4), |
192 | |
193 | corner_vertex_data(3, 0, 1, 0), |
194 | corner_vertex_data(3, 0, 1, 1), |
195 | corner_vertex_data(3, 0, 1, 2), |
196 | corner_vertex_data(3, 0, 1, 3), |
197 | |
198 | corner_vertex_data(2, 3, 0, 0), |
199 | corner_vertex_data(2, 3, 0, 1), |
200 | corner_vertex_data(2, 3, 0, 2), |
201 | corner_vertex_data(2, 3, 0, 3), |
202 | }; |
203 | |
204 | GR_DECLARE_STATIC_UNIQUE_KEY(gCurveVertexBufferKey); |
205 | |
206 | static constexpr uint16_t kCurveIndicesAsStrips[] = { |
207 | 1, 0, 2, 11, 3, 5, 4, kRestartStrip, // First half of the hull (split diagonally). |
208 | 7, 6, 8, 5, 9, 11, 10, kRestartStrip, // Second half of the hull. |
209 | 13, 12, 14, 15, kRestartStrip, // First corner. |
210 | 17, 16, 18, 19 // Final corner. |
211 | }; |
212 | |
213 | static constexpr uint16_t kCurveIndicesAsTris[] = { |
214 | // First half of the hull (split diagonally). |
215 | 1, 0, 2, |
216 | 0, 11, 2, |
217 | 2, 11, 3, |
218 | 11, 5, 3, |
219 | 3, 5, 4, |
220 | |
221 | // Second half of the hull. |
222 | 7, 6, 8, |
223 | 6, 5, 8, |
224 | 8, 5, 9, |
225 | 5, 11, 9, |
226 | 9, 11, 10, |
227 | |
228 | // First corner. |
229 | 13, 12, 14, |
230 | 12, 15, 14, |
231 | |
232 | // Final corner. |
233 | 17, 16, 18, |
234 | 16, 19, 18, |
235 | }; |
236 | |
237 | GR_DECLARE_STATIC_UNIQUE_KEY(gCurveIndexBufferKey); |
238 | |
239 | // Generates a conservative raster hull around a triangle or curve. For triangles we generate |
240 | // additional conservative rasters with coverage ramps around the edges and corners. |
241 | // |
242 | // Triangles are drawn in three steps: (1) Draw a conservative raster of the entire triangle, with a |
243 | // coverage of +1. (2) Draw conservative rasters around each edge, with a coverage ramp from -1 to |
244 | // 0. These edge coverage values convert jagged conservative raster edges into smooth, antialiased |
245 | // ones. (3) Draw conservative rasters (aka pixel-size boxes) around each corner, replacing the |
246 | // previous coverage values with ones that ramp to zero in the bloat vertices that fall outside the |
247 | // triangle. |
248 | // |
249 | // Curve shaders handle the opposite edge and corners on their own. For curves we just generate a |
250 | // conservative raster here and the shader does the rest. |
251 | void GrVSCoverageProcessor::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { |
252 | const GrVSCoverageProcessor& proc = args.fGP.cast<GrVSCoverageProcessor>(); |
253 | GrGLSLVertexBuilder* v = args.fVertBuilder; |
254 | int numInputPoints = proc.numInputPoints(); |
255 | |
256 | int inputWidth = (4 == numInputPoints || proc.hasInputWeight()) ? 4 : 3; |
257 | const char* swizzle = (4 == inputWidth) ? "xyzw" : "xyz" ; |
258 | v->codeAppendf("float%ix2 pts = transpose(float2x%i(%s.%s, %s.%s));" , inputWidth, inputWidth, |
259 | proc.fInputXAndYValues[kInstanceAttribIdx_X].name(), swizzle, |
260 | proc.fInputXAndYValues[kInstanceAttribIdx_Y].name(), swizzle); |
261 | |
262 | v->codeAppend ("half wind;" ); |
263 | Shader::CalcWind(proc, v, "pts" , "wind" ); |
264 | if (PrimitiveType::kWeightedTriangles == proc.fPrimitiveType) { |
265 | SkASSERT(3 == numInputPoints); |
266 | SkASSERT(kFloat4_GrVertexAttribType == |
267 | proc.fInputXAndYValues[kInstanceAttribIdx_X].cpuType()); |
268 | v->codeAppendf("wind *= half(%s.w);" , |
269 | proc.fInputXAndYValues[kInstanceAttribIdx_X].name()); |
270 | } |
271 | |
272 | float bloat = kAABloatRadius; |
273 | #ifdef SK_DEBUG |
274 | if (proc.debugBloatEnabled()) { |
275 | bloat *= proc.debugBloat(); |
276 | } |
277 | #endif |
278 | v->defineConstant("bloat" , bloat); |
279 | |
280 | const char* hullPts = "pts" ; |
281 | fShader->emitSetupCode(v, "pts" , (4 == fNumSides) ? &hullPts : nullptr); |
282 | |
283 | // Reverse all indices if the wind is counter-clockwise: [0, 1, 2] -> [2, 1, 0]. |
284 | v->codeAppendf("int clockwise_indices = wind > 0 ? %s : 0x%x - %s;" , |
285 | proc.fPerVertexData.name(), |
286 | ((fNumSides - 1) << kVertexData_LeftNeighborIdShift) | |
287 | ((fNumSides - 1) << kVertexData_RightNeighborIdShift) | |
288 | (((1 << kVertexData_RightNeighborIdShift) - 1) ^ 3) | |
289 | (fNumSides - 1), |
290 | proc.fPerVertexData.name()); |
291 | |
292 | // Here we generate conservative raster geometry for the input polygon. It is the convex |
293 | // hull of N pixel-size boxes, one centered on each the input points. Each corner has three |
294 | // vertices, where one or two may cause degenerate triangles. The vertex data tells us how |
295 | // to offset each vertex. Triangle edges and corners are also handled here using the same |
296 | // concept. For more details on conservative raster, see: |
297 | // https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter42.html |
298 | v->codeAppendf("float2 corner = %s[clockwise_indices & 3];" , hullPts); |
299 | v->codeAppendf("float2 left = %s[clockwise_indices >> %i];" , |
300 | hullPts, kVertexData_LeftNeighborIdShift); |
301 | v->codeAppendf("float2 right = %s[(clockwise_indices >> %i) & 3];" , |
302 | hullPts, kVertexData_RightNeighborIdShift); |
303 | |
304 | v->codeAppend ("float2 leftbloat = sign(corner - left);" ); |
305 | v->codeAppend ("leftbloat = float2(0 != leftbloat.y ? leftbloat.y : leftbloat.x, " |
306 | "0 != leftbloat.x ? -leftbloat.x : -leftbloat.y);" ); |
307 | |
308 | v->codeAppend ("float2 rightbloat = sign(right - corner);" ); |
309 | v->codeAppend ("rightbloat = float2(0 != rightbloat.y ? rightbloat.y : rightbloat.x, " |
310 | "0 != rightbloat.x ? -rightbloat.x : -rightbloat.y);" ); |
311 | |
312 | v->codeAppend ("bool2 left_right_notequal = notEqual(leftbloat, rightbloat);" ); |
313 | |
314 | v->codeAppend ("float2 bloatdir = leftbloat;" ); |
315 | |
316 | v->codeAppend ("float2 leftdir = corner - left;" ); |
317 | v->codeAppend ("leftdir = (float2(0) != leftdir) ? normalize(leftdir) : float2(1, 0);" ); |
318 | |
319 | v->codeAppend ("float2 rightdir = right - corner;" ); |
320 | v->codeAppend ("rightdir = (float2(0) != rightdir) ? normalize(rightdir) : float2(1, 0);" ); |
321 | |
322 | v->codeAppendf("if (0 != (%s & %i)) {" , // Are we a corner? |
323 | proc.fPerVertexData.name(), kVertexData_IsCornerBit); |
324 | |
325 | // In corner boxes, all 4 coverage values will not map linearly. |
326 | // Therefore it is important to align the box so its diagonal shared |
327 | // edge points out of the triangle, in the direction that ramps to 0. |
328 | v->codeAppend ( "bloatdir = float2(leftdir.x > rightdir.x ? +1 : -1, " |
329 | "leftdir.y > rightdir.y ? +1 : -1);" ); |
330 | |
331 | // For corner boxes, we hack left_right_notequal to always true. This |
332 | // in turn causes the upcoming code to always rotate, generating all |
333 | // 4 vertices of the corner box. |
334 | v->codeAppendf( "left_right_notequal = bool2(true);" ); |
335 | v->codeAppend ("}" ); |
336 | |
337 | // At each corner of the polygon, our hull will have either 1, 2, or 3 vertices (or 4 if |
338 | // it's a corner box). We begin with this corner's first raster vertex (leftbloat), then |
339 | // continue rotating 90 degrees clockwise until we reach the desired raster vertex for this |
340 | // invocation. Corners with less than 3 corresponding raster vertices will result in |
341 | // redundant vertices and degenerate triangles. |
342 | v->codeAppendf("int bloatidx = (%s >> %i) & 3;" , proc.fPerVertexData.name(), |
343 | kVertexData_BloatIdxShift); |
344 | v->codeAppend ("switch (bloatidx) {" ); |
345 | v->codeAppend ( "case 3:" ); |
346 | // Only corners will have bloatidx=3, and corners always rotate. |
347 | v->codeAppend ( "bloatdir = float2(-bloatdir.y, +bloatdir.x);" ); // 90 deg CW. |
348 | // fallthru. |
349 | v->codeAppend ( "case 2:" ); |
350 | v->codeAppendf( "if (all(left_right_notequal)) {" ); |
351 | v->codeAppend ( "bloatdir = float2(-bloatdir.y, +bloatdir.x);" ); // 90 deg CW. |
352 | v->codeAppend ( "}" ); |
353 | // fallthru. |
354 | v->codeAppend ( "case 1:" ); |
355 | v->codeAppendf( "if (any(left_right_notequal)) {" ); |
356 | v->codeAppend ( "bloatdir = float2(-bloatdir.y, +bloatdir.x);" ); // 90 deg CW. |
357 | v->codeAppend ( "}" ); |
358 | // fallthru. |
359 | v->codeAppend ("}" ); |
360 | |
361 | v->codeAppend ("float2 vertexpos = fma(bloatdir, float2(bloat), corner);" ); |
362 | gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos" ); |
363 | |
364 | // Hulls have a coverage of +1 all around. |
365 | v->codeAppend ("half coverage = +1;" ); |
366 | |
367 | if (3 == fNumSides) { |
368 | v->codeAppend ("half left_coverage; {" ); |
369 | Shader::CalcEdgeCoverageAtBloatVertex(v, "left" , "corner" , "bloatdir" , "left_coverage" ); |
370 | v->codeAppend ("}" ); |
371 | |
372 | v->codeAppend ("half right_coverage; {" ); |
373 | Shader::CalcEdgeCoverageAtBloatVertex(v, "corner" , "right" , "bloatdir" , "right_coverage" ); |
374 | v->codeAppend ("}" ); |
375 | |
376 | v->codeAppendf("if (0 != (%s & %i)) {" , // Are we an edge? |
377 | proc.fPerVertexData.name(), kVertexData_IsEdgeBit); |
378 | v->codeAppend ( "coverage = left_coverage;" ); |
379 | v->codeAppend ("}" ); |
380 | |
381 | v->codeAppendf("if (0 != (%s & %i)) {" , // Invert coverage? |
382 | proc.fPerVertexData.name(), |
383 | kVertexData_InvertNegativeCoverageBit); |
384 | v->codeAppend ( "coverage = -1 - coverage;" ); |
385 | v->codeAppend ("}" ); |
386 | } else if (!fShader->calculatesOwnEdgeCoverage()) { |
387 | // Determine the amount of coverage to subtract out for the flat edge of the curve. |
388 | v->codeAppendf("float2 p0 = pts[0], p1 = pts[%i];" , numInputPoints - 1); |
389 | v->codeAppendf("float2 n = float2(p0.y - p1.y, p1.x - p0.x);" ); |
390 | v->codeAppend ("float nwidth = bloat*2 * (abs(n.x) + abs(n.y));" ); |
391 | // When nwidth=0, wind must also be 0 (and coverage * wind = 0). So it doesn't matter |
392 | // what we come up with here as long as it isn't NaN or Inf. |
393 | v->codeAppend ("float d = dot(p0 - vertexpos, n);" ); |
394 | v->codeAppend ("d /= (0 != nwidth) ? nwidth : 1;" ); |
395 | v->codeAppend ("coverage = half(d) - .5*sign(wind);" ); |
396 | } |
397 | |
398 | // Non-corner geometry should have zero effect from corner coverage. |
399 | v->codeAppend ("half2 corner_coverage = half2(0);" ); |
400 | |
401 | v->codeAppendf("if (0 != (%s & %i)) {" , // Are we a corner? |
402 | proc.fPerVertexData.name(), kVertexData_IsCornerBit); |
403 | // Erase what the previous geometry wrote. |
404 | v->codeAppend ( "wind = -wind;" ); |
405 | if (3 == fNumSides) { |
406 | v->codeAppend ("coverage = 1 + left_coverage + right_coverage;" ); |
407 | } else if (!fShader->calculatesOwnEdgeCoverage()) { |
408 | v->codeAppend ("coverage = -coverage;" ); |
409 | } |
410 | |
411 | // Corner boxes require attenuated coverage. |
412 | v->codeAppend ( "half attenuation; {" ); |
413 | Shader::CalcCornerAttenuation(v, "leftdir" , "rightdir" , "attenuation" ); |
414 | v->codeAppend ( "}" ); |
415 | |
416 | // Attenuate corner coverage towards the outermost vertex (where bloatidx=0). |
417 | // This is all that curves need: At each vertex of the corner box, the curve |
418 | // Shader will calculate the curve's local coverage value, interpolate it |
419 | // alongside our attenuation parameter, and multiply the two together for a |
420 | // final coverage value. |
421 | v->codeAppend ( "corner_coverage = (0 == bloatidx) ? half2(0, attenuation) : half2(-1,+1);" ); |
422 | |
423 | if (3 == fNumSides) { |
424 | // For triangles we also provide the actual coverage values at each vertex of |
425 | // the corner box. |
426 | v->codeAppend ("if (1 == bloatidx || 2 == bloatidx) {" ); |
427 | v->codeAppend ( "corner_coverage.x -= right_coverage;" ); |
428 | v->codeAppend ("}" ); |
429 | v->codeAppend ("if (bloatidx >= 2) {" ); |
430 | v->codeAppend ( "corner_coverage.x -= left_coverage;" ); |
431 | v->codeAppend ("}" ); |
432 | } |
433 | v->codeAppend ("}" ); |
434 | |
435 | GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; |
436 | v->codeAppend ("coverage *= wind;" ); |
437 | v->codeAppend ("corner_coverage.x *= wind;" ); |
438 | fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag, &AccessCodeString(v), |
439 | "vertexpos" , "coverage" , "corner_coverage" , "wind" ); |
440 | |
441 | varyingHandler->emitAttributes(proc); |
442 | SkASSERT(!*args.fFPCoordTransformHandler); |
443 | |
444 | // Fragment shader. |
445 | GrGLSLFPFragmentBuilder* f = args.fFragBuilder; |
446 | f->codeAppendf("half coverage;" ); |
447 | fShader->emitFragmentCoverageCode(f, "coverage" ); |
448 | f->codeAppendf("%s = half4(coverage);" , args.fOutputColor); |
449 | f->codeAppendf("%s = half4(1);" , args.fOutputCoverage); |
450 | } |
451 | |
452 | void GrVSCoverageProcessor::reset(PrimitiveType primitiveType, int subpassIdx, |
453 | GrResourceProvider* rp) { |
454 | SkASSERT(subpassIdx == 0); |
455 | const GrCaps& caps = *rp->caps(); |
456 | |
457 | fPrimitiveType = primitiveType; |
458 | switch (fPrimitiveType) { |
459 | case PrimitiveType::kTriangles: |
460 | case PrimitiveType::kWeightedTriangles: { |
461 | GR_DEFINE_STATIC_UNIQUE_KEY(gTriangleVertexBufferKey); |
462 | fVertexBuffer = rp->findOrMakeStaticBuffer( |
463 | GrGpuBufferType::kVertex, sizeof(kTriangleVertices), kTriangleVertices, |
464 | gTriangleVertexBufferKey); |
465 | GR_DEFINE_STATIC_UNIQUE_KEY(gTriangleIndexBufferKey); |
466 | if (caps.usePrimitiveRestart()) { |
467 | fIndexBuffer = rp->findOrMakeStaticBuffer( |
468 | GrGpuBufferType::kIndex, sizeof(kTriangleIndicesAsStrips), |
469 | kTriangleIndicesAsStrips, gTriangleIndexBufferKey); |
470 | fNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsStrips); |
471 | } else { |
472 | fIndexBuffer = rp->findOrMakeStaticBuffer( |
473 | GrGpuBufferType::kIndex, sizeof(kTriangleIndicesAsTris), |
474 | kTriangleIndicesAsTris, gTriangleIndexBufferKey); |
475 | fNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsTris); |
476 | } |
477 | break; |
478 | } |
479 | |
480 | case PrimitiveType::kQuadratics: |
481 | case PrimitiveType::kCubics: |
482 | case PrimitiveType::kConics: { |
483 | GR_DEFINE_STATIC_UNIQUE_KEY(gCurveVertexBufferKey); |
484 | fVertexBuffer = rp->findOrMakeStaticBuffer( |
485 | GrGpuBufferType::kVertex, sizeof(kCurveVertices), kCurveVertices, |
486 | gCurveVertexBufferKey); |
487 | GR_DEFINE_STATIC_UNIQUE_KEY(gCurveIndexBufferKey); |
488 | if (caps.usePrimitiveRestart()) { |
489 | fIndexBuffer = rp->findOrMakeStaticBuffer( |
490 | GrGpuBufferType::kIndex, sizeof(kCurveIndicesAsStrips), |
491 | kCurveIndicesAsStrips, gCurveIndexBufferKey); |
492 | fNumIndicesPerInstance = SK_ARRAY_COUNT(kCurveIndicesAsStrips); |
493 | } else { |
494 | fIndexBuffer = rp->findOrMakeStaticBuffer( |
495 | GrGpuBufferType::kIndex, sizeof(kCurveIndicesAsTris), kCurveIndicesAsTris, |
496 | gCurveIndexBufferKey); |
497 | fNumIndicesPerInstance = SK_ARRAY_COUNT(kCurveIndicesAsTris); |
498 | } |
499 | break; |
500 | } |
501 | } |
502 | |
503 | GrVertexAttribType xyAttribType; |
504 | GrSLType xySLType; |
505 | if (4 == this->numInputPoints() || this->hasInputWeight()) { |
506 | static_assert(offsetof(QuadPointInstance, fX) == 0); |
507 | static_assert(sizeof(QuadPointInstance::fX) == |
508 | GrVertexAttribTypeSize(kFloat4_GrVertexAttribType)); |
509 | static_assert(sizeof(QuadPointInstance::fY) == |
510 | GrVertexAttribTypeSize(kFloat4_GrVertexAttribType)); |
511 | xyAttribType = kFloat4_GrVertexAttribType; |
512 | xySLType = kFloat4_GrSLType; |
513 | } else { |
514 | static_assert(sizeof(TriPointInstance) == |
515 | 2 * GrVertexAttribTypeSize(kFloat3_GrVertexAttribType)); |
516 | xyAttribType = kFloat3_GrVertexAttribType; |
517 | xySLType = kFloat3_GrSLType; |
518 | } |
519 | fInputXAndYValues[kInstanceAttribIdx_X] = {"X" , xyAttribType, xySLType}; |
520 | fInputXAndYValues[kInstanceAttribIdx_Y] = {"Y" , xyAttribType, xySLType}; |
521 | this->setInstanceAttributes(fInputXAndYValues, 2); |
522 | fPerVertexData = {"vertexdata" , kInt_GrVertexAttribType, kInt_GrSLType}; |
523 | this->setVertexAttributes(&fPerVertexData, 1); |
524 | |
525 | if (caps.usePrimitiveRestart()) { |
526 | fTriangleType = GrPrimitiveType::kTriangleStrip; |
527 | } else { |
528 | fTriangleType = GrPrimitiveType::kTriangles; |
529 | } |
530 | } |
531 | |
532 | void GrVSCoverageProcessor::bindBuffers(GrOpsRenderPass* renderPass, |
533 | sk_sp<const GrBuffer> instanceBuffer) const { |
534 | SkASSERT(fTriangleType == GrPrimitiveType::kTriangles || |
535 | fTriangleType == GrPrimitiveType::kTriangleStrip); |
536 | renderPass->bindBuffers(fIndexBuffer, std::move(instanceBuffer), fVertexBuffer, |
537 | GrPrimitiveRestart(GrPrimitiveType::kTriangleStrip == fTriangleType)); |
538 | } |
539 | |
540 | void GrVSCoverageProcessor::drawInstances(GrOpsRenderPass* renderPass, int instanceCount, |
541 | int baseInstance) const { |
542 | renderPass->drawIndexedInstanced(fNumIndicesPerInstance, 0, instanceCount, baseInstance, 0); |
543 | } |
544 | |
545 | GrGLSLPrimitiveProcessor* GrVSCoverageProcessor::onCreateGLSLInstance( |
546 | std::unique_ptr<Shader> shader) const { |
547 | switch (fPrimitiveType) { |
548 | case PrimitiveType::kTriangles: |
549 | case PrimitiveType::kWeightedTriangles: |
550 | return new Impl(std::move(shader), 3); |
551 | case PrimitiveType::kQuadratics: |
552 | case PrimitiveType::kCubics: |
553 | case PrimitiveType::kConics: |
554 | return new Impl(std::move(shader), 4); |
555 | } |
556 | SK_ABORT("Invalid PrimitiveType" ); |
557 | } |
558 | |