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