• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/GrCCFiller.h"
9 
10 #include "include/core/SkPath.h"
11 #include "include/core/SkPoint.h"
12 #include "src/core/SkMathPriv.h"
13 #include "src/core/SkPathPriv.h"
14 #include "src/gpu/GrCaps.h"
15 #include "src/gpu/GrGpuCommandBuffer.h"
16 #include "src/gpu/GrOnFlushResourceProvider.h"
17 #include "src/gpu/GrOpFlushState.h"
18 #include <stdlib.h>
19 
20 using TriPointInstance = GrCCCoverageProcessor::TriPointInstance;
21 using QuadPointInstance = GrCCCoverageProcessor::QuadPointInstance;
22 
GrCCFiller(Algorithm algorithm,int numPaths,int numSkPoints,int numSkVerbs,int numConicWeights)23 GrCCFiller::GrCCFiller(Algorithm algorithm, int numPaths, int numSkPoints, int numSkVerbs,
24                        int numConicWeights)
25         : fAlgorithm(algorithm)
26         , fGeometry(numSkPoints, numSkVerbs, numConicWeights)
27         , fPathInfos(numPaths)
28         , fScissorSubBatches(numPaths)
29         , fTotalPrimitiveCounts{PrimitiveTallies(), PrimitiveTallies()} {
30     // Batches decide what to draw by looking where the previous one ended. Define initial batches
31     // that "end" at the beginning of the data. These will not be drawn, but will only be be read by
32     // the first actual batch.
33     fScissorSubBatches.push_back() = {PrimitiveTallies(), SkIRect::MakeEmpty()};
34     fBatches.push_back() = {PrimitiveTallies(), fScissorSubBatches.count(), PrimitiveTallies()};
35 }
36 
parseDeviceSpaceFill(const SkPath & path,const SkPoint * deviceSpacePts,GrScissorTest scissorTest,const SkIRect & clippedDevIBounds,const SkIVector & devToAtlasOffset)37 void GrCCFiller::parseDeviceSpaceFill(const SkPath& path, const SkPoint* deviceSpacePts,
38                                       GrScissorTest scissorTest, const SkIRect& clippedDevIBounds,
39                                       const SkIVector& devToAtlasOffset) {
40     SkASSERT(!fInstanceBuffer);  // Can't call after prepareToDraw().
41     SkASSERT(!path.isEmpty());
42 
43     int currPathPointsIdx = fGeometry.points().count();
44     int currPathVerbsIdx = fGeometry.verbs().count();
45     PrimitiveTallies currPathPrimitiveCounts = PrimitiveTallies();
46 
47     fGeometry.beginPath();
48 
49     const float* conicWeights = SkPathPriv::ConicWeightData(path);
50     int ptsIdx = 0;
51     int conicWeightsIdx = 0;
52     bool insideContour = false;
53 
54     for (SkPath::Verb verb : SkPathPriv::Verbs(path)) {
55         switch (verb) {
56             case SkPath::kMove_Verb:
57                 if (insideContour) {
58                     currPathPrimitiveCounts += fGeometry.endContour();
59                 }
60                 fGeometry.beginContour(deviceSpacePts[ptsIdx]);
61                 ++ptsIdx;
62                 insideContour = true;
63                 continue;
64             case SkPath::kClose_Verb:
65                 if (insideContour) {
66                     currPathPrimitiveCounts += fGeometry.endContour();
67                 }
68                 insideContour = false;
69                 continue;
70             case SkPath::kLine_Verb:
71                 fGeometry.lineTo(&deviceSpacePts[ptsIdx - 1]);
72                 ++ptsIdx;
73                 continue;
74             case SkPath::kQuad_Verb:
75                 fGeometry.quadraticTo(&deviceSpacePts[ptsIdx - 1]);
76                 ptsIdx += 2;
77                 continue;
78             case SkPath::kCubic_Verb:
79                 fGeometry.cubicTo(&deviceSpacePts[ptsIdx - 1]);
80                 ptsIdx += 3;
81                 continue;
82             case SkPath::kConic_Verb:
83                 fGeometry.conicTo(&deviceSpacePts[ptsIdx - 1], conicWeights[conicWeightsIdx]);
84                 ptsIdx += 2;
85                 ++conicWeightsIdx;
86                 continue;
87             default:
88                 SK_ABORT("Unexpected path verb.");
89         }
90     }
91     SkASSERT(ptsIdx == path.countPoints());
92     SkASSERT(conicWeightsIdx == SkPathPriv::ConicWeightCnt(path));
93 
94     if (insideContour) {
95         currPathPrimitiveCounts += fGeometry.endContour();
96     }
97 
98     fPathInfos.emplace_back(scissorTest, devToAtlasOffset);
99 
100     // Tessellate fans from very large and/or simple paths, in order to reduce overdraw.
101     int numVerbs = fGeometry.verbs().count() - currPathVerbsIdx - 1;
102     int64_t tessellationWork = (int64_t)numVerbs * (32 - SkCLZ(numVerbs)); // N log N.
103     int64_t fanningWork = (int64_t)clippedDevIBounds.height() * clippedDevIBounds.width();
104     if (tessellationWork * (50*50) + (100*100) < fanningWork) { // Don't tessellate under 100x100.
105         fPathInfos.back().tessellateFan(
106                 fAlgorithm, path, fGeometry, currPathVerbsIdx, currPathPointsIdx, clippedDevIBounds,
107                 &currPathPrimitiveCounts);
108     }
109 
110     fTotalPrimitiveCounts[(int)scissorTest] += currPathPrimitiveCounts;
111 
112     if (GrScissorTest::kEnabled == scissorTest) {
113         fScissorSubBatches.push_back() = {fTotalPrimitiveCounts[(int)GrScissorTest::kEnabled],
114                                           clippedDevIBounds.makeOffset(devToAtlasOffset.fX,
115                                                                        devToAtlasOffset.fY)};
116     }
117 }
118 
tessellateFan(Algorithm algorithm,const SkPath & originalPath,const GrCCFillGeometry & geometry,int verbsIdx,int ptsIdx,const SkIRect & clippedDevIBounds,PrimitiveTallies * newTriangleCounts)119 void GrCCFiller::PathInfo::tessellateFan(
120         Algorithm algorithm, const SkPath& originalPath, const GrCCFillGeometry& geometry,
121         int verbsIdx, int ptsIdx, const SkIRect& clippedDevIBounds,
122         PrimitiveTallies* newTriangleCounts) {
123     using Verb = GrCCFillGeometry::Verb;
124     SkASSERT(-1 == fFanTessellationCount);
125     SkASSERT(!fFanTessellation);
126 
127     const SkTArray<Verb, true>& verbs = geometry.verbs();
128     const SkTArray<SkPoint, true>& pts = geometry.points();
129 
130     newTriangleCounts->fTriangles =
131             newTriangleCounts->fWeightedTriangles = 0;
132 
133     // Build an SkPath of the Redbook fan.
134     SkPath fan;
135     if (Algorithm::kCoverageCount == algorithm) {
136         // We use "winding" fill type right now because we are producing a coverage count, and must
137         // fill in every region that has non-zero wind. The path processor will convert coverage
138         // count to the appropriate fill type later.
139         fan.setFillType(SkPath::kWinding_FillType);
140     } else {
141         // When counting winding numbers in the stencil buffer, it works to just tessellate the
142         // Redbook fan with the same fill type as the path.
143         fan.setFillType(originalPath.getFillType());
144     }
145     SkASSERT(Verb::kBeginPath == verbs[verbsIdx]);
146     for (int i = verbsIdx + 1; i < verbs.count(); ++i) {
147         switch (verbs[i]) {
148             case Verb::kBeginPath:
149                 SK_ABORT("Invalid GrCCFillGeometry");
150                 continue;
151 
152             case Verb::kBeginContour:
153                 fan.moveTo(pts[ptsIdx++]);
154                 continue;
155 
156             case Verb::kLineTo:
157                 fan.lineTo(pts[ptsIdx++]);
158                 continue;
159 
160             case Verb::kMonotonicQuadraticTo:
161             case Verb::kMonotonicConicTo:
162                 fan.lineTo(pts[ptsIdx + 1]);
163                 ptsIdx += 2;
164                 continue;
165 
166             case Verb::kMonotonicCubicTo:
167                 fan.lineTo(pts[ptsIdx + 2]);
168                 ptsIdx += 3;
169                 continue;
170 
171             case Verb::kEndClosedContour:
172             case Verb::kEndOpenContour:
173                 fan.close();
174                 continue;
175         }
176     }
177 
178     GrTessellator::WindingVertex* vertices = nullptr;
179     fFanTessellationCount =
180             GrTessellator::PathToVertices(fan, std::numeric_limits<float>::infinity(),
181                                           SkRect::Make(clippedDevIBounds), &vertices);
182     if (fFanTessellationCount <= 0) {
183         SkASSERT(0 == fFanTessellationCount);
184         SkASSERT(nullptr == vertices);
185         return;
186     }
187 
188     SkASSERT(0 == fFanTessellationCount % 3);
189     for (int i = 0; i < fFanTessellationCount; i += 3) {
190         int tessWinding = vertices[i].fWinding;
191         SkASSERT(tessWinding == vertices[i + 1].fWinding);
192         SkASSERT(tessWinding == vertices[i + 2].fWinding);
193 
194         // Ensure this triangle's points actually wind in the same direction as tessWinding.
195         // CCPR shaders use the sign of wind to determine which direction to bloat, so even for
196         // "wound" triangles the winding sign and point ordering need to agree.
197         float ax = vertices[i].fPos.fX - vertices[i + 1].fPos.fX;
198         float ay = vertices[i].fPos.fY - vertices[i + 1].fPos.fY;
199         float bx = vertices[i].fPos.fX - vertices[i + 2].fPos.fX;
200         float by = vertices[i].fPos.fY - vertices[i + 2].fPos.fY;
201         float wind = ax*by - ay*bx;
202         if ((wind > 0) != (-tessWinding > 0)) { // Tessellator has opposite winding sense.
203             std::swap(vertices[i + 1].fPos, vertices[i + 2].fPos);
204         }
205 
206         int weight = abs(tessWinding);
207         SkASSERT(SkPath::kEvenOdd_FillType != fan.getFillType() || weight == 1);
208         if (weight > 1 && Algorithm::kCoverageCount == algorithm) {
209             ++newTriangleCounts->fWeightedTriangles;
210         } else {
211             newTriangleCounts->fTriangles += weight;
212         }
213     }
214 
215     fFanTessellation.reset(vertices);
216 }
217 
closeCurrentBatch()218 GrCCFiller::BatchID GrCCFiller::closeCurrentBatch() {
219     SkASSERT(!fInstanceBuffer);
220     SkASSERT(!fBatches.empty());
221 
222     const auto& lastBatch = fBatches.back();
223     int maxMeshes = 1 + fScissorSubBatches.count() - lastBatch.fEndScissorSubBatchIdx;
224     fMaxMeshesPerDraw = SkTMax(fMaxMeshesPerDraw, maxMeshes);
225 
226     const auto& lastScissorSubBatch = fScissorSubBatches[lastBatch.fEndScissorSubBatchIdx - 1];
227     PrimitiveTallies batchTotalCounts = fTotalPrimitiveCounts[(int)GrScissorTest::kDisabled] -
228                                         lastBatch.fEndNonScissorIndices;
229     batchTotalCounts += fTotalPrimitiveCounts[(int)GrScissorTest::kEnabled] -
230                         lastScissorSubBatch.fEndPrimitiveIndices;
231 
232     // This will invalidate lastBatch.
233     fBatches.push_back() = {
234         fTotalPrimitiveCounts[(int)GrScissorTest::kDisabled],
235         fScissorSubBatches.count(),
236         batchTotalCounts
237     };
238     return fBatches.count() - 1;
239 }
240 
241 // Emits a contour's triangle fan.
242 //
243 // Classic Redbook fanning would be the triangles: [0  1  2], [0  2  3], ..., [0  n-2  n-1].
244 //
245 // This function emits the triangle: [0  n/3  n*2/3], and then recurses on all three sides. The
246 // advantage to this approach is that for a convex-ish contour, it generates larger triangles.
247 // Classic fanning tends to generate long, skinny triangles, which are expensive to draw since they
248 // have a longer perimeter to rasterize and antialias.
249 //
250 // The indices array indexes the fan's points (think: glDrawElements), and must have at least log3
251 // elements past the end for this method to use as scratch space.
252 //
253 // Returns the next triangle instance after the final one emitted.
emit_recursive_fan(const SkTArray<SkPoint,true> & pts,SkTArray<int32_t,true> & indices,int firstIndex,int indexCount,const Sk2f & devToAtlasOffset,TriPointInstance::Ordering ordering,TriPointInstance out[])254 static TriPointInstance* emit_recursive_fan(
255         const SkTArray<SkPoint, true>& pts, SkTArray<int32_t, true>& indices, int firstIndex,
256         int indexCount, const Sk2f& devToAtlasOffset, TriPointInstance::Ordering ordering,
257         TriPointInstance out[]) {
258     if (indexCount < 3) {
259         return out;
260     }
261 
262     int32_t oneThirdCount = indexCount / 3;
263     int32_t twoThirdsCount = (2 * indexCount) / 3;
264     out++->set(pts[indices[firstIndex]], pts[indices[firstIndex + oneThirdCount]],
265                pts[indices[firstIndex + twoThirdsCount]], devToAtlasOffset, ordering);
266 
267     out = emit_recursive_fan(
268             pts, indices, firstIndex, oneThirdCount + 1, devToAtlasOffset, ordering, out);
269     out = emit_recursive_fan(
270             pts, indices, firstIndex + oneThirdCount, twoThirdsCount - oneThirdCount + 1,
271             devToAtlasOffset, ordering, out);
272 
273     int endIndex = firstIndex + indexCount;
274     int32_t oldValue = indices[endIndex];
275     indices[endIndex] = indices[firstIndex];
276     out = emit_recursive_fan(
277             pts, indices, firstIndex + twoThirdsCount, indexCount - twoThirdsCount + 1,
278             devToAtlasOffset, ordering, out);
279     indices[endIndex] = oldValue;
280 
281     return out;
282 }
283 
emitTessellatedFan(const GrTessellator::WindingVertex * vertices,int numVertices,const Sk2f & devToAtlasOffset,TriPointInstance::Ordering ordering,TriPointInstance * triPointInstanceData,QuadPointInstance * quadPointInstanceData,GrCCFillGeometry::PrimitiveTallies * indices)284 void GrCCFiller::emitTessellatedFan(
285         const GrTessellator::WindingVertex* vertices, int numVertices, const Sk2f& devToAtlasOffset,
286         TriPointInstance::Ordering ordering, TriPointInstance* triPointInstanceData,
287         QuadPointInstance* quadPointInstanceData, GrCCFillGeometry::PrimitiveTallies* indices) {
288     for (int i = 0; i < numVertices; i += 3) {
289         int weight = abs(vertices[i].fWinding);
290         SkASSERT(weight >= 1);
291         if (weight > 1 && Algorithm::kStencilWindingCount != fAlgorithm) {
292             quadPointInstanceData[indices->fWeightedTriangles++].setW(
293                     vertices[i].fPos, vertices[i+1].fPos, vertices[i + 2].fPos, devToAtlasOffset,
294                     static_cast<float>(abs(vertices[i].fWinding)));
295         } else for (int j = 0; j < weight; ++j) {
296             // Unfortunately, there is not a way to increment stencil values by an amount larger
297             // than 1. Instead we draw the triangle 'weight' times.
298             triPointInstanceData[indices->fTriangles++].set(
299                     vertices[i].fPos, vertices[i + 1].fPos, vertices[i + 2].fPos, devToAtlasOffset,
300                     ordering);
301         }
302     }
303 }
304 
prepareToDraw(GrOnFlushResourceProvider * onFlushRP)305 bool GrCCFiller::prepareToDraw(GrOnFlushResourceProvider* onFlushRP) {
306     using Verb = GrCCFillGeometry::Verb;
307     SkASSERT(!fInstanceBuffer);
308     SkASSERT(fBatches.back().fEndNonScissorIndices == // Call closeCurrentBatch().
309              fTotalPrimitiveCounts[(int)GrScissorTest::kDisabled]);
310     SkASSERT(fBatches.back().fEndScissorSubBatchIdx == fScissorSubBatches.count());
311 
312     auto triangleOrdering = (Algorithm::kCoverageCount == fAlgorithm)
313             ? TriPointInstance::Ordering::kXYTransposed
314             : TriPointInstance::Ordering::kXYInterleaved;
315 
316     // Here we build a single instance buffer to share with every internal batch.
317     //
318     // CCPR processs 3 different types of primitives: triangles, quadratics, cubics. Each primitive
319     // type is further divided into instances that require a scissor and those that don't. This
320     // leaves us with 3*2 = 6 independent instance arrays to build for the GPU.
321     //
322     // Rather than place each instance array in its own GPU buffer, we allocate a single
323     // megabuffer and lay them all out side-by-side. We can offset the "baseInstance" parameter in
324     // our draw calls to direct the GPU to the applicable elements within a given array.
325     //
326     // We already know how big to make each of the 6 arrays from fTotalPrimitiveCounts, so layout is
327     // straightforward. Start with triangles and quadratics. They both view the instance buffer as
328     // an array of TriPointInstance[], so we can begin at zero and lay them out one after the other.
329     fBaseInstances[0].fTriangles = 0;
330     fBaseInstances[1].fTriangles = fBaseInstances[0].fTriangles +
331                                    fTotalPrimitiveCounts[0].fTriangles;
332     fBaseInstances[0].fQuadratics = fBaseInstances[1].fTriangles +
333                                     fTotalPrimitiveCounts[1].fTriangles;
334     fBaseInstances[1].fQuadratics = fBaseInstances[0].fQuadratics +
335                                     fTotalPrimitiveCounts[0].fQuadratics;
336     int triEndIdx = fBaseInstances[1].fQuadratics + fTotalPrimitiveCounts[1].fQuadratics;
337 
338     // Wound triangles and cubics both view the same instance buffer as an array of
339     // QuadPointInstance[]. So, reinterpreting the instance data as QuadPointInstance[], we start
340     // them on the first index that will not overwrite previous TriPointInstance data.
341     int quadBaseIdx =
342             GrSizeDivRoundUp(triEndIdx * sizeof(TriPointInstance), sizeof(QuadPointInstance));
343     fBaseInstances[0].fWeightedTriangles = quadBaseIdx;
344     fBaseInstances[1].fWeightedTriangles = fBaseInstances[0].fWeightedTriangles +
345                                         fTotalPrimitiveCounts[0].fWeightedTriangles;
346     fBaseInstances[0].fCubics = fBaseInstances[1].fWeightedTriangles +
347                                 fTotalPrimitiveCounts[1].fWeightedTriangles;
348     fBaseInstances[1].fCubics = fBaseInstances[0].fCubics + fTotalPrimitiveCounts[0].fCubics;
349     fBaseInstances[0].fConics = fBaseInstances[1].fCubics + fTotalPrimitiveCounts[1].fCubics;
350     fBaseInstances[1].fConics = fBaseInstances[0].fConics + fTotalPrimitiveCounts[0].fConics;
351     int quadEndIdx = fBaseInstances[1].fConics + fTotalPrimitiveCounts[1].fConics;
352 
353     fInstanceBuffer =
354             onFlushRP->makeBuffer(GrGpuBufferType::kVertex, quadEndIdx * sizeof(QuadPointInstance));
355     if (!fInstanceBuffer) {
356         SkDebugf("WARNING: failed to allocate CCPR fill instance buffer.\n");
357         return false;
358     }
359 
360     TriPointInstance* triPointInstanceData = static_cast<TriPointInstance*>(fInstanceBuffer->map());
361     QuadPointInstance* quadPointInstanceData =
362             reinterpret_cast<QuadPointInstance*>(triPointInstanceData);
363     SkASSERT(quadPointInstanceData);
364 
365     PathInfo* nextPathInfo = fPathInfos.begin();
366     Sk2f devToAtlasOffset;
367     PrimitiveTallies instanceIndices[2] = {fBaseInstances[0], fBaseInstances[1]};
368     PrimitiveTallies* currIndices = nullptr;
369     SkSTArray<256, int32_t, true> currFan;
370     bool currFanIsTessellated = false;
371 
372     const SkTArray<SkPoint, true>& pts = fGeometry.points();
373     int ptsIdx = -1;
374     int nextConicWeightIdx = 0;
375 
376     // Expand the ccpr verbs into GPU instance buffers.
377     for (Verb verb : fGeometry.verbs()) {
378         switch (verb) {
379             case Verb::kBeginPath:
380                 SkASSERT(currFan.empty());
381                 currIndices = &instanceIndices[(int)nextPathInfo->scissorTest()];
382                 devToAtlasOffset = Sk2f(static_cast<float>(nextPathInfo->devToAtlasOffset().fX),
383                                         static_cast<float>(nextPathInfo->devToAtlasOffset().fY));
384                 currFanIsTessellated = nextPathInfo->hasFanTessellation();
385                 if (currFanIsTessellated) {
386                     this->emitTessellatedFan(
387                             nextPathInfo->fanTessellation(), nextPathInfo->fanTessellationCount(),
388                             devToAtlasOffset, triangleOrdering, triPointInstanceData,
389                             quadPointInstanceData, currIndices);
390                 }
391                 ++nextPathInfo;
392                 continue;
393 
394             case Verb::kBeginContour:
395                 SkASSERT(currFan.empty());
396                 ++ptsIdx;
397                 if (!currFanIsTessellated) {
398                     currFan.push_back(ptsIdx);
399                 }
400                 continue;
401 
402             case Verb::kLineTo:
403                 ++ptsIdx;
404                 if (!currFanIsTessellated) {
405                     SkASSERT(!currFan.empty());
406                     currFan.push_back(ptsIdx);
407                 }
408                 continue;
409 
410             case Verb::kMonotonicQuadraticTo:
411                 triPointInstanceData[currIndices->fQuadratics++].set(
412                         &pts[ptsIdx], devToAtlasOffset, TriPointInstance::Ordering::kXYTransposed);
413                 ptsIdx += 2;
414                 if (!currFanIsTessellated) {
415                     SkASSERT(!currFan.empty());
416                     currFan.push_back(ptsIdx);
417                 }
418                 continue;
419 
420             case Verb::kMonotonicCubicTo:
421                 quadPointInstanceData[currIndices->fCubics++].set(
422                         &pts[ptsIdx], devToAtlasOffset[0], devToAtlasOffset[1]);
423                 ptsIdx += 3;
424                 if (!currFanIsTessellated) {
425                     SkASSERT(!currFan.empty());
426                     currFan.push_back(ptsIdx);
427                 }
428                 continue;
429 
430             case Verb::kMonotonicConicTo:
431                 quadPointInstanceData[currIndices->fConics++].setW(
432                         &pts[ptsIdx], devToAtlasOffset,
433                         fGeometry.getConicWeight(nextConicWeightIdx));
434                 ptsIdx += 2;
435                 ++nextConicWeightIdx;
436                 if (!currFanIsTessellated) {
437                     SkASSERT(!currFan.empty());
438                     currFan.push_back(ptsIdx);
439                 }
440                 continue;
441 
442             case Verb::kEndClosedContour:  // endPt == startPt.
443                 if (!currFanIsTessellated) {
444                     SkASSERT(!currFan.empty());
445                     currFan.pop_back();
446                 }
447             // fallthru.
448             case Verb::kEndOpenContour:  // endPt != startPt.
449                 SkASSERT(!currFanIsTessellated || currFan.empty());
450                 if (!currFanIsTessellated && currFan.count() >= 3) {
451                     int fanSize = currFan.count();
452                     // Reserve space for emit_recursive_fan. Technically this can grow to
453                     // fanSize + log3(fanSize), but we approximate with log2.
454                     currFan.push_back_n(SkNextLog2(fanSize));
455                     SkDEBUGCODE(TriPointInstance* end =) emit_recursive_fan(
456                             pts, currFan, 0, fanSize, devToAtlasOffset, triangleOrdering,
457                             triPointInstanceData + currIndices->fTriangles);
458                     currIndices->fTriangles += fanSize - 2;
459                     SkASSERT(triPointInstanceData + currIndices->fTriangles == end);
460                 }
461                 currFan.reset();
462                 continue;
463         }
464     }
465 
466     fInstanceBuffer->unmap();
467 
468     SkASSERT(nextPathInfo == fPathInfos.end());
469     SkASSERT(ptsIdx == pts.count() - 1);
470     SkASSERT(instanceIndices[0].fTriangles == fBaseInstances[1].fTriangles);
471     SkASSERT(instanceIndices[1].fTriangles == fBaseInstances[0].fQuadratics);
472     SkASSERT(instanceIndices[0].fQuadratics == fBaseInstances[1].fQuadratics);
473     SkASSERT(instanceIndices[1].fQuadratics == triEndIdx);
474     SkASSERT(instanceIndices[0].fWeightedTriangles == fBaseInstances[1].fWeightedTriangles);
475     SkASSERT(instanceIndices[1].fWeightedTriangles == fBaseInstances[0].fCubics);
476     SkASSERT(instanceIndices[0].fCubics == fBaseInstances[1].fCubics);
477     SkASSERT(instanceIndices[1].fCubics == fBaseInstances[0].fConics);
478     SkASSERT(instanceIndices[0].fConics == fBaseInstances[1].fConics);
479     SkASSERT(instanceIndices[1].fConics == quadEndIdx);
480 
481     fMeshesScratchBuffer.reserve(fMaxMeshesPerDraw);
482     fScissorRectScratchBuffer.reserve(fMaxMeshesPerDraw);
483 
484     return true;
485 }
486 
drawFills(GrOpFlushState * flushState,GrCCCoverageProcessor * proc,const GrPipeline & pipeline,BatchID batchID,const SkIRect & drawBounds) const487 void GrCCFiller::drawFills(
488         GrOpFlushState* flushState, GrCCCoverageProcessor* proc, const GrPipeline& pipeline,
489         BatchID batchID, const SkIRect& drawBounds) const {
490     using PrimitiveType = GrCCCoverageProcessor::PrimitiveType;
491 
492     SkASSERT(fInstanceBuffer);
493 
494     GrResourceProvider* rp = flushState->resourceProvider();
495     const PrimitiveTallies& batchTotalCounts = fBatches[batchID].fTotalPrimitiveCounts;
496 
497     if (batchTotalCounts.fTriangles) {
498         proc->reset(PrimitiveType::kTriangles, rp);
499         this->drawPrimitives(
500                 flushState, *proc, pipeline, batchID, &PrimitiveTallies::fTriangles, drawBounds);
501     }
502 
503     if (batchTotalCounts.fWeightedTriangles) {
504         SkASSERT(Algorithm::kStencilWindingCount != fAlgorithm);
505         proc->reset(PrimitiveType::kWeightedTriangles, rp);
506         this->drawPrimitives(
507                 flushState, *proc, pipeline, batchID, &PrimitiveTallies::fWeightedTriangles,
508                 drawBounds);
509     }
510 
511     if (batchTotalCounts.fQuadratics) {
512         proc->reset(PrimitiveType::kQuadratics, rp);
513         this->drawPrimitives(
514                 flushState, *proc, pipeline, batchID, &PrimitiveTallies::fQuadratics, drawBounds);
515     }
516 
517     if (batchTotalCounts.fCubics) {
518         proc->reset(PrimitiveType::kCubics, rp);
519         this->drawPrimitives(
520                 flushState, *proc, pipeline, batchID, &PrimitiveTallies::fCubics, drawBounds);
521     }
522 
523     if (batchTotalCounts.fConics) {
524         proc->reset(PrimitiveType::kConics, rp);
525         this->drawPrimitives(
526                 flushState, *proc, pipeline, batchID, &PrimitiveTallies::fConics, drawBounds);
527     }
528 }
529 
drawPrimitives(GrOpFlushState * flushState,const GrCCCoverageProcessor & proc,const GrPipeline & pipeline,BatchID batchID,int PrimitiveTallies::* instanceType,const SkIRect & drawBounds) const530 void GrCCFiller::drawPrimitives(
531         GrOpFlushState* flushState, const GrCCCoverageProcessor& proc, const GrPipeline& pipeline,
532         BatchID batchID, int PrimitiveTallies::*instanceType, const SkIRect& drawBounds) const {
533     SkASSERT(pipeline.isScissorEnabled());
534 
535     // Don't call reset(), as that also resets the reserve count.
536     fMeshesScratchBuffer.pop_back_n(fMeshesScratchBuffer.count());
537     fScissorRectScratchBuffer.pop_back_n(fScissorRectScratchBuffer.count());
538 
539     SkASSERT(batchID > 0);
540     SkASSERT(batchID < fBatches.count());
541     const Batch& previousBatch = fBatches[batchID - 1];
542     const Batch& batch = fBatches[batchID];
543     SkDEBUGCODE(int totalInstanceCount = 0);
544 
545     if (int instanceCount = batch.fEndNonScissorIndices.*instanceType -
546                             previousBatch.fEndNonScissorIndices.*instanceType) {
547         SkASSERT(instanceCount > 0);
548         int baseInstance = fBaseInstances[(int)GrScissorTest::kDisabled].*instanceType +
549                            previousBatch.fEndNonScissorIndices.*instanceType;
550         proc.appendMesh(fInstanceBuffer, instanceCount, baseInstance, &fMeshesScratchBuffer);
551         fScissorRectScratchBuffer.push_back().setXYWH(0, 0, drawBounds.width(),
552                                                       drawBounds.height());
553         SkDEBUGCODE(totalInstanceCount += instanceCount);
554     }
555 
556     SkASSERT(previousBatch.fEndScissorSubBatchIdx > 0);
557     SkASSERT(batch.fEndScissorSubBatchIdx <= fScissorSubBatches.count());
558     int baseScissorInstance = fBaseInstances[(int)GrScissorTest::kEnabled].*instanceType;
559     for (int i = previousBatch.fEndScissorSubBatchIdx; i < batch.fEndScissorSubBatchIdx; ++i) {
560         const ScissorSubBatch& previousSubBatch = fScissorSubBatches[i - 1];
561         const ScissorSubBatch& scissorSubBatch = fScissorSubBatches[i];
562         int startIndex = previousSubBatch.fEndPrimitiveIndices.*instanceType;
563         int instanceCount = scissorSubBatch.fEndPrimitiveIndices.*instanceType - startIndex;
564         if (!instanceCount) {
565             continue;
566         }
567         SkASSERT(instanceCount > 0);
568         proc.appendMesh(fInstanceBuffer, instanceCount, baseScissorInstance + startIndex,
569                         &fMeshesScratchBuffer);
570         fScissorRectScratchBuffer.push_back() = scissorSubBatch.fScissor;
571         SkDEBUGCODE(totalInstanceCount += instanceCount);
572     }
573 
574     SkASSERT(fMeshesScratchBuffer.count() == fScissorRectScratchBuffer.count());
575     SkASSERT(fMeshesScratchBuffer.count() <= fMaxMeshesPerDraw);
576     SkASSERT(totalInstanceCount == batch.fTotalPrimitiveCounts.*instanceType);
577 
578     if (!fMeshesScratchBuffer.empty()) {
579         proc.draw(flushState, pipeline, fScissorRectScratchBuffer.begin(),
580                   fMeshesScratchBuffer.begin(), fMeshesScratchBuffer.count(),
581                   SkRect::Make(drawBounds));
582     }
583 }
584