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