blob: f0a56bba5c38f9763296124d07712a1fba3915ec [file] [log] [blame]
Chris Dalton9ca27842018-01-18 12:24:50 -07001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/ccpr/GrCCFiller.h"
Chris Dalton9ca27842018-01-18 12:24:50 -07009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/gpu/GrOnFlushResourceProvider.h"
16#include "src/gpu/GrOpFlushState.h"
Chris Dalton84403d72018-02-13 21:46:17 -050017#include <stdlib.h>
Chris Dalton9ca27842018-01-18 12:24:50 -070018
Chris Dalton84403d72018-02-13 21:46:17 -050019using TriPointInstance = GrCCCoverageProcessor::TriPointInstance;
20using QuadPointInstance = GrCCCoverageProcessor::QuadPointInstance;
Chris Dalton9ca27842018-01-18 12:24:50 -070021
Chris Daltonc3318f02019-07-19 14:20:53 -060022GrCCFiller::GrCCFiller(Algorithm algorithm, int numPaths, int numSkPoints, int numSkVerbs,
23 int numConicWeights)
24 : fAlgorithm(algorithm)
25 , fGeometry(numSkPoints, numSkVerbs, numConicWeights)
Chris Daltone1639692018-08-20 14:00:30 -060026 , fPathInfos(numPaths)
Chris Dalton3917b1e2018-05-09 00:40:52 -060027 , fScissorSubBatches(numPaths)
Chris Dalton9ca27842018-01-18 12:24:50 -070028 , 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()};
Chris Daltone1639692018-08-20 14:00:30 -060033 fBatches.push_back() = {PrimitiveTallies(), fScissorSubBatches.count(), PrimitiveTallies()};
Chris Dalton9ca27842018-01-18 12:24:50 -070034}
35
Chris Daltone1639692018-08-20 14:00:30 -060036void 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());
Chris Dalton9ca27842018-01-18 12:24:50 -070041
Chris Daltone1639692018-08-20 14:00:30 -060042 int currPathPointsIdx = fGeometry.points().count();
43 int currPathVerbsIdx = fGeometry.verbs().count();
44 PrimitiveTallies currPathPrimitiveCounts = PrimitiveTallies();
Chris Dalton9ca27842018-01-18 12:24:50 -070045
46 fGeometry.beginPath();
47
Chris Dalton9f2dab02018-04-18 14:07:03 -060048 const float* conicWeights = SkPathPriv::ConicWeightData(path);
Chris Dalton9ca27842018-01-18 12:24:50 -070049 int ptsIdx = 0;
Chris Dalton9f2dab02018-04-18 14:07:03 -060050 int conicWeightsIdx = 0;
Chris Dalton9ca27842018-01-18 12:24:50 -070051 bool insideContour = false;
52
53 for (SkPath::Verb verb : SkPathPriv::Verbs(path)) {
54 switch (verb) {
55 case SkPath::kMove_Verb:
Chris Daltone1639692018-08-20 14:00:30 -060056 if (insideContour) {
57 currPathPrimitiveCounts += fGeometry.endContour();
58 }
Chris Dalton9ca27842018-01-18 12:24:50 -070059 fGeometry.beginContour(deviceSpacePts[ptsIdx]);
60 ++ptsIdx;
61 insideContour = true;
62 continue;
63 case SkPath::kClose_Verb:
Chris Daltone1639692018-08-20 14:00:30 -060064 if (insideContour) {
65 currPathPrimitiveCounts += fGeometry.endContour();
66 }
Chris Dalton9ca27842018-01-18 12:24:50 -070067 insideContour = false;
68 continue;
69 case SkPath::kLine_Verb:
Chris Dalton6f5e77a2018-04-23 21:14:42 -060070 fGeometry.lineTo(&deviceSpacePts[ptsIdx - 1]);
Chris Dalton9ca27842018-01-18 12:24:50 -070071 ++ptsIdx;
72 continue;
73 case SkPath::kQuad_Verb:
Chris Dalton7ca3b7b2018-04-10 00:21:19 -060074 fGeometry.quadraticTo(&deviceSpacePts[ptsIdx - 1]);
Chris Dalton9ca27842018-01-18 12:24:50 -070075 ptsIdx += 2;
76 continue;
77 case SkPath::kCubic_Verb:
Chris Dalton7ca3b7b2018-04-10 00:21:19 -060078 fGeometry.cubicTo(&deviceSpacePts[ptsIdx - 1]);
Chris Dalton9ca27842018-01-18 12:24:50 -070079 ptsIdx += 3;
80 continue;
81 case SkPath::kConic_Verb:
Chris Dalton9f2dab02018-04-18 14:07:03 -060082 fGeometry.conicTo(&deviceSpacePts[ptsIdx - 1], conicWeights[conicWeightsIdx]);
83 ptsIdx += 2;
84 ++conicWeightsIdx;
85 continue;
Chris Dalton9ca27842018-01-18 12:24:50 -070086 default:
87 SK_ABORT("Unexpected path verb.");
88 }
89 }
Chris Dalton9f2dab02018-04-18 14:07:03 -060090 SkASSERT(ptsIdx == path.countPoints());
91 SkASSERT(conicWeightsIdx == SkPathPriv::ConicWeightCnt(path));
Chris Dalton9ca27842018-01-18 12:24:50 -070092
Chris Dalton9ca27842018-01-18 12:24:50 -070093 if (insideContour) {
Chris Daltone1639692018-08-20 14:00:30 -060094 currPathPrimitiveCounts += fGeometry.endContour();
Chris Dalton9ca27842018-01-18 12:24:50 -070095 }
Chris Dalton9ca27842018-01-18 12:24:50 -070096
Chris Daltone1639692018-08-20 14:00:30 -060097 fPathInfos.emplace_back(scissorTest, devToAtlasOffset);
Chris Dalton84403d72018-02-13 21:46:17 -050098
99 // Tessellate fans from very large and/or simple paths, in order to reduce overdraw.
Chris Daltone1639692018-08-20 14:00:30 -0600100 int numVerbs = fGeometry.verbs().count() - currPathVerbsIdx - 1;
Chris Dalton84403d72018-02-13 21:46:17 -0500101 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.
Chris Daltonc3318f02019-07-19 14:20:53 -0600104 fPathInfos.back().tessellateFan(
105 fAlgorithm, path, fGeometry, currPathVerbsIdx, currPathPointsIdx, clippedDevIBounds,
106 &currPathPrimitiveCounts);
Chris Dalton84403d72018-02-13 21:46:17 -0500107 }
108
Chris Daltone1639692018-08-20 14:00:30 -0600109 fTotalPrimitiveCounts[(int)scissorTest] += currPathPrimitiveCounts;
Chris Dalton9ca27842018-01-18 12:24:50 -0700110
Chris Dalton916c4982018-08-15 00:53:25 -0600111 if (GrScissorTest::kEnabled == scissorTest) {
112 fScissorSubBatches.push_back() = {fTotalPrimitiveCounts[(int)GrScissorTest::kEnabled],
Brian Salomon9bd947d2019-10-03 14:57:07 -0400113 clippedDevIBounds.makeOffset(devToAtlasOffset)};
Chris Dalton9ca27842018-01-18 12:24:50 -0700114 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700115}
116
Chris Daltonc3318f02019-07-19 14:20:53 -0600117void GrCCFiller::PathInfo::tessellateFan(
118 Algorithm algorithm, const SkPath& originalPath, const GrCCFillGeometry& geometry,
119 int verbsIdx, int ptsIdx, const SkIRect& clippedDevIBounds,
120 PrimitiveTallies* newTriangleCounts) {
Chris Daltone1639692018-08-20 14:00:30 -0600121 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
Chris Daltonc3318f02019-07-19 14:20:53 -0600131 // Build an SkPath of the Redbook fan.
Chris Daltone1639692018-08-20 14:00:30 -0600132 SkPath fan;
Chris Daltonc3318f02019-07-19 14:20:53 -0600133 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.
Mike Reed4241f5e2019-09-14 19:13:23 +0000137 fan.setFillType(SkPath::kWinding_FillType);
Chris Daltonc3318f02019-07-19 14:20:53 -0600138 } else {
Chris Daltonc0966542019-09-23 20:16:03 -0600139 // 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(SkPath::ConvertToNonInverseFillType(originalPath.getFillType()));
Chris Daltonc3318f02019-07-19 14:20:53 -0600143 }
Chris Daltone1639692018-08-20 14:00:30 -0600144 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;
Chris Daltonc0966542019-09-23 20:16:03 -0600178 SkASSERT(!fan.isInverseFillType());
179 fFanTessellationCount = GrTessellator::PathToVertices(
180 fan, std::numeric_limits<float>::infinity(), SkRect::Make(clippedDevIBounds),
181 &vertices);
Chris Daltone1639692018-08-20 14:00:30 -0600182 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
Chris Daltonc3318f02019-07-19 14:20:53 -0600206 int weight = abs(tessWinding);
Chris Dalton9fdebfb2019-11-18 19:55:11 -0700207 if (SkPath::kEvenOdd_FillType == fan.getFillType()) {
208 SkASSERT(Algorithm::kCoverageCount != algorithm); // Covg. count always uses winding.
209 if (weight != 1) {
210 // The tessellator doesn't wrap weights modulo 2 when we request even/odd fill type.
211 SkASSERT(weight & 1); // Even wind regions are empty and should have been omitted.
212 weight = 1;
213 }
214 }
Chris Daltonc3318f02019-07-19 14:20:53 -0600215 if (weight > 1 && Algorithm::kCoverageCount == algorithm) {
Chris Daltone1639692018-08-20 14:00:30 -0600216 ++newTriangleCounts->fWeightedTriangles;
Chris Daltonc3318f02019-07-19 14:20:53 -0600217 } else {
218 newTriangleCounts->fTriangles += weight;
Chris Daltone1639692018-08-20 14:00:30 -0600219 }
Chris Dalton9fdebfb2019-11-18 19:55:11 -0700220 vertices[i].fWinding = weight;
Chris Daltone1639692018-08-20 14:00:30 -0600221 }
222
223 fFanTessellation.reset(vertices);
Chris Dalton9ca27842018-01-18 12:24:50 -0700224}
225
Chris Daltone1639692018-08-20 14:00:30 -0600226GrCCFiller::BatchID GrCCFiller::closeCurrentBatch() {
Chris Dalton9ca27842018-01-18 12:24:50 -0700227 SkASSERT(!fInstanceBuffer);
Chris Daltone1639692018-08-20 14:00:30 -0600228 SkASSERT(!fBatches.empty());
Chris Dalton9ca27842018-01-18 12:24:50 -0700229
Chris Daltone1639692018-08-20 14:00:30 -0600230 const auto& lastBatch = fBatches.back();
Chris Daltona883aca2018-03-08 23:05:30 -0700231 int maxMeshes = 1 + fScissorSubBatches.count() - lastBatch.fEndScissorSubBatchIdx;
232 fMaxMeshesPerDraw = SkTMax(fMaxMeshesPerDraw, maxMeshes);
233
234 const auto& lastScissorSubBatch = fScissorSubBatches[lastBatch.fEndScissorSubBatchIdx - 1];
Chris Dalton916c4982018-08-15 00:53:25 -0600235 PrimitiveTallies batchTotalCounts = fTotalPrimitiveCounts[(int)GrScissorTest::kDisabled] -
Chris Dalton84403d72018-02-13 21:46:17 -0500236 lastBatch.fEndNonScissorIndices;
Chris Dalton916c4982018-08-15 00:53:25 -0600237 batchTotalCounts += fTotalPrimitiveCounts[(int)GrScissorTest::kEnabled] -
Chris Dalton84403d72018-02-13 21:46:17 -0500238 lastScissorSubBatch.fEndPrimitiveIndices;
Chris Dalton9ca27842018-01-18 12:24:50 -0700239
Chris Daltona883aca2018-03-08 23:05:30 -0700240 // This will invalidate lastBatch.
Chris Daltone1639692018-08-20 14:00:30 -0600241 fBatches.push_back() = {
Chris Dalton916c4982018-08-15 00:53:25 -0600242 fTotalPrimitiveCounts[(int)GrScissorTest::kDisabled],
Chris Dalton84403d72018-02-13 21:46:17 -0500243 fScissorSubBatches.count(),
244 batchTotalCounts
Chris Dalton9ca27842018-01-18 12:24:50 -0700245 };
Chris Daltone1639692018-08-20 14:00:30 -0600246 return fBatches.count() - 1;
Chris Dalton9ca27842018-01-18 12:24:50 -0700247}
248
249// Emits a contour's triangle fan.
250//
251// Classic Redbook fanning would be the triangles: [0 1 2], [0 2 3], ..., [0 n-2 n-1].
252//
253// This function emits the triangle: [0 n/3 n*2/3], and then recurses on all three sides. The
254// advantage to this approach is that for a convex-ish contour, it generates larger triangles.
255// Classic fanning tends to generate long, skinny triangles, which are expensive to draw since they
256// have a longer perimeter to rasterize and antialias.
257//
258// The indices array indexes the fan's points (think: glDrawElements), and must have at least log3
259// elements past the end for this method to use as scratch space.
260//
261// Returns the next triangle instance after the final one emitted.
Chris Daltonc3318f02019-07-19 14:20:53 -0600262static TriPointInstance* emit_recursive_fan(
263 const SkTArray<SkPoint, true>& pts, SkTArray<int32_t, true>& indices, int firstIndex,
264 int indexCount, const Sk2f& devToAtlasOffset, TriPointInstance::Ordering ordering,
265 TriPointInstance out[]) {
Chris Dalton9ca27842018-01-18 12:24:50 -0700266 if (indexCount < 3) {
267 return out;
268 }
269
270 int32_t oneThirdCount = indexCount / 3;
271 int32_t twoThirdsCount = (2 * indexCount) / 3;
272 out++->set(pts[indices[firstIndex]], pts[indices[firstIndex + oneThirdCount]],
Chris Daltonc3318f02019-07-19 14:20:53 -0600273 pts[indices[firstIndex + twoThirdsCount]], devToAtlasOffset, ordering);
Chris Dalton9ca27842018-01-18 12:24:50 -0700274
Chris Daltonc3318f02019-07-19 14:20:53 -0600275 out = emit_recursive_fan(
276 pts, indices, firstIndex, oneThirdCount + 1, devToAtlasOffset, ordering, out);
277 out = emit_recursive_fan(
278 pts, indices, firstIndex + oneThirdCount, twoThirdsCount - oneThirdCount + 1,
279 devToAtlasOffset, ordering, out);
Chris Dalton9ca27842018-01-18 12:24:50 -0700280
281 int endIndex = firstIndex + indexCount;
282 int32_t oldValue = indices[endIndex];
283 indices[endIndex] = indices[firstIndex];
Chris Daltonc3318f02019-07-19 14:20:53 -0600284 out = emit_recursive_fan(
285 pts, indices, firstIndex + twoThirdsCount, indexCount - twoThirdsCount + 1,
286 devToAtlasOffset, ordering, out);
Chris Dalton9ca27842018-01-18 12:24:50 -0700287 indices[endIndex] = oldValue;
288
289 return out;
290}
291
Chris Daltonc3318f02019-07-19 14:20:53 -0600292void GrCCFiller::emitTessellatedFan(
293 const GrTessellator::WindingVertex* vertices, int numVertices, const Sk2f& devToAtlasOffset,
294 TriPointInstance::Ordering ordering, TriPointInstance* triPointInstanceData,
295 QuadPointInstance* quadPointInstanceData, GrCCFillGeometry::PrimitiveTallies* indices) {
Chris Dalton84403d72018-02-13 21:46:17 -0500296 for (int i = 0; i < numVertices; i += 3) {
Chris Dalton9fdebfb2019-11-18 19:55:11 -0700297 int weight = vertices[i].fWinding;
Chris Daltonc3318f02019-07-19 14:20:53 -0600298 SkASSERT(weight >= 1);
299 if (weight > 1 && Algorithm::kStencilWindingCount != fAlgorithm) {
Chris Dalton703b4762018-04-06 16:11:48 -0600300 quadPointInstanceData[indices->fWeightedTriangles++].setW(
Chris Dalton9414c962018-06-14 10:14:50 -0600301 vertices[i].fPos, vertices[i+1].fPos, vertices[i + 2].fPos, devToAtlasOffset,
Chris Dalton6f5e77a2018-04-23 21:14:42 -0600302 static_cast<float>(abs(vertices[i].fWinding)));
Chris Daltonc3318f02019-07-19 14:20:53 -0600303 } else for (int j = 0; j < weight; ++j) {
304 // Unfortunately, there is not a way to increment stencil values by an amount larger
305 // than 1. Instead we draw the triangle 'weight' times.
306 triPointInstanceData[indices->fTriangles++].set(
307 vertices[i].fPos, vertices[i + 1].fPos, vertices[i + 2].fPos, devToAtlasOffset,
308 ordering);
Chris Dalton84403d72018-02-13 21:46:17 -0500309 }
310 }
311}
312
Chris Daltone1639692018-08-20 14:00:30 -0600313bool GrCCFiller::prepareToDraw(GrOnFlushResourceProvider* onFlushRP) {
314 using Verb = GrCCFillGeometry::Verb;
315 SkASSERT(!fInstanceBuffer);
316 SkASSERT(fBatches.back().fEndNonScissorIndices == // Call closeCurrentBatch().
Chris Dalton916c4982018-08-15 00:53:25 -0600317 fTotalPrimitiveCounts[(int)GrScissorTest::kDisabled]);
Chris Daltone1639692018-08-20 14:00:30 -0600318 SkASSERT(fBatches.back().fEndScissorSubBatchIdx == fScissorSubBatches.count());
Chris Dalton9ca27842018-01-18 12:24:50 -0700319
Chris Daltonc3318f02019-07-19 14:20:53 -0600320 auto triangleOrdering = (Algorithm::kCoverageCount == fAlgorithm)
321 ? TriPointInstance::Ordering::kXYTransposed
322 : TriPointInstance::Ordering::kXYInterleaved;
323
Chris Dalton9ca27842018-01-18 12:24:50 -0700324 // Here we build a single instance buffer to share with every internal batch.
325 //
326 // CCPR processs 3 different types of primitives: triangles, quadratics, cubics. Each primitive
327 // type is further divided into instances that require a scissor and those that don't. This
328 // leaves us with 3*2 = 6 independent instance arrays to build for the GPU.
329 //
330 // Rather than place each instance array in its own GPU buffer, we allocate a single
331 // megabuffer and lay them all out side-by-side. We can offset the "baseInstance" parameter in
332 // our draw calls to direct the GPU to the applicable elements within a given array.
333 //
334 // We already know how big to make each of the 6 arrays from fTotalPrimitiveCounts, so layout is
335 // straightforward. Start with triangles and quadratics. They both view the instance buffer as
Chris Dalton84403d72018-02-13 21:46:17 -0500336 // an array of TriPointInstance[], so we can begin at zero and lay them out one after the other.
Chris Dalton9ca27842018-01-18 12:24:50 -0700337 fBaseInstances[0].fTriangles = 0;
338 fBaseInstances[1].fTriangles = fBaseInstances[0].fTriangles +
339 fTotalPrimitiveCounts[0].fTriangles;
340 fBaseInstances[0].fQuadratics = fBaseInstances[1].fTriangles +
341 fTotalPrimitiveCounts[1].fTriangles;
342 fBaseInstances[1].fQuadratics = fBaseInstances[0].fQuadratics +
343 fTotalPrimitiveCounts[0].fQuadratics;
344 int triEndIdx = fBaseInstances[1].fQuadratics + fTotalPrimitiveCounts[1].fQuadratics;
345
Chris Dalton84403d72018-02-13 21:46:17 -0500346 // Wound triangles and cubics both view the same instance buffer as an array of
347 // QuadPointInstance[]. So, reinterpreting the instance data as QuadPointInstance[], we start
348 // them on the first index that will not overwrite previous TriPointInstance data.
349 int quadBaseIdx =
Brian Salomon24d377e2019-04-23 15:24:31 -0400350 GrSizeDivRoundUp(triEndIdx * sizeof(TriPointInstance), sizeof(QuadPointInstance));
Chris Dalton703b4762018-04-06 16:11:48 -0600351 fBaseInstances[0].fWeightedTriangles = quadBaseIdx;
352 fBaseInstances[1].fWeightedTriangles = fBaseInstances[0].fWeightedTriangles +
353 fTotalPrimitiveCounts[0].fWeightedTriangles;
354 fBaseInstances[0].fCubics = fBaseInstances[1].fWeightedTriangles +
355 fTotalPrimitiveCounts[1].fWeightedTriangles;
Chris Dalton9ca27842018-01-18 12:24:50 -0700356 fBaseInstances[1].fCubics = fBaseInstances[0].fCubics + fTotalPrimitiveCounts[0].fCubics;
Chris Dalton9f2dab02018-04-18 14:07:03 -0600357 fBaseInstances[0].fConics = fBaseInstances[1].fCubics + fTotalPrimitiveCounts[1].fCubics;
358 fBaseInstances[1].fConics = fBaseInstances[0].fConics + fTotalPrimitiveCounts[0].fConics;
359 int quadEndIdx = fBaseInstances[1].fConics + fTotalPrimitiveCounts[1].fConics;
Chris Dalton9ca27842018-01-18 12:24:50 -0700360
Brian Salomonae64c192019-02-05 09:41:37 -0500361 fInstanceBuffer =
362 onFlushRP->makeBuffer(GrGpuBufferType::kVertex, quadEndIdx * sizeof(QuadPointInstance));
Chris Dalton9ca27842018-01-18 12:24:50 -0700363 if (!fInstanceBuffer) {
Chris Daltone1639692018-08-20 14:00:30 -0600364 SkDebugf("WARNING: failed to allocate CCPR fill instance buffer.\n");
Chris Dalton9ca27842018-01-18 12:24:50 -0700365 return false;
366 }
367
Chris Dalton84403d72018-02-13 21:46:17 -0500368 TriPointInstance* triPointInstanceData = static_cast<TriPointInstance*>(fInstanceBuffer->map());
369 QuadPointInstance* quadPointInstanceData =
370 reinterpret_cast<QuadPointInstance*>(triPointInstanceData);
371 SkASSERT(quadPointInstanceData);
Chris Dalton9ca27842018-01-18 12:24:50 -0700372
Chris Daltone1639692018-08-20 14:00:30 -0600373 PathInfo* nextPathInfo = fPathInfos.begin();
Chris Dalton9414c962018-06-14 10:14:50 -0600374 Sk2f devToAtlasOffset;
Chris Dalton9ca27842018-01-18 12:24:50 -0700375 PrimitiveTallies instanceIndices[2] = {fBaseInstances[0], fBaseInstances[1]};
376 PrimitiveTallies* currIndices = nullptr;
377 SkSTArray<256, int32_t, true> currFan;
Chris Dalton84403d72018-02-13 21:46:17 -0500378 bool currFanIsTessellated = false;
Chris Dalton9ca27842018-01-18 12:24:50 -0700379
380 const SkTArray<SkPoint, true>& pts = fGeometry.points();
Chris Dalton84403d72018-02-13 21:46:17 -0500381 int ptsIdx = -1;
Chris Dalton9f2dab02018-04-18 14:07:03 -0600382 int nextConicWeightIdx = 0;
Chris Dalton9ca27842018-01-18 12:24:50 -0700383
384 // Expand the ccpr verbs into GPU instance buffers.
Chris Daltone1639692018-08-20 14:00:30 -0600385 for (Verb verb : fGeometry.verbs()) {
Chris Dalton9ca27842018-01-18 12:24:50 -0700386 switch (verb) {
Chris Daltone1639692018-08-20 14:00:30 -0600387 case Verb::kBeginPath:
Chris Dalton9ca27842018-01-18 12:24:50 -0700388 SkASSERT(currFan.empty());
Chris Dalton916c4982018-08-15 00:53:25 -0600389 currIndices = &instanceIndices[(int)nextPathInfo->scissorTest()];
Chris Dalton9414c962018-06-14 10:14:50 -0600390 devToAtlasOffset = Sk2f(static_cast<float>(nextPathInfo->devToAtlasOffset().fX),
391 static_cast<float>(nextPathInfo->devToAtlasOffset().fY));
Chris Daltonad065442018-03-08 22:41:33 -0700392 currFanIsTessellated = nextPathInfo->hasFanTessellation();
Chris Dalton84403d72018-02-13 21:46:17 -0500393 if (currFanIsTessellated) {
Chris Daltonc3318f02019-07-19 14:20:53 -0600394 this->emitTessellatedFan(
395 nextPathInfo->fanTessellation(), nextPathInfo->fanTessellationCount(),
396 devToAtlasOffset, triangleOrdering, triPointInstanceData,
397 quadPointInstanceData, currIndices);
Chris Dalton84403d72018-02-13 21:46:17 -0500398 }
399 ++nextPathInfo;
Chris Dalton9ca27842018-01-18 12:24:50 -0700400 continue;
401
Chris Daltone1639692018-08-20 14:00:30 -0600402 case Verb::kBeginContour:
Chris Dalton9ca27842018-01-18 12:24:50 -0700403 SkASSERT(currFan.empty());
Chris Dalton84403d72018-02-13 21:46:17 -0500404 ++ptsIdx;
405 if (!currFanIsTessellated) {
406 currFan.push_back(ptsIdx);
407 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700408 continue;
409
Chris Daltone1639692018-08-20 14:00:30 -0600410 case Verb::kLineTo:
Chris Dalton84403d72018-02-13 21:46:17 -0500411 ++ptsIdx;
412 if (!currFanIsTessellated) {
413 SkASSERT(!currFan.empty());
414 currFan.push_back(ptsIdx);
415 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700416 continue;
417
Chris Daltone1639692018-08-20 14:00:30 -0600418 case Verb::kMonotonicQuadraticTo:
Chris Daltonc3318f02019-07-19 14:20:53 -0600419 triPointInstanceData[currIndices->fQuadratics++].set(
420 &pts[ptsIdx], devToAtlasOffset, TriPointInstance::Ordering::kXYTransposed);
Chris Dalton84403d72018-02-13 21:46:17 -0500421 ptsIdx += 2;
422 if (!currFanIsTessellated) {
423 SkASSERT(!currFan.empty());
424 currFan.push_back(ptsIdx);
425 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700426 continue;
427
Chris Daltone1639692018-08-20 14:00:30 -0600428 case Verb::kMonotonicCubicTo:
Chris Daltonc3318f02019-07-19 14:20:53 -0600429 quadPointInstanceData[currIndices->fCubics++].set(
430 &pts[ptsIdx], devToAtlasOffset[0], devToAtlasOffset[1]);
Chris Dalton84403d72018-02-13 21:46:17 -0500431 ptsIdx += 3;
432 if (!currFanIsTessellated) {
433 SkASSERT(!currFan.empty());
434 currFan.push_back(ptsIdx);
435 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700436 continue;
437
Chris Daltone1639692018-08-20 14:00:30 -0600438 case Verb::kMonotonicConicTo:
Chris Dalton9f2dab02018-04-18 14:07:03 -0600439 quadPointInstanceData[currIndices->fConics++].setW(
Chris Dalton9414c962018-06-14 10:14:50 -0600440 &pts[ptsIdx], devToAtlasOffset,
441 fGeometry.getConicWeight(nextConicWeightIdx));
Chris Dalton9f2dab02018-04-18 14:07:03 -0600442 ptsIdx += 2;
443 ++nextConicWeightIdx;
444 if (!currFanIsTessellated) {
445 SkASSERT(!currFan.empty());
446 currFan.push_back(ptsIdx);
447 }
448 continue;
449
Chris Daltone1639692018-08-20 14:00:30 -0600450 case Verb::kEndClosedContour: // endPt == startPt.
Chris Dalton84403d72018-02-13 21:46:17 -0500451 if (!currFanIsTessellated) {
452 SkASSERT(!currFan.empty());
453 currFan.pop_back();
454 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700455 // fallthru.
Chris Daltone1639692018-08-20 14:00:30 -0600456 case Verb::kEndOpenContour: // endPt != startPt.
Chris Dalton84403d72018-02-13 21:46:17 -0500457 SkASSERT(!currFanIsTessellated || currFan.empty());
458 if (!currFanIsTessellated && currFan.count() >= 3) {
Chris Dalton9ca27842018-01-18 12:24:50 -0700459 int fanSize = currFan.count();
460 // Reserve space for emit_recursive_fan. Technically this can grow to
461 // fanSize + log3(fanSize), but we approximate with log2.
462 currFan.push_back_n(SkNextLog2(fanSize));
Chris Daltonc3318f02019-07-19 14:20:53 -0600463 SkDEBUGCODE(TriPointInstance* end =) emit_recursive_fan(
464 pts, currFan, 0, fanSize, devToAtlasOffset, triangleOrdering,
465 triPointInstanceData + currIndices->fTriangles);
Chris Dalton9ca27842018-01-18 12:24:50 -0700466 currIndices->fTriangles += fanSize - 2;
Chris Dalton84403d72018-02-13 21:46:17 -0500467 SkASSERT(triPointInstanceData + currIndices->fTriangles == end);
Chris Dalton9ca27842018-01-18 12:24:50 -0700468 }
469 currFan.reset();
470 continue;
471 }
472 }
473
474 fInstanceBuffer->unmap();
475
Chris Daltone1639692018-08-20 14:00:30 -0600476 SkASSERT(nextPathInfo == fPathInfos.end());
Chris Dalton9ca27842018-01-18 12:24:50 -0700477 SkASSERT(ptsIdx == pts.count() - 1);
478 SkASSERT(instanceIndices[0].fTriangles == fBaseInstances[1].fTriangles);
479 SkASSERT(instanceIndices[1].fTriangles == fBaseInstances[0].fQuadratics);
480 SkASSERT(instanceIndices[0].fQuadratics == fBaseInstances[1].fQuadratics);
481 SkASSERT(instanceIndices[1].fQuadratics == triEndIdx);
Chris Dalton703b4762018-04-06 16:11:48 -0600482 SkASSERT(instanceIndices[0].fWeightedTriangles == fBaseInstances[1].fWeightedTriangles);
483 SkASSERT(instanceIndices[1].fWeightedTriangles == fBaseInstances[0].fCubics);
Chris Dalton9ca27842018-01-18 12:24:50 -0700484 SkASSERT(instanceIndices[0].fCubics == fBaseInstances[1].fCubics);
Chris Dalton9f2dab02018-04-18 14:07:03 -0600485 SkASSERT(instanceIndices[1].fCubics == fBaseInstances[0].fConics);
486 SkASSERT(instanceIndices[0].fConics == fBaseInstances[1].fConics);
487 SkASSERT(instanceIndices[1].fConics == quadEndIdx);
Chris Dalton9ca27842018-01-18 12:24:50 -0700488
489 fMeshesScratchBuffer.reserve(fMaxMeshesPerDraw);
Brian Salomon49348902018-06-26 09:12:38 -0400490 fScissorRectScratchBuffer.reserve(fMaxMeshesPerDraw);
Chris Dalton9ca27842018-01-18 12:24:50 -0700491
492 return true;
493}
494
Chris Daltonc3318f02019-07-19 14:20:53 -0600495void GrCCFiller::drawFills(
496 GrOpFlushState* flushState, GrCCCoverageProcessor* proc, const GrPipeline& pipeline,
497 BatchID batchID, const SkIRect& drawBounds) const {
Chris Dalton8dfc70f2018-03-26 19:15:22 -0600498 using PrimitiveType = GrCCCoverageProcessor::PrimitiveType;
Chris Dalton9ca27842018-01-18 12:24:50 -0700499
500 SkASSERT(fInstanceBuffer);
501
Chris Dalton2c5e0112019-03-29 13:14:18 -0500502 GrResourceProvider* rp = flushState->resourceProvider();
Chris Daltone1639692018-08-20 14:00:30 -0600503 const PrimitiveTallies& batchTotalCounts = fBatches[batchID].fTotalPrimitiveCounts;
Chris Dalton84403d72018-02-13 21:46:17 -0500504
Chris Dalton84403d72018-02-13 21:46:17 -0500505 if (batchTotalCounts.fTriangles) {
Chris Dalton2c5e0112019-03-29 13:14:18 -0500506 proc->reset(PrimitiveType::kTriangles, rp);
507 this->drawPrimitives(
508 flushState, *proc, pipeline, batchID, &PrimitiveTallies::fTriangles, drawBounds);
Chris Dalton84403d72018-02-13 21:46:17 -0500509 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700510
Chris Dalton703b4762018-04-06 16:11:48 -0600511 if (batchTotalCounts.fWeightedTriangles) {
Chris Daltonc3318f02019-07-19 14:20:53 -0600512 SkASSERT(Algorithm::kStencilWindingCount != fAlgorithm);
Chris Dalton2c5e0112019-03-29 13:14:18 -0500513 proc->reset(PrimitiveType::kWeightedTriangles, rp);
514 this->drawPrimitives(
515 flushState, *proc, pipeline, batchID, &PrimitiveTallies::fWeightedTriangles,
516 drawBounds);
Chris Dalton84403d72018-02-13 21:46:17 -0500517 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700518
Chris Dalton84403d72018-02-13 21:46:17 -0500519 if (batchTotalCounts.fQuadratics) {
Chris Dalton2c5e0112019-03-29 13:14:18 -0500520 proc->reset(PrimitiveType::kQuadratics, rp);
521 this->drawPrimitives(
522 flushState, *proc, pipeline, batchID, &PrimitiveTallies::fQuadratics, drawBounds);
Chris Dalton84403d72018-02-13 21:46:17 -0500523 }
524
525 if (batchTotalCounts.fCubics) {
Chris Dalton2c5e0112019-03-29 13:14:18 -0500526 proc->reset(PrimitiveType::kCubics, rp);
527 this->drawPrimitives(
528 flushState, *proc, pipeline, batchID, &PrimitiveTallies::fCubics, drawBounds);
Chris Dalton84403d72018-02-13 21:46:17 -0500529 }
Chris Dalton9f2dab02018-04-18 14:07:03 -0600530
531 if (batchTotalCounts.fConics) {
Chris Dalton2c5e0112019-03-29 13:14:18 -0500532 proc->reset(PrimitiveType::kConics, rp);
533 this->drawPrimitives(
534 flushState, *proc, pipeline, batchID, &PrimitiveTallies::fConics, drawBounds);
Chris Dalton9f2dab02018-04-18 14:07:03 -0600535 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700536}
537
Chris Dalton2c5e0112019-03-29 13:14:18 -0500538void GrCCFiller::drawPrimitives(
539 GrOpFlushState* flushState, const GrCCCoverageProcessor& proc, const GrPipeline& pipeline,
540 BatchID batchID, int PrimitiveTallies::*instanceType, const SkIRect& drawBounds) const {
Brian Salomond818ebf2018-07-02 14:08:49 +0000541 SkASSERT(pipeline.isScissorEnabled());
Chris Dalton9ca27842018-01-18 12:24:50 -0700542
Chris Dalton9ca27842018-01-18 12:24:50 -0700543 // Don't call reset(), as that also resets the reserve count.
544 fMeshesScratchBuffer.pop_back_n(fMeshesScratchBuffer.count());
Brian Salomon49348902018-06-26 09:12:38 -0400545 fScissorRectScratchBuffer.pop_back_n(fScissorRectScratchBuffer.count());
Chris Dalton9ca27842018-01-18 12:24:50 -0700546
Chris Dalton9ca27842018-01-18 12:24:50 -0700547 SkASSERT(batchID > 0);
Chris Daltone1639692018-08-20 14:00:30 -0600548 SkASSERT(batchID < fBatches.count());
549 const Batch& previousBatch = fBatches[batchID - 1];
550 const Batch& batch = fBatches[batchID];
Chris Dalton84403d72018-02-13 21:46:17 -0500551 SkDEBUGCODE(int totalInstanceCount = 0);
Chris Dalton9ca27842018-01-18 12:24:50 -0700552
553 if (int instanceCount = batch.fEndNonScissorIndices.*instanceType -
554 previousBatch.fEndNonScissorIndices.*instanceType) {
555 SkASSERT(instanceCount > 0);
Chris Dalton916c4982018-08-15 00:53:25 -0600556 int baseInstance = fBaseInstances[(int)GrScissorTest::kDisabled].*instanceType +
Chris Dalton9ca27842018-01-18 12:24:50 -0700557 previousBatch.fEndNonScissorIndices.*instanceType;
Brian Salomon12d22642019-01-29 14:38:50 -0500558 proc.appendMesh(fInstanceBuffer, instanceCount, baseInstance, &fMeshesScratchBuffer);
Brian Salomon49348902018-06-26 09:12:38 -0400559 fScissorRectScratchBuffer.push_back().setXYWH(0, 0, drawBounds.width(),
560 drawBounds.height());
Chris Dalton84403d72018-02-13 21:46:17 -0500561 SkDEBUGCODE(totalInstanceCount += instanceCount);
Chris Dalton9ca27842018-01-18 12:24:50 -0700562 }
563
564 SkASSERT(previousBatch.fEndScissorSubBatchIdx > 0);
565 SkASSERT(batch.fEndScissorSubBatchIdx <= fScissorSubBatches.count());
Chris Dalton916c4982018-08-15 00:53:25 -0600566 int baseScissorInstance = fBaseInstances[(int)GrScissorTest::kEnabled].*instanceType;
Chris Dalton9ca27842018-01-18 12:24:50 -0700567 for (int i = previousBatch.fEndScissorSubBatchIdx; i < batch.fEndScissorSubBatchIdx; ++i) {
568 const ScissorSubBatch& previousSubBatch = fScissorSubBatches[i - 1];
569 const ScissorSubBatch& scissorSubBatch = fScissorSubBatches[i];
570 int startIndex = previousSubBatch.fEndPrimitiveIndices.*instanceType;
571 int instanceCount = scissorSubBatch.fEndPrimitiveIndices.*instanceType - startIndex;
572 if (!instanceCount) {
573 continue;
574 }
575 SkASSERT(instanceCount > 0);
Brian Salomon12d22642019-01-29 14:38:50 -0500576 proc.appendMesh(fInstanceBuffer, instanceCount, baseScissorInstance + startIndex,
577 &fMeshesScratchBuffer);
Brian Salomon49348902018-06-26 09:12:38 -0400578 fScissorRectScratchBuffer.push_back() = scissorSubBatch.fScissor;
Chris Dalton84403d72018-02-13 21:46:17 -0500579 SkDEBUGCODE(totalInstanceCount += instanceCount);
Chris Dalton9ca27842018-01-18 12:24:50 -0700580 }
581
Brian Salomon49348902018-06-26 09:12:38 -0400582 SkASSERT(fMeshesScratchBuffer.count() == fScissorRectScratchBuffer.count());
Chris Dalton9ca27842018-01-18 12:24:50 -0700583 SkASSERT(fMeshesScratchBuffer.count() <= fMaxMeshesPerDraw);
Chris Dalton84403d72018-02-13 21:46:17 -0500584 SkASSERT(totalInstanceCount == batch.fTotalPrimitiveCounts.*instanceType);
Chris Dalton9ca27842018-01-18 12:24:50 -0700585
586 if (!fMeshesScratchBuffer.empty()) {
Brian Salomon49348902018-06-26 09:12:38 -0400587 proc.draw(flushState, pipeline, fScissorRectScratchBuffer.begin(),
588 fMeshesScratchBuffer.begin(), fMeshesScratchBuffer.count(),
Chris Dalton8dfc70f2018-03-26 19:15:22 -0600589 SkRect::Make(drawBounds));
Chris Dalton9ca27842018-01-18 12:24:50 -0700590 }
591}