blob: 311eb95e56a252c6d0c0d8a0bc38491e9f86a7ca [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
Chris Daltone1639692018-08-20 14:00:30 -06008#include "GrCCFiller.h"
Chris Dalton9ca27842018-01-18 12:24:50 -07009
10#include "GrCaps.h"
11#include "GrGpuCommandBuffer.h"
12#include "GrOnFlushResourceProvider.h"
13#include "GrOpFlushState.h"
14#include "SkMathPriv.h"
15#include "SkPath.h"
16#include "SkPathPriv.h"
17#include "SkPoint.h"
Chris Dalton84403d72018-02-13 21:46:17 -050018#include <stdlib.h>
Chris Dalton9ca27842018-01-18 12:24:50 -070019
Chris Dalton84403d72018-02-13 21:46:17 -050020using TriPointInstance = GrCCCoverageProcessor::TriPointInstance;
21using QuadPointInstance = GrCCCoverageProcessor::QuadPointInstance;
Chris Dalton9ca27842018-01-18 12:24:50 -070022
Chris Dalton09a7bb22018-08-31 19:53:15 +080023GrCCFiller::GrCCFiller(int numPaths, int numSkPoints, int numSkVerbs, int numConicWeights)
24 : fGeometry(numSkPoints, numSkVerbs, numConicWeights)
Chris Daltone1639692018-08-20 14:00:30 -060025 , fPathInfos(numPaths)
Chris Dalton3917b1e2018-05-09 00:40:52 -060026 , fScissorSubBatches(numPaths)
Chris Dalton9ca27842018-01-18 12:24:50 -070027 , fTotalPrimitiveCounts{PrimitiveTallies(), PrimitiveTallies()} {
28 // Batches decide what to draw by looking where the previous one ended. Define initial batches
29 // that "end" at the beginning of the data. These will not be drawn, but will only be be read by
30 // the first actual batch.
31 fScissorSubBatches.push_back() = {PrimitiveTallies(), SkIRect::MakeEmpty()};
Chris Daltone1639692018-08-20 14:00:30 -060032 fBatches.push_back() = {PrimitiveTallies(), fScissorSubBatches.count(), PrimitiveTallies()};
Chris Dalton9ca27842018-01-18 12:24:50 -070033}
34
Chris Daltone1639692018-08-20 14:00:30 -060035void GrCCFiller::parseDeviceSpaceFill(const SkPath& path, const SkPoint* deviceSpacePts,
36 GrScissorTest scissorTest, const SkIRect& clippedDevIBounds,
37 const SkIVector& devToAtlasOffset) {
38 SkASSERT(!fInstanceBuffer); // Can't call after prepareToDraw().
39 SkASSERT(!path.isEmpty());
Chris Dalton9ca27842018-01-18 12:24:50 -070040
Chris Daltone1639692018-08-20 14:00:30 -060041 int currPathPointsIdx = fGeometry.points().count();
42 int currPathVerbsIdx = fGeometry.verbs().count();
43 PrimitiveTallies currPathPrimitiveCounts = PrimitiveTallies();
Chris Dalton9ca27842018-01-18 12:24:50 -070044
45 fGeometry.beginPath();
46
Chris Dalton9f2dab02018-04-18 14:07:03 -060047 const float* conicWeights = SkPathPriv::ConicWeightData(path);
Chris Dalton9ca27842018-01-18 12:24:50 -070048 int ptsIdx = 0;
Chris Dalton9f2dab02018-04-18 14:07:03 -060049 int conicWeightsIdx = 0;
Chris Dalton9ca27842018-01-18 12:24:50 -070050 bool insideContour = false;
51
52 for (SkPath::Verb verb : SkPathPriv::Verbs(path)) {
53 switch (verb) {
54 case SkPath::kMove_Verb:
Chris Daltone1639692018-08-20 14:00:30 -060055 if (insideContour) {
56 currPathPrimitiveCounts += fGeometry.endContour();
57 }
Chris Dalton9ca27842018-01-18 12:24:50 -070058 fGeometry.beginContour(deviceSpacePts[ptsIdx]);
59 ++ptsIdx;
60 insideContour = true;
61 continue;
62 case SkPath::kClose_Verb:
Chris Daltone1639692018-08-20 14:00:30 -060063 if (insideContour) {
64 currPathPrimitiveCounts += fGeometry.endContour();
65 }
Chris Dalton9ca27842018-01-18 12:24:50 -070066 insideContour = false;
67 continue;
68 case SkPath::kLine_Verb:
Chris Dalton6f5e77a2018-04-23 21:14:42 -060069 fGeometry.lineTo(&deviceSpacePts[ptsIdx - 1]);
Chris Dalton9ca27842018-01-18 12:24:50 -070070 ++ptsIdx;
71 continue;
72 case SkPath::kQuad_Verb:
Chris Dalton7ca3b7b2018-04-10 00:21:19 -060073 fGeometry.quadraticTo(&deviceSpacePts[ptsIdx - 1]);
Chris Dalton9ca27842018-01-18 12:24:50 -070074 ptsIdx += 2;
75 continue;
76 case SkPath::kCubic_Verb:
Chris Dalton7ca3b7b2018-04-10 00:21:19 -060077 fGeometry.cubicTo(&deviceSpacePts[ptsIdx - 1]);
Chris Dalton9ca27842018-01-18 12:24:50 -070078 ptsIdx += 3;
79 continue;
80 case SkPath::kConic_Verb:
Chris Dalton9f2dab02018-04-18 14:07:03 -060081 fGeometry.conicTo(&deviceSpacePts[ptsIdx - 1], conicWeights[conicWeightsIdx]);
82 ptsIdx += 2;
83 ++conicWeightsIdx;
84 continue;
Chris Dalton9ca27842018-01-18 12:24:50 -070085 default:
86 SK_ABORT("Unexpected path verb.");
87 }
88 }
Chris Dalton9f2dab02018-04-18 14:07:03 -060089 SkASSERT(ptsIdx == path.countPoints());
90 SkASSERT(conicWeightsIdx == SkPathPriv::ConicWeightCnt(path));
Chris Dalton9ca27842018-01-18 12:24:50 -070091
Chris Dalton9ca27842018-01-18 12:24:50 -070092 if (insideContour) {
Chris Daltone1639692018-08-20 14:00:30 -060093 currPathPrimitiveCounts += fGeometry.endContour();
Chris Dalton9ca27842018-01-18 12:24:50 -070094 }
Chris Dalton9ca27842018-01-18 12:24:50 -070095
Chris Daltone1639692018-08-20 14:00:30 -060096 fPathInfos.emplace_back(scissorTest, devToAtlasOffset);
Chris Dalton84403d72018-02-13 21:46:17 -050097
98 // Tessellate fans from very large and/or simple paths, in order to reduce overdraw.
Chris Daltone1639692018-08-20 14:00:30 -060099 int numVerbs = fGeometry.verbs().count() - currPathVerbsIdx - 1;
Chris Dalton84403d72018-02-13 21:46:17 -0500100 int64_t tessellationWork = (int64_t)numVerbs * (32 - SkCLZ(numVerbs)); // N log N.
101 int64_t fanningWork = (int64_t)clippedDevIBounds.height() * clippedDevIBounds.width();
102 if (tessellationWork * (50*50) + (100*100) < fanningWork) { // Don't tessellate under 100x100.
Chris Daltone1639692018-08-20 14:00:30 -0600103 fPathInfos.back().tessellateFan(fGeometry, currPathVerbsIdx, currPathPointsIdx,
104 clippedDevIBounds, &currPathPrimitiveCounts);
Chris Dalton84403d72018-02-13 21:46:17 -0500105 }
106
Chris Daltone1639692018-08-20 14:00:30 -0600107 fTotalPrimitiveCounts[(int)scissorTest] += currPathPrimitiveCounts;
Chris Dalton9ca27842018-01-18 12:24:50 -0700108
Chris Dalton916c4982018-08-15 00:53:25 -0600109 if (GrScissorTest::kEnabled == scissorTest) {
110 fScissorSubBatches.push_back() = {fTotalPrimitiveCounts[(int)GrScissorTest::kEnabled],
Chris Dalton9414c962018-06-14 10:14:50 -0600111 clippedDevIBounds.makeOffset(devToAtlasOffset.fX,
112 devToAtlasOffset.fY)};
Chris Dalton9ca27842018-01-18 12:24:50 -0700113 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700114}
115
Chris Daltone1639692018-08-20 14:00:30 -0600116void GrCCFiller::PathInfo::tessellateFan(const GrCCFillGeometry& geometry, int verbsIdx,
117 int ptsIdx, const SkIRect& clippedDevIBounds,
118 PrimitiveTallies* newTriangleCounts) {
119 using Verb = GrCCFillGeometry::Verb;
120 SkASSERT(-1 == fFanTessellationCount);
121 SkASSERT(!fFanTessellation);
122
123 const SkTArray<Verb, true>& verbs = geometry.verbs();
124 const SkTArray<SkPoint, true>& pts = geometry.points();
125
126 newTriangleCounts->fTriangles =
127 newTriangleCounts->fWeightedTriangles = 0;
128
129 // Build an SkPath of the Redbook fan. We use "winding" fill type right now because we are
130 // producing a coverage count, and must fill in every region that has non-zero wind. The
131 // path processor will convert coverage count to the appropriate fill type later.
132 SkPath fan;
133 fan.setFillType(SkPath::kWinding_FillType);
134 SkASSERT(Verb::kBeginPath == verbs[verbsIdx]);
135 for (int i = verbsIdx + 1; i < verbs.count(); ++i) {
136 switch (verbs[i]) {
137 case Verb::kBeginPath:
138 SK_ABORT("Invalid GrCCFillGeometry");
139 continue;
140
141 case Verb::kBeginContour:
142 fan.moveTo(pts[ptsIdx++]);
143 continue;
144
145 case Verb::kLineTo:
146 fan.lineTo(pts[ptsIdx++]);
147 continue;
148
149 case Verb::kMonotonicQuadraticTo:
150 case Verb::kMonotonicConicTo:
151 fan.lineTo(pts[ptsIdx + 1]);
152 ptsIdx += 2;
153 continue;
154
155 case Verb::kMonotonicCubicTo:
156 fan.lineTo(pts[ptsIdx + 2]);
157 ptsIdx += 3;
158 continue;
159
160 case Verb::kEndClosedContour:
161 case Verb::kEndOpenContour:
162 fan.close();
163 continue;
164 }
165 }
166
167 GrTessellator::WindingVertex* vertices = nullptr;
168 fFanTessellationCount =
169 GrTessellator::PathToVertices(fan, std::numeric_limits<float>::infinity(),
170 SkRect::Make(clippedDevIBounds), &vertices);
171 if (fFanTessellationCount <= 0) {
172 SkASSERT(0 == fFanTessellationCount);
173 SkASSERT(nullptr == vertices);
174 return;
175 }
176
177 SkASSERT(0 == fFanTessellationCount % 3);
178 for (int i = 0; i < fFanTessellationCount; i += 3) {
179 int tessWinding = vertices[i].fWinding;
180 SkASSERT(tessWinding == vertices[i + 1].fWinding);
181 SkASSERT(tessWinding == vertices[i + 2].fWinding);
182
183 // Ensure this triangle's points actually wind in the same direction as tessWinding.
184 // CCPR shaders use the sign of wind to determine which direction to bloat, so even for
185 // "wound" triangles the winding sign and point ordering need to agree.
186 float ax = vertices[i].fPos.fX - vertices[i + 1].fPos.fX;
187 float ay = vertices[i].fPos.fY - vertices[i + 1].fPos.fY;
188 float bx = vertices[i].fPos.fX - vertices[i + 2].fPos.fX;
189 float by = vertices[i].fPos.fY - vertices[i + 2].fPos.fY;
190 float wind = ax*by - ay*bx;
191 if ((wind > 0) != (-tessWinding > 0)) { // Tessellator has opposite winding sense.
192 std::swap(vertices[i + 1].fPos, vertices[i + 2].fPos);
193 }
194
195 if (1 == abs(tessWinding)) {
196 ++newTriangleCounts->fTriangles;
197 } else {
198 ++newTriangleCounts->fWeightedTriangles;
199 }
200 }
201
202 fFanTessellation.reset(vertices);
Chris Dalton9ca27842018-01-18 12:24:50 -0700203}
204
Chris Daltone1639692018-08-20 14:00:30 -0600205GrCCFiller::BatchID GrCCFiller::closeCurrentBatch() {
Chris Dalton9ca27842018-01-18 12:24:50 -0700206 SkASSERT(!fInstanceBuffer);
Chris Daltone1639692018-08-20 14:00:30 -0600207 SkASSERT(!fBatches.empty());
Chris Dalton9ca27842018-01-18 12:24:50 -0700208
Chris Daltone1639692018-08-20 14:00:30 -0600209 const auto& lastBatch = fBatches.back();
Chris Daltona883aca2018-03-08 23:05:30 -0700210 int maxMeshes = 1 + fScissorSubBatches.count() - lastBatch.fEndScissorSubBatchIdx;
211 fMaxMeshesPerDraw = SkTMax(fMaxMeshesPerDraw, maxMeshes);
212
213 const auto& lastScissorSubBatch = fScissorSubBatches[lastBatch.fEndScissorSubBatchIdx - 1];
Chris Dalton916c4982018-08-15 00:53:25 -0600214 PrimitiveTallies batchTotalCounts = fTotalPrimitiveCounts[(int)GrScissorTest::kDisabled] -
Chris Dalton84403d72018-02-13 21:46:17 -0500215 lastBatch.fEndNonScissorIndices;
Chris Dalton916c4982018-08-15 00:53:25 -0600216 batchTotalCounts += fTotalPrimitiveCounts[(int)GrScissorTest::kEnabled] -
Chris Dalton84403d72018-02-13 21:46:17 -0500217 lastScissorSubBatch.fEndPrimitiveIndices;
Chris Dalton9ca27842018-01-18 12:24:50 -0700218
Chris Daltona883aca2018-03-08 23:05:30 -0700219 // This will invalidate lastBatch.
Chris Daltone1639692018-08-20 14:00:30 -0600220 fBatches.push_back() = {
Chris Dalton916c4982018-08-15 00:53:25 -0600221 fTotalPrimitiveCounts[(int)GrScissorTest::kDisabled],
Chris Dalton84403d72018-02-13 21:46:17 -0500222 fScissorSubBatches.count(),
223 batchTotalCounts
Chris Dalton9ca27842018-01-18 12:24:50 -0700224 };
Chris Daltone1639692018-08-20 14:00:30 -0600225 return fBatches.count() - 1;
Chris Dalton9ca27842018-01-18 12:24:50 -0700226}
227
228// Emits a contour's triangle fan.
229//
230// Classic Redbook fanning would be the triangles: [0 1 2], [0 2 3], ..., [0 n-2 n-1].
231//
232// This function emits the triangle: [0 n/3 n*2/3], and then recurses on all three sides. The
233// advantage to this approach is that for a convex-ish contour, it generates larger triangles.
234// Classic fanning tends to generate long, skinny triangles, which are expensive to draw since they
235// have a longer perimeter to rasterize and antialias.
236//
237// The indices array indexes the fan's points (think: glDrawElements), and must have at least log3
238// elements past the end for this method to use as scratch space.
239//
240// Returns the next triangle instance after the final one emitted.
Chris Dalton84403d72018-02-13 21:46:17 -0500241static TriPointInstance* emit_recursive_fan(const SkTArray<SkPoint, true>& pts,
Chris Dalton9ca27842018-01-18 12:24:50 -0700242 SkTArray<int32_t, true>& indices, int firstIndex,
Chris Dalton9414c962018-06-14 10:14:50 -0600243 int indexCount, const Sk2f& devToAtlasOffset,
Chris Dalton84403d72018-02-13 21:46:17 -0500244 TriPointInstance out[]) {
Chris Dalton9ca27842018-01-18 12:24:50 -0700245 if (indexCount < 3) {
246 return out;
247 }
248
249 int32_t oneThirdCount = indexCount / 3;
250 int32_t twoThirdsCount = (2 * indexCount) / 3;
251 out++->set(pts[indices[firstIndex]], pts[indices[firstIndex + oneThirdCount]],
Chris Dalton9414c962018-06-14 10:14:50 -0600252 pts[indices[firstIndex + twoThirdsCount]], devToAtlasOffset);
Chris Dalton9ca27842018-01-18 12:24:50 -0700253
Chris Dalton9414c962018-06-14 10:14:50 -0600254 out = emit_recursive_fan(pts, indices, firstIndex, oneThirdCount + 1, devToAtlasOffset, out);
Chris Dalton9ca27842018-01-18 12:24:50 -0700255 out = emit_recursive_fan(pts, indices, firstIndex + oneThirdCount,
Chris Dalton9414c962018-06-14 10:14:50 -0600256 twoThirdsCount - oneThirdCount + 1, devToAtlasOffset, out);
Chris Dalton9ca27842018-01-18 12:24:50 -0700257
258 int endIndex = firstIndex + indexCount;
259 int32_t oldValue = indices[endIndex];
260 indices[endIndex] = indices[firstIndex];
261 out = emit_recursive_fan(pts, indices, firstIndex + twoThirdsCount,
Chris Dalton9414c962018-06-14 10:14:50 -0600262 indexCount - twoThirdsCount + 1, devToAtlasOffset, out);
Chris Dalton9ca27842018-01-18 12:24:50 -0700263 indices[endIndex] = oldValue;
264
265 return out;
266}
267
Chris Dalton84403d72018-02-13 21:46:17 -0500268static void emit_tessellated_fan(const GrTessellator::WindingVertex* vertices, int numVertices,
Chris Dalton9414c962018-06-14 10:14:50 -0600269 const Sk2f& devToAtlasOffset,
270 TriPointInstance* triPointInstanceData,
Chris Dalton84403d72018-02-13 21:46:17 -0500271 QuadPointInstance* quadPointInstanceData,
Chris Daltone1639692018-08-20 14:00:30 -0600272 GrCCFillGeometry::PrimitiveTallies* indices) {
Chris Dalton84403d72018-02-13 21:46:17 -0500273 for (int i = 0; i < numVertices; i += 3) {
274 if (1 == abs(vertices[i].fWinding)) {
275 triPointInstanceData[indices->fTriangles++].set(vertices[i].fPos, vertices[i + 1].fPos,
Chris Dalton9414c962018-06-14 10:14:50 -0600276 vertices[i + 2].fPos, devToAtlasOffset);
Chris Dalton84403d72018-02-13 21:46:17 -0500277 } else {
Chris Dalton703b4762018-04-06 16:11:48 -0600278 quadPointInstanceData[indices->fWeightedTriangles++].setW(
Chris Dalton9414c962018-06-14 10:14:50 -0600279 vertices[i].fPos, vertices[i+1].fPos, vertices[i + 2].fPos, devToAtlasOffset,
Chris Dalton6f5e77a2018-04-23 21:14:42 -0600280 static_cast<float>(abs(vertices[i].fWinding)));
Chris Dalton84403d72018-02-13 21:46:17 -0500281 }
282 }
283}
284
Chris Daltone1639692018-08-20 14:00:30 -0600285bool GrCCFiller::prepareToDraw(GrOnFlushResourceProvider* onFlushRP) {
286 using Verb = GrCCFillGeometry::Verb;
287 SkASSERT(!fInstanceBuffer);
288 SkASSERT(fBatches.back().fEndNonScissorIndices == // Call closeCurrentBatch().
Chris Dalton916c4982018-08-15 00:53:25 -0600289 fTotalPrimitiveCounts[(int)GrScissorTest::kDisabled]);
Chris Daltone1639692018-08-20 14:00:30 -0600290 SkASSERT(fBatches.back().fEndScissorSubBatchIdx == fScissorSubBatches.count());
Chris Dalton9ca27842018-01-18 12:24:50 -0700291
292 // Here we build a single instance buffer to share with every internal batch.
293 //
294 // CCPR processs 3 different types of primitives: triangles, quadratics, cubics. Each primitive
295 // type is further divided into instances that require a scissor and those that don't. This
296 // leaves us with 3*2 = 6 independent instance arrays to build for the GPU.
297 //
298 // Rather than place each instance array in its own GPU buffer, we allocate a single
299 // megabuffer and lay them all out side-by-side. We can offset the "baseInstance" parameter in
300 // our draw calls to direct the GPU to the applicable elements within a given array.
301 //
302 // We already know how big to make each of the 6 arrays from fTotalPrimitiveCounts, so layout is
303 // straightforward. Start with triangles and quadratics. They both view the instance buffer as
Chris Dalton84403d72018-02-13 21:46:17 -0500304 // 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 -0700305 fBaseInstances[0].fTriangles = 0;
306 fBaseInstances[1].fTriangles = fBaseInstances[0].fTriangles +
307 fTotalPrimitiveCounts[0].fTriangles;
308 fBaseInstances[0].fQuadratics = fBaseInstances[1].fTriangles +
309 fTotalPrimitiveCounts[1].fTriangles;
310 fBaseInstances[1].fQuadratics = fBaseInstances[0].fQuadratics +
311 fTotalPrimitiveCounts[0].fQuadratics;
312 int triEndIdx = fBaseInstances[1].fQuadratics + fTotalPrimitiveCounts[1].fQuadratics;
313
Chris Dalton84403d72018-02-13 21:46:17 -0500314 // Wound triangles and cubics both view the same instance buffer as an array of
315 // QuadPointInstance[]. So, reinterpreting the instance data as QuadPointInstance[], we start
316 // them on the first index that will not overwrite previous TriPointInstance data.
317 int quadBaseIdx =
318 GR_CT_DIV_ROUND_UP(triEndIdx * sizeof(TriPointInstance), sizeof(QuadPointInstance));
Chris Dalton703b4762018-04-06 16:11:48 -0600319 fBaseInstances[0].fWeightedTriangles = quadBaseIdx;
320 fBaseInstances[1].fWeightedTriangles = fBaseInstances[0].fWeightedTriangles +
321 fTotalPrimitiveCounts[0].fWeightedTriangles;
322 fBaseInstances[0].fCubics = fBaseInstances[1].fWeightedTriangles +
323 fTotalPrimitiveCounts[1].fWeightedTriangles;
Chris Dalton9ca27842018-01-18 12:24:50 -0700324 fBaseInstances[1].fCubics = fBaseInstances[0].fCubics + fTotalPrimitiveCounts[0].fCubics;
Chris Dalton9f2dab02018-04-18 14:07:03 -0600325 fBaseInstances[0].fConics = fBaseInstances[1].fCubics + fTotalPrimitiveCounts[1].fCubics;
326 fBaseInstances[1].fConics = fBaseInstances[0].fConics + fTotalPrimitiveCounts[0].fConics;
327 int quadEndIdx = fBaseInstances[1].fConics + fTotalPrimitiveCounts[1].fConics;
Chris Dalton9ca27842018-01-18 12:24:50 -0700328
Brian Salomonae64c192019-02-05 09:41:37 -0500329 fInstanceBuffer =
330 onFlushRP->makeBuffer(GrGpuBufferType::kVertex, quadEndIdx * sizeof(QuadPointInstance));
Chris Dalton9ca27842018-01-18 12:24:50 -0700331 if (!fInstanceBuffer) {
Chris Daltone1639692018-08-20 14:00:30 -0600332 SkDebugf("WARNING: failed to allocate CCPR fill instance buffer.\n");
Chris Dalton9ca27842018-01-18 12:24:50 -0700333 return false;
334 }
335
Chris Dalton84403d72018-02-13 21:46:17 -0500336 TriPointInstance* triPointInstanceData = static_cast<TriPointInstance*>(fInstanceBuffer->map());
337 QuadPointInstance* quadPointInstanceData =
338 reinterpret_cast<QuadPointInstance*>(triPointInstanceData);
339 SkASSERT(quadPointInstanceData);
Chris Dalton9ca27842018-01-18 12:24:50 -0700340
Chris Daltone1639692018-08-20 14:00:30 -0600341 PathInfo* nextPathInfo = fPathInfos.begin();
Chris Dalton9414c962018-06-14 10:14:50 -0600342 Sk2f devToAtlasOffset;
Chris Dalton9ca27842018-01-18 12:24:50 -0700343 PrimitiveTallies instanceIndices[2] = {fBaseInstances[0], fBaseInstances[1]};
344 PrimitiveTallies* currIndices = nullptr;
345 SkSTArray<256, int32_t, true> currFan;
Chris Dalton84403d72018-02-13 21:46:17 -0500346 bool currFanIsTessellated = false;
Chris Dalton9ca27842018-01-18 12:24:50 -0700347
348 const SkTArray<SkPoint, true>& pts = fGeometry.points();
Chris Dalton84403d72018-02-13 21:46:17 -0500349 int ptsIdx = -1;
Chris Dalton9f2dab02018-04-18 14:07:03 -0600350 int nextConicWeightIdx = 0;
Chris Dalton9ca27842018-01-18 12:24:50 -0700351
352 // Expand the ccpr verbs into GPU instance buffers.
Chris Daltone1639692018-08-20 14:00:30 -0600353 for (Verb verb : fGeometry.verbs()) {
Chris Dalton9ca27842018-01-18 12:24:50 -0700354 switch (verb) {
Chris Daltone1639692018-08-20 14:00:30 -0600355 case Verb::kBeginPath:
Chris Dalton9ca27842018-01-18 12:24:50 -0700356 SkASSERT(currFan.empty());
Chris Dalton916c4982018-08-15 00:53:25 -0600357 currIndices = &instanceIndices[(int)nextPathInfo->scissorTest()];
Chris Dalton9414c962018-06-14 10:14:50 -0600358 devToAtlasOffset = Sk2f(static_cast<float>(nextPathInfo->devToAtlasOffset().fX),
359 static_cast<float>(nextPathInfo->devToAtlasOffset().fY));
Chris Daltonad065442018-03-08 22:41:33 -0700360 currFanIsTessellated = nextPathInfo->hasFanTessellation();
Chris Dalton84403d72018-02-13 21:46:17 -0500361 if (currFanIsTessellated) {
Chris Daltonad065442018-03-08 22:41:33 -0700362 emit_tessellated_fan(nextPathInfo->fanTessellation(),
Chris Dalton9414c962018-06-14 10:14:50 -0600363 nextPathInfo->fanTessellationCount(), devToAtlasOffset,
Chris Dalton84403d72018-02-13 21:46:17 -0500364 triPointInstanceData, quadPointInstanceData, currIndices);
365 }
366 ++nextPathInfo;
Chris Dalton9ca27842018-01-18 12:24:50 -0700367 continue;
368
Chris Daltone1639692018-08-20 14:00:30 -0600369 case Verb::kBeginContour:
Chris Dalton9ca27842018-01-18 12:24:50 -0700370 SkASSERT(currFan.empty());
Chris Dalton84403d72018-02-13 21:46:17 -0500371 ++ptsIdx;
372 if (!currFanIsTessellated) {
373 currFan.push_back(ptsIdx);
374 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700375 continue;
376
Chris Daltone1639692018-08-20 14:00:30 -0600377 case Verb::kLineTo:
Chris Dalton84403d72018-02-13 21:46:17 -0500378 ++ptsIdx;
379 if (!currFanIsTessellated) {
380 SkASSERT(!currFan.empty());
381 currFan.push_back(ptsIdx);
382 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700383 continue;
384
Chris Daltone1639692018-08-20 14:00:30 -0600385 case Verb::kMonotonicQuadraticTo:
Chris Dalton9414c962018-06-14 10:14:50 -0600386 triPointInstanceData[currIndices->fQuadratics++].set(&pts[ptsIdx],
387 devToAtlasOffset);
Chris Dalton84403d72018-02-13 21:46:17 -0500388 ptsIdx += 2;
389 if (!currFanIsTessellated) {
390 SkASSERT(!currFan.empty());
391 currFan.push_back(ptsIdx);
392 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700393 continue;
394
Chris Daltone1639692018-08-20 14:00:30 -0600395 case Verb::kMonotonicCubicTo:
Chris Dalton9414c962018-06-14 10:14:50 -0600396 quadPointInstanceData[currIndices->fCubics++].set(&pts[ptsIdx], devToAtlasOffset[0],
397 devToAtlasOffset[1]);
Chris Dalton84403d72018-02-13 21:46:17 -0500398 ptsIdx += 3;
399 if (!currFanIsTessellated) {
400 SkASSERT(!currFan.empty());
401 currFan.push_back(ptsIdx);
402 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700403 continue;
404
Chris Daltone1639692018-08-20 14:00:30 -0600405 case Verb::kMonotonicConicTo:
Chris Dalton9f2dab02018-04-18 14:07:03 -0600406 quadPointInstanceData[currIndices->fConics++].setW(
Chris Dalton9414c962018-06-14 10:14:50 -0600407 &pts[ptsIdx], devToAtlasOffset,
408 fGeometry.getConicWeight(nextConicWeightIdx));
Chris Dalton9f2dab02018-04-18 14:07:03 -0600409 ptsIdx += 2;
410 ++nextConicWeightIdx;
411 if (!currFanIsTessellated) {
412 SkASSERT(!currFan.empty());
413 currFan.push_back(ptsIdx);
414 }
415 continue;
416
Chris Daltone1639692018-08-20 14:00:30 -0600417 case Verb::kEndClosedContour: // endPt == startPt.
Chris Dalton84403d72018-02-13 21:46:17 -0500418 if (!currFanIsTessellated) {
419 SkASSERT(!currFan.empty());
420 currFan.pop_back();
421 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700422 // fallthru.
Chris Daltone1639692018-08-20 14:00:30 -0600423 case Verb::kEndOpenContour: // endPt != startPt.
Chris Dalton84403d72018-02-13 21:46:17 -0500424 SkASSERT(!currFanIsTessellated || currFan.empty());
425 if (!currFanIsTessellated && currFan.count() >= 3) {
Chris Dalton9ca27842018-01-18 12:24:50 -0700426 int fanSize = currFan.count();
427 // Reserve space for emit_recursive_fan. Technically this can grow to
428 // fanSize + log3(fanSize), but we approximate with log2.
429 currFan.push_back_n(SkNextLog2(fanSize));
Chris Dalton84403d72018-02-13 21:46:17 -0500430 SkDEBUGCODE(TriPointInstance* end =)
Chris Dalton9414c962018-06-14 10:14:50 -0600431 emit_recursive_fan(pts, currFan, 0, fanSize, devToAtlasOffset,
Chris Dalton84403d72018-02-13 21:46:17 -0500432 triPointInstanceData + currIndices->fTriangles);
Chris Dalton9ca27842018-01-18 12:24:50 -0700433 currIndices->fTriangles += fanSize - 2;
Chris Dalton84403d72018-02-13 21:46:17 -0500434 SkASSERT(triPointInstanceData + currIndices->fTriangles == end);
Chris Dalton9ca27842018-01-18 12:24:50 -0700435 }
436 currFan.reset();
437 continue;
438 }
439 }
440
441 fInstanceBuffer->unmap();
442
Chris Daltone1639692018-08-20 14:00:30 -0600443 SkASSERT(nextPathInfo == fPathInfos.end());
Chris Dalton9ca27842018-01-18 12:24:50 -0700444 SkASSERT(ptsIdx == pts.count() - 1);
445 SkASSERT(instanceIndices[0].fTriangles == fBaseInstances[1].fTriangles);
446 SkASSERT(instanceIndices[1].fTriangles == fBaseInstances[0].fQuadratics);
447 SkASSERT(instanceIndices[0].fQuadratics == fBaseInstances[1].fQuadratics);
448 SkASSERT(instanceIndices[1].fQuadratics == triEndIdx);
Chris Dalton703b4762018-04-06 16:11:48 -0600449 SkASSERT(instanceIndices[0].fWeightedTriangles == fBaseInstances[1].fWeightedTriangles);
450 SkASSERT(instanceIndices[1].fWeightedTriangles == fBaseInstances[0].fCubics);
Chris Dalton9ca27842018-01-18 12:24:50 -0700451 SkASSERT(instanceIndices[0].fCubics == fBaseInstances[1].fCubics);
Chris Dalton9f2dab02018-04-18 14:07:03 -0600452 SkASSERT(instanceIndices[1].fCubics == fBaseInstances[0].fConics);
453 SkASSERT(instanceIndices[0].fConics == fBaseInstances[1].fConics);
454 SkASSERT(instanceIndices[1].fConics == quadEndIdx);
Chris Dalton9ca27842018-01-18 12:24:50 -0700455
456 fMeshesScratchBuffer.reserve(fMaxMeshesPerDraw);
Brian Salomon49348902018-06-26 09:12:38 -0400457 fScissorRectScratchBuffer.reserve(fMaxMeshesPerDraw);
Chris Dalton9ca27842018-01-18 12:24:50 -0700458
459 return true;
460}
461
Chris Daltone1639692018-08-20 14:00:30 -0600462void GrCCFiller::drawFills(GrOpFlushState* flushState, BatchID batchID,
463 const SkIRect& drawBounds) const {
Chris Dalton8dfc70f2018-03-26 19:15:22 -0600464 using PrimitiveType = GrCCCoverageProcessor::PrimitiveType;
Chris Dalton9ca27842018-01-18 12:24:50 -0700465
466 SkASSERT(fInstanceBuffer);
467
Chris Daltone1639692018-08-20 14:00:30 -0600468 const PrimitiveTallies& batchTotalCounts = fBatches[batchID].fTotalPrimitiveCounts;
Chris Dalton84403d72018-02-13 21:46:17 -0500469
Robert Phillipsd0fe8752019-01-31 14:13:59 -0500470 GrPipeline pipeline(GrScissorTest::kEnabled, SkBlendMode::kPlus);
Chris Dalton9ca27842018-01-18 12:24:50 -0700471
Chris Dalton84403d72018-02-13 21:46:17 -0500472 if (batchTotalCounts.fTriangles) {
Chris Dalton8dfc70f2018-03-26 19:15:22 -0600473 this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kTriangles,
Chris Dalton703b4762018-04-06 16:11:48 -0600474 &PrimitiveTallies::fTriangles, drawBounds);
Chris Dalton84403d72018-02-13 21:46:17 -0500475 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700476
Chris Dalton703b4762018-04-06 16:11:48 -0600477 if (batchTotalCounts.fWeightedTriangles) {
478 this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kWeightedTriangles,
479 &PrimitiveTallies::fWeightedTriangles, drawBounds);
Chris Dalton84403d72018-02-13 21:46:17 -0500480 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700481
Chris Dalton84403d72018-02-13 21:46:17 -0500482 if (batchTotalCounts.fQuadratics) {
Chris Dalton8dfc70f2018-03-26 19:15:22 -0600483 this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kQuadratics,
Chris Dalton703b4762018-04-06 16:11:48 -0600484 &PrimitiveTallies::fQuadratics, drawBounds);
Chris Dalton84403d72018-02-13 21:46:17 -0500485 }
486
487 if (batchTotalCounts.fCubics) {
Chris Dalton8dfc70f2018-03-26 19:15:22 -0600488 this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kCubics,
Chris Dalton703b4762018-04-06 16:11:48 -0600489 &PrimitiveTallies::fCubics, drawBounds);
Chris Dalton84403d72018-02-13 21:46:17 -0500490 }
Chris Dalton9f2dab02018-04-18 14:07:03 -0600491
492 if (batchTotalCounts.fConics) {
493 this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kConics,
494 &PrimitiveTallies::fConics, drawBounds);
495 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700496}
497
Chris Daltone1639692018-08-20 14:00:30 -0600498void GrCCFiller::drawPrimitives(GrOpFlushState* flushState, const GrPipeline& pipeline,
499 BatchID batchID, GrCCCoverageProcessor::PrimitiveType primitiveType,
500 int PrimitiveTallies::*instanceType,
501 const SkIRect& drawBounds) const {
Brian Salomond818ebf2018-07-02 14:08:49 +0000502 SkASSERT(pipeline.isScissorEnabled());
Chris Dalton9ca27842018-01-18 12:24:50 -0700503
Chris Dalton9ca27842018-01-18 12:24:50 -0700504 // Don't call reset(), as that also resets the reserve count.
505 fMeshesScratchBuffer.pop_back_n(fMeshesScratchBuffer.count());
Brian Salomon49348902018-06-26 09:12:38 -0400506 fScissorRectScratchBuffer.pop_back_n(fScissorRectScratchBuffer.count());
Chris Dalton9ca27842018-01-18 12:24:50 -0700507
Chris Dalton703b4762018-04-06 16:11:48 -0600508 GrCCCoverageProcessor proc(flushState->resourceProvider(), primitiveType);
Chris Dalton9ca27842018-01-18 12:24:50 -0700509
510 SkASSERT(batchID > 0);
Chris Daltone1639692018-08-20 14:00:30 -0600511 SkASSERT(batchID < fBatches.count());
512 const Batch& previousBatch = fBatches[batchID - 1];
513 const Batch& batch = fBatches[batchID];
Chris Dalton84403d72018-02-13 21:46:17 -0500514 SkDEBUGCODE(int totalInstanceCount = 0);
Chris Dalton9ca27842018-01-18 12:24:50 -0700515
516 if (int instanceCount = batch.fEndNonScissorIndices.*instanceType -
517 previousBatch.fEndNonScissorIndices.*instanceType) {
518 SkASSERT(instanceCount > 0);
Chris Dalton916c4982018-08-15 00:53:25 -0600519 int baseInstance = fBaseInstances[(int)GrScissorTest::kDisabled].*instanceType +
Chris Dalton9ca27842018-01-18 12:24:50 -0700520 previousBatch.fEndNonScissorIndices.*instanceType;
Brian Salomon12d22642019-01-29 14:38:50 -0500521 proc.appendMesh(fInstanceBuffer, instanceCount, baseInstance, &fMeshesScratchBuffer);
Brian Salomon49348902018-06-26 09:12:38 -0400522 fScissorRectScratchBuffer.push_back().setXYWH(0, 0, drawBounds.width(),
523 drawBounds.height());
Chris Dalton84403d72018-02-13 21:46:17 -0500524 SkDEBUGCODE(totalInstanceCount += instanceCount);
Chris Dalton9ca27842018-01-18 12:24:50 -0700525 }
526
527 SkASSERT(previousBatch.fEndScissorSubBatchIdx > 0);
528 SkASSERT(batch.fEndScissorSubBatchIdx <= fScissorSubBatches.count());
Chris Dalton916c4982018-08-15 00:53:25 -0600529 int baseScissorInstance = fBaseInstances[(int)GrScissorTest::kEnabled].*instanceType;
Chris Dalton9ca27842018-01-18 12:24:50 -0700530 for (int i = previousBatch.fEndScissorSubBatchIdx; i < batch.fEndScissorSubBatchIdx; ++i) {
531 const ScissorSubBatch& previousSubBatch = fScissorSubBatches[i - 1];
532 const ScissorSubBatch& scissorSubBatch = fScissorSubBatches[i];
533 int startIndex = previousSubBatch.fEndPrimitiveIndices.*instanceType;
534 int instanceCount = scissorSubBatch.fEndPrimitiveIndices.*instanceType - startIndex;
535 if (!instanceCount) {
536 continue;
537 }
538 SkASSERT(instanceCount > 0);
Brian Salomon12d22642019-01-29 14:38:50 -0500539 proc.appendMesh(fInstanceBuffer, instanceCount, baseScissorInstance + startIndex,
540 &fMeshesScratchBuffer);
Brian Salomon49348902018-06-26 09:12:38 -0400541 fScissorRectScratchBuffer.push_back() = scissorSubBatch.fScissor;
Chris Dalton84403d72018-02-13 21:46:17 -0500542 SkDEBUGCODE(totalInstanceCount += instanceCount);
Chris Dalton9ca27842018-01-18 12:24:50 -0700543 }
544
Brian Salomon49348902018-06-26 09:12:38 -0400545 SkASSERT(fMeshesScratchBuffer.count() == fScissorRectScratchBuffer.count());
Chris Dalton9ca27842018-01-18 12:24:50 -0700546 SkASSERT(fMeshesScratchBuffer.count() <= fMaxMeshesPerDraw);
Chris Dalton84403d72018-02-13 21:46:17 -0500547 SkASSERT(totalInstanceCount == batch.fTotalPrimitiveCounts.*instanceType);
Chris Dalton9ca27842018-01-18 12:24:50 -0700548
549 if (!fMeshesScratchBuffer.empty()) {
Brian Salomon49348902018-06-26 09:12:38 -0400550 proc.draw(flushState, pipeline, fScissorRectScratchBuffer.begin(),
551 fMeshesScratchBuffer.begin(), fMeshesScratchBuffer.count(),
Chris Dalton8dfc70f2018-03-26 19:15:22 -0600552 SkRect::Make(drawBounds));
Chris Dalton9ca27842018-01-18 12:24:50 -0700553 }
554}