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.
15class GrVSCoverageProcessor::Impl : public GrGLSLGeometryProcessor {
16public:
17 Impl(std::unique_ptr<Shader> shader, int numSides)
18 : fShader(std::move(shader)), fNumSides(numSides) {}
19
20private:
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
29static constexpr int kInstanceAttribIdx_X = 0; // Transposed X values of all input points.
30static 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.
34static constexpr int kVertexData_LeftNeighborIdShift = 10;
35static constexpr int kVertexData_RightNeighborIdShift = 8;
36static constexpr int kVertexData_BloatIdxShift = 6;
37static constexpr int kVertexData_InvertNegativeCoverageBit = 1 << 5;
38static constexpr int kVertexData_IsCornerBit = 1 << 4;
39static constexpr int kVertexData_IsEdgeBit = 1 << 3;
40static constexpr int kVertexData_IsHullBit = 1 << 2;
41
42static constexpr int32_t pack_vertex_data(int32_t leftNeighborID, int32_t rightNeighborID,
43 int32_t bloatIdx, int32_t cornerID,
44 int32_t extraData = 0) {
45 return (leftNeighborID << kVertexData_LeftNeighborIdShift) |
46 (rightNeighborID << kVertexData_RightNeighborIdShift) |
47 (bloatIdx << kVertexData_BloatIdxShift) |
48 cornerID | extraData;
49}
50
51static 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
56static 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
65static 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
70static 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
118GR_DECLARE_STATIC_UNIQUE_KEY(gTriangleVertexBufferKey);
119
120static constexpr uint16_t kRestartStrip = 0xffff;
121
122static 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
133static 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
176GR_DECLARE_STATIC_UNIQUE_KEY(gTriangleIndexBufferKey);
177
178// Curves, including quadratics, are drawn with a four-sided hull.
179static 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
204GR_DECLARE_STATIC_UNIQUE_KEY(gCurveVertexBufferKey);
205
206static 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
213static 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
237GR_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.
251void 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
452void 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
532void 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
540void GrVSCoverageProcessor::drawInstances(GrOpsRenderPass* renderPass, int instanceCount,
541 int baseInstance) const {
542 renderPass->drawIndexedInstanced(fNumIndicesPerInstance, 0, instanceCount, baseInstance, 0);
543}
544
545GrGLSLPrimitiveProcessor* 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