blob: cdace98705455e1535367ebbcf25b2c0ad893edc [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 Dalton02e6efe2018-08-31 14:45:19 +000023GrCCFiller::GrCCFiller(int numPaths, const PathStats& pathStats)
24 : fGeometry(pathStats.fNumTotalSkPoints, pathStats.fNumTotalSkVerbs,
25 pathStats.fNumTotalConicWeights)
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 Daltone1639692018-08-20 14:00:30 -0600104 fPathInfos.back().tessellateFan(fGeometry, currPathVerbsIdx, currPathPointsIdx,
105 clippedDevIBounds, &currPathPrimitiveCounts);
Chris Dalton84403d72018-02-13 21:46:17 -0500106 }
107
Chris Daltone1639692018-08-20 14:00:30 -0600108 fTotalPrimitiveCounts[(int)scissorTest] += currPathPrimitiveCounts;
Chris Dalton9ca27842018-01-18 12:24:50 -0700109
Chris Dalton916c4982018-08-15 00:53:25 -0600110 if (GrScissorTest::kEnabled == scissorTest) {
111 fScissorSubBatches.push_back() = {fTotalPrimitiveCounts[(int)GrScissorTest::kEnabled],
Chris Dalton9414c962018-06-14 10:14:50 -0600112 clippedDevIBounds.makeOffset(devToAtlasOffset.fX,
113 devToAtlasOffset.fY)};
Chris Dalton9ca27842018-01-18 12:24:50 -0700114 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700115}
116
Chris Daltone1639692018-08-20 14:00:30 -0600117void GrCCFiller::PathInfo::tessellateFan(const GrCCFillGeometry& geometry, int verbsIdx,
118 int ptsIdx, const SkIRect& clippedDevIBounds,
119 PrimitiveTallies* newTriangleCounts) {
120 using Verb = GrCCFillGeometry::Verb;
121 SkASSERT(-1 == fFanTessellationCount);
122 SkASSERT(!fFanTessellation);
123
124 const SkTArray<Verb, true>& verbs = geometry.verbs();
125 const SkTArray<SkPoint, true>& pts = geometry.points();
126
127 newTriangleCounts->fTriangles =
128 newTriangleCounts->fWeightedTriangles = 0;
129
130 // Build an SkPath of the Redbook fan. We use "winding" fill type right now because we are
131 // producing a coverage count, and must fill in every region that has non-zero wind. The
132 // path processor will convert coverage count to the appropriate fill type later.
133 SkPath fan;
134 fan.setFillType(SkPath::kWinding_FillType);
135 SkASSERT(Verb::kBeginPath == verbs[verbsIdx]);
136 for (int i = verbsIdx + 1; i < verbs.count(); ++i) {
137 switch (verbs[i]) {
138 case Verb::kBeginPath:
139 SK_ABORT("Invalid GrCCFillGeometry");
140 continue;
141
142 case Verb::kBeginContour:
143 fan.moveTo(pts[ptsIdx++]);
144 continue;
145
146 case Verb::kLineTo:
147 fan.lineTo(pts[ptsIdx++]);
148 continue;
149
150 case Verb::kMonotonicQuadraticTo:
151 case Verb::kMonotonicConicTo:
152 fan.lineTo(pts[ptsIdx + 1]);
153 ptsIdx += 2;
154 continue;
155
156 case Verb::kMonotonicCubicTo:
157 fan.lineTo(pts[ptsIdx + 2]);
158 ptsIdx += 3;
159 continue;
160
161 case Verb::kEndClosedContour:
162 case Verb::kEndOpenContour:
163 fan.close();
164 continue;
165 }
166 }
167
168 GrTessellator::WindingVertex* vertices = nullptr;
169 fFanTessellationCount =
170 GrTessellator::PathToVertices(fan, std::numeric_limits<float>::infinity(),
171 SkRect::Make(clippedDevIBounds), &vertices);
172 if (fFanTessellationCount <= 0) {
173 SkASSERT(0 == fFanTessellationCount);
174 SkASSERT(nullptr == vertices);
175 return;
176 }
177
178 SkASSERT(0 == fFanTessellationCount % 3);
179 for (int i = 0; i < fFanTessellationCount; i += 3) {
180 int tessWinding = vertices[i].fWinding;
181 SkASSERT(tessWinding == vertices[i + 1].fWinding);
182 SkASSERT(tessWinding == vertices[i + 2].fWinding);
183
184 // Ensure this triangle's points actually wind in the same direction as tessWinding.
185 // CCPR shaders use the sign of wind to determine which direction to bloat, so even for
186 // "wound" triangles the winding sign and point ordering need to agree.
187 float ax = vertices[i].fPos.fX - vertices[i + 1].fPos.fX;
188 float ay = vertices[i].fPos.fY - vertices[i + 1].fPos.fY;
189 float bx = vertices[i].fPos.fX - vertices[i + 2].fPos.fX;
190 float by = vertices[i].fPos.fY - vertices[i + 2].fPos.fY;
191 float wind = ax*by - ay*bx;
192 if ((wind > 0) != (-tessWinding > 0)) { // Tessellator has opposite winding sense.
193 std::swap(vertices[i + 1].fPos, vertices[i + 2].fPos);
194 }
195
196 if (1 == abs(tessWinding)) {
197 ++newTriangleCounts->fTriangles;
198 } else {
199 ++newTriangleCounts->fWeightedTriangles;
200 }
201 }
202
203 fFanTessellation.reset(vertices);
Chris Dalton9ca27842018-01-18 12:24:50 -0700204}
205
Chris Daltone1639692018-08-20 14:00:30 -0600206GrCCFiller::BatchID GrCCFiller::closeCurrentBatch() {
Chris Dalton9ca27842018-01-18 12:24:50 -0700207 SkASSERT(!fInstanceBuffer);
Chris Daltone1639692018-08-20 14:00:30 -0600208 SkASSERT(!fBatches.empty());
Chris Dalton9ca27842018-01-18 12:24:50 -0700209
Chris Daltone1639692018-08-20 14:00:30 -0600210 const auto& lastBatch = fBatches.back();
Chris Daltona883aca2018-03-08 23:05:30 -0700211 int maxMeshes = 1 + fScissorSubBatches.count() - lastBatch.fEndScissorSubBatchIdx;
212 fMaxMeshesPerDraw = SkTMax(fMaxMeshesPerDraw, maxMeshes);
213
214 const auto& lastScissorSubBatch = fScissorSubBatches[lastBatch.fEndScissorSubBatchIdx - 1];
Chris Dalton916c4982018-08-15 00:53:25 -0600215 PrimitiveTallies batchTotalCounts = fTotalPrimitiveCounts[(int)GrScissorTest::kDisabled] -
Chris Dalton84403d72018-02-13 21:46:17 -0500216 lastBatch.fEndNonScissorIndices;
Chris Dalton916c4982018-08-15 00:53:25 -0600217 batchTotalCounts += fTotalPrimitiveCounts[(int)GrScissorTest::kEnabled] -
Chris Dalton84403d72018-02-13 21:46:17 -0500218 lastScissorSubBatch.fEndPrimitiveIndices;
Chris Dalton9ca27842018-01-18 12:24:50 -0700219
Chris Daltona883aca2018-03-08 23:05:30 -0700220 // This will invalidate lastBatch.
Chris Daltone1639692018-08-20 14:00:30 -0600221 fBatches.push_back() = {
Chris Dalton916c4982018-08-15 00:53:25 -0600222 fTotalPrimitiveCounts[(int)GrScissorTest::kDisabled],
Chris Dalton84403d72018-02-13 21:46:17 -0500223 fScissorSubBatches.count(),
224 batchTotalCounts
Chris Dalton9ca27842018-01-18 12:24:50 -0700225 };
Chris Daltone1639692018-08-20 14:00:30 -0600226 return fBatches.count() - 1;
Chris Dalton9ca27842018-01-18 12:24:50 -0700227}
228
229// Emits a contour's triangle fan.
230//
231// Classic Redbook fanning would be the triangles: [0 1 2], [0 2 3], ..., [0 n-2 n-1].
232//
233// This function emits the triangle: [0 n/3 n*2/3], and then recurses on all three sides. The
234// advantage to this approach is that for a convex-ish contour, it generates larger triangles.
235// Classic fanning tends to generate long, skinny triangles, which are expensive to draw since they
236// have a longer perimeter to rasterize and antialias.
237//
238// The indices array indexes the fan's points (think: glDrawElements), and must have at least log3
239// elements past the end for this method to use as scratch space.
240//
241// Returns the next triangle instance after the final one emitted.
Chris Dalton84403d72018-02-13 21:46:17 -0500242static TriPointInstance* emit_recursive_fan(const SkTArray<SkPoint, true>& pts,
Chris Dalton9ca27842018-01-18 12:24:50 -0700243 SkTArray<int32_t, true>& indices, int firstIndex,
Chris Dalton9414c962018-06-14 10:14:50 -0600244 int indexCount, const Sk2f& devToAtlasOffset,
Chris Dalton84403d72018-02-13 21:46:17 -0500245 TriPointInstance out[]) {
Chris Dalton9ca27842018-01-18 12:24:50 -0700246 if (indexCount < 3) {
247 return out;
248 }
249
250 int32_t oneThirdCount = indexCount / 3;
251 int32_t twoThirdsCount = (2 * indexCount) / 3;
252 out++->set(pts[indices[firstIndex]], pts[indices[firstIndex + oneThirdCount]],
Chris Dalton9414c962018-06-14 10:14:50 -0600253 pts[indices[firstIndex + twoThirdsCount]], devToAtlasOffset);
Chris Dalton9ca27842018-01-18 12:24:50 -0700254
Chris Dalton9414c962018-06-14 10:14:50 -0600255 out = emit_recursive_fan(pts, indices, firstIndex, oneThirdCount + 1, devToAtlasOffset, out);
Chris Dalton9ca27842018-01-18 12:24:50 -0700256 out = emit_recursive_fan(pts, indices, firstIndex + oneThirdCount,
Chris Dalton9414c962018-06-14 10:14:50 -0600257 twoThirdsCount - oneThirdCount + 1, devToAtlasOffset, out);
Chris Dalton9ca27842018-01-18 12:24:50 -0700258
259 int endIndex = firstIndex + indexCount;
260 int32_t oldValue = indices[endIndex];
261 indices[endIndex] = indices[firstIndex];
262 out = emit_recursive_fan(pts, indices, firstIndex + twoThirdsCount,
Chris Dalton9414c962018-06-14 10:14:50 -0600263 indexCount - twoThirdsCount + 1, devToAtlasOffset, out);
Chris Dalton9ca27842018-01-18 12:24:50 -0700264 indices[endIndex] = oldValue;
265
266 return out;
267}
268
Chris Dalton84403d72018-02-13 21:46:17 -0500269static void emit_tessellated_fan(const GrTessellator::WindingVertex* vertices, int numVertices,
Chris Dalton9414c962018-06-14 10:14:50 -0600270 const Sk2f& devToAtlasOffset,
271 TriPointInstance* triPointInstanceData,
Chris Dalton84403d72018-02-13 21:46:17 -0500272 QuadPointInstance* quadPointInstanceData,
Chris Daltone1639692018-08-20 14:00:30 -0600273 GrCCFillGeometry::PrimitiveTallies* indices) {
Chris Dalton84403d72018-02-13 21:46:17 -0500274 for (int i = 0; i < numVertices; i += 3) {
275 if (1 == abs(vertices[i].fWinding)) {
276 triPointInstanceData[indices->fTriangles++].set(vertices[i].fPos, vertices[i + 1].fPos,
Chris Dalton9414c962018-06-14 10:14:50 -0600277 vertices[i + 2].fPos, devToAtlasOffset);
Chris Dalton84403d72018-02-13 21:46:17 -0500278 } else {
Chris Dalton703b4762018-04-06 16:11:48 -0600279 quadPointInstanceData[indices->fWeightedTriangles++].setW(
Chris Dalton9414c962018-06-14 10:14:50 -0600280 vertices[i].fPos, vertices[i+1].fPos, vertices[i + 2].fPos, devToAtlasOffset,
Chris Dalton6f5e77a2018-04-23 21:14:42 -0600281 static_cast<float>(abs(vertices[i].fWinding)));
Chris Dalton84403d72018-02-13 21:46:17 -0500282 }
283 }
284}
285
Chris Daltone1639692018-08-20 14:00:30 -0600286bool GrCCFiller::prepareToDraw(GrOnFlushResourceProvider* onFlushRP) {
287 using Verb = GrCCFillGeometry::Verb;
288 SkASSERT(!fInstanceBuffer);
289 SkASSERT(fBatches.back().fEndNonScissorIndices == // Call closeCurrentBatch().
Chris Dalton916c4982018-08-15 00:53:25 -0600290 fTotalPrimitiveCounts[(int)GrScissorTest::kDisabled]);
Chris Daltone1639692018-08-20 14:00:30 -0600291 SkASSERT(fBatches.back().fEndScissorSubBatchIdx == fScissorSubBatches.count());
Chris Dalton9ca27842018-01-18 12:24:50 -0700292
293 // Here we build a single instance buffer to share with every internal batch.
294 //
295 // CCPR processs 3 different types of primitives: triangles, quadratics, cubics. Each primitive
296 // type is further divided into instances that require a scissor and those that don't. This
297 // leaves us with 3*2 = 6 independent instance arrays to build for the GPU.
298 //
299 // Rather than place each instance array in its own GPU buffer, we allocate a single
300 // megabuffer and lay them all out side-by-side. We can offset the "baseInstance" parameter in
301 // our draw calls to direct the GPU to the applicable elements within a given array.
302 //
303 // We already know how big to make each of the 6 arrays from fTotalPrimitiveCounts, so layout is
304 // straightforward. Start with triangles and quadratics. They both view the instance buffer as
Chris Dalton84403d72018-02-13 21:46:17 -0500305 // 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 -0700306 fBaseInstances[0].fTriangles = 0;
307 fBaseInstances[1].fTriangles = fBaseInstances[0].fTriangles +
308 fTotalPrimitiveCounts[0].fTriangles;
309 fBaseInstances[0].fQuadratics = fBaseInstances[1].fTriangles +
310 fTotalPrimitiveCounts[1].fTriangles;
311 fBaseInstances[1].fQuadratics = fBaseInstances[0].fQuadratics +
312 fTotalPrimitiveCounts[0].fQuadratics;
313 int triEndIdx = fBaseInstances[1].fQuadratics + fTotalPrimitiveCounts[1].fQuadratics;
314
Chris Dalton84403d72018-02-13 21:46:17 -0500315 // Wound triangles and cubics both view the same instance buffer as an array of
316 // QuadPointInstance[]. So, reinterpreting the instance data as QuadPointInstance[], we start
317 // them on the first index that will not overwrite previous TriPointInstance data.
318 int quadBaseIdx =
319 GR_CT_DIV_ROUND_UP(triEndIdx * sizeof(TriPointInstance), sizeof(QuadPointInstance));
Chris Dalton703b4762018-04-06 16:11:48 -0600320 fBaseInstances[0].fWeightedTriangles = quadBaseIdx;
321 fBaseInstances[1].fWeightedTriangles = fBaseInstances[0].fWeightedTriangles +
322 fTotalPrimitiveCounts[0].fWeightedTriangles;
323 fBaseInstances[0].fCubics = fBaseInstances[1].fWeightedTriangles +
324 fTotalPrimitiveCounts[1].fWeightedTriangles;
Chris Dalton9ca27842018-01-18 12:24:50 -0700325 fBaseInstances[1].fCubics = fBaseInstances[0].fCubics + fTotalPrimitiveCounts[0].fCubics;
Chris Dalton9f2dab02018-04-18 14:07:03 -0600326 fBaseInstances[0].fConics = fBaseInstances[1].fCubics + fTotalPrimitiveCounts[1].fCubics;
327 fBaseInstances[1].fConics = fBaseInstances[0].fConics + fTotalPrimitiveCounts[0].fConics;
328 int quadEndIdx = fBaseInstances[1].fConics + fTotalPrimitiveCounts[1].fConics;
Chris Dalton9ca27842018-01-18 12:24:50 -0700329
330 fInstanceBuffer = onFlushRP->makeBuffer(kVertex_GrBufferType,
Chris Dalton84403d72018-02-13 21:46:17 -0500331 quadEndIdx * sizeof(QuadPointInstance));
Chris Dalton9ca27842018-01-18 12:24:50 -0700332 if (!fInstanceBuffer) {
Chris Daltone1639692018-08-20 14:00:30 -0600333 SkDebugf("WARNING: failed to allocate CCPR fill instance buffer.\n");
Chris Dalton9ca27842018-01-18 12:24:50 -0700334 return false;
335 }
336
Chris Dalton84403d72018-02-13 21:46:17 -0500337 TriPointInstance* triPointInstanceData = static_cast<TriPointInstance*>(fInstanceBuffer->map());
338 QuadPointInstance* quadPointInstanceData =
339 reinterpret_cast<QuadPointInstance*>(triPointInstanceData);
340 SkASSERT(quadPointInstanceData);
Chris Dalton9ca27842018-01-18 12:24:50 -0700341
Chris Daltone1639692018-08-20 14:00:30 -0600342 PathInfo* nextPathInfo = fPathInfos.begin();
Chris Dalton9414c962018-06-14 10:14:50 -0600343 Sk2f devToAtlasOffset;
Chris Dalton9ca27842018-01-18 12:24:50 -0700344 PrimitiveTallies instanceIndices[2] = {fBaseInstances[0], fBaseInstances[1]};
345 PrimitiveTallies* currIndices = nullptr;
346 SkSTArray<256, int32_t, true> currFan;
Chris Dalton84403d72018-02-13 21:46:17 -0500347 bool currFanIsTessellated = false;
Chris Dalton9ca27842018-01-18 12:24:50 -0700348
349 const SkTArray<SkPoint, true>& pts = fGeometry.points();
Chris Dalton84403d72018-02-13 21:46:17 -0500350 int ptsIdx = -1;
Chris Dalton9f2dab02018-04-18 14:07:03 -0600351 int nextConicWeightIdx = 0;
Chris Dalton9ca27842018-01-18 12:24:50 -0700352
353 // Expand the ccpr verbs into GPU instance buffers.
Chris Daltone1639692018-08-20 14:00:30 -0600354 for (Verb verb : fGeometry.verbs()) {
Chris Dalton9ca27842018-01-18 12:24:50 -0700355 switch (verb) {
Chris Daltone1639692018-08-20 14:00:30 -0600356 case Verb::kBeginPath:
Chris Dalton9ca27842018-01-18 12:24:50 -0700357 SkASSERT(currFan.empty());
Chris Dalton916c4982018-08-15 00:53:25 -0600358 currIndices = &instanceIndices[(int)nextPathInfo->scissorTest()];
Chris Dalton9414c962018-06-14 10:14:50 -0600359 devToAtlasOffset = Sk2f(static_cast<float>(nextPathInfo->devToAtlasOffset().fX),
360 static_cast<float>(nextPathInfo->devToAtlasOffset().fY));
Chris Daltonad065442018-03-08 22:41:33 -0700361 currFanIsTessellated = nextPathInfo->hasFanTessellation();
Chris Dalton84403d72018-02-13 21:46:17 -0500362 if (currFanIsTessellated) {
Chris Daltonad065442018-03-08 22:41:33 -0700363 emit_tessellated_fan(nextPathInfo->fanTessellation(),
Chris Dalton9414c962018-06-14 10:14:50 -0600364 nextPathInfo->fanTessellationCount(), devToAtlasOffset,
Chris Dalton84403d72018-02-13 21:46:17 -0500365 triPointInstanceData, quadPointInstanceData, currIndices);
366 }
367 ++nextPathInfo;
Chris Dalton9ca27842018-01-18 12:24:50 -0700368 continue;
369
Chris Daltone1639692018-08-20 14:00:30 -0600370 case Verb::kBeginContour:
Chris Dalton9ca27842018-01-18 12:24:50 -0700371 SkASSERT(currFan.empty());
Chris Dalton84403d72018-02-13 21:46:17 -0500372 ++ptsIdx;
373 if (!currFanIsTessellated) {
374 currFan.push_back(ptsIdx);
375 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700376 continue;
377
Chris Daltone1639692018-08-20 14:00:30 -0600378 case Verb::kLineTo:
Chris Dalton84403d72018-02-13 21:46:17 -0500379 ++ptsIdx;
380 if (!currFanIsTessellated) {
381 SkASSERT(!currFan.empty());
382 currFan.push_back(ptsIdx);
383 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700384 continue;
385
Chris Daltone1639692018-08-20 14:00:30 -0600386 case Verb::kMonotonicQuadraticTo:
Chris Dalton9414c962018-06-14 10:14:50 -0600387 triPointInstanceData[currIndices->fQuadratics++].set(&pts[ptsIdx],
388 devToAtlasOffset);
Chris Dalton84403d72018-02-13 21:46:17 -0500389 ptsIdx += 2;
390 if (!currFanIsTessellated) {
391 SkASSERT(!currFan.empty());
392 currFan.push_back(ptsIdx);
393 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700394 continue;
395
Chris Daltone1639692018-08-20 14:00:30 -0600396 case Verb::kMonotonicCubicTo:
Chris Dalton9414c962018-06-14 10:14:50 -0600397 quadPointInstanceData[currIndices->fCubics++].set(&pts[ptsIdx], devToAtlasOffset[0],
398 devToAtlasOffset[1]);
Chris Dalton84403d72018-02-13 21:46:17 -0500399 ptsIdx += 3;
400 if (!currFanIsTessellated) {
401 SkASSERT(!currFan.empty());
402 currFan.push_back(ptsIdx);
403 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700404 continue;
405
Chris Daltone1639692018-08-20 14:00:30 -0600406 case Verb::kMonotonicConicTo:
Chris Dalton9f2dab02018-04-18 14:07:03 -0600407 quadPointInstanceData[currIndices->fConics++].setW(
Chris Dalton9414c962018-06-14 10:14:50 -0600408 &pts[ptsIdx], devToAtlasOffset,
409 fGeometry.getConicWeight(nextConicWeightIdx));
Chris Dalton9f2dab02018-04-18 14:07:03 -0600410 ptsIdx += 2;
411 ++nextConicWeightIdx;
412 if (!currFanIsTessellated) {
413 SkASSERT(!currFan.empty());
414 currFan.push_back(ptsIdx);
415 }
416 continue;
417
Chris Daltone1639692018-08-20 14:00:30 -0600418 case Verb::kEndClosedContour: // endPt == startPt.
Chris Dalton84403d72018-02-13 21:46:17 -0500419 if (!currFanIsTessellated) {
420 SkASSERT(!currFan.empty());
421 currFan.pop_back();
422 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700423 // fallthru.
Chris Daltone1639692018-08-20 14:00:30 -0600424 case Verb::kEndOpenContour: // endPt != startPt.
Chris Dalton84403d72018-02-13 21:46:17 -0500425 SkASSERT(!currFanIsTessellated || currFan.empty());
426 if (!currFanIsTessellated && currFan.count() >= 3) {
Chris Dalton9ca27842018-01-18 12:24:50 -0700427 int fanSize = currFan.count();
428 // Reserve space for emit_recursive_fan. Technically this can grow to
429 // fanSize + log3(fanSize), but we approximate with log2.
430 currFan.push_back_n(SkNextLog2(fanSize));
Chris Dalton84403d72018-02-13 21:46:17 -0500431 SkDEBUGCODE(TriPointInstance* end =)
Chris Dalton9414c962018-06-14 10:14:50 -0600432 emit_recursive_fan(pts, currFan, 0, fanSize, devToAtlasOffset,
Chris Dalton84403d72018-02-13 21:46:17 -0500433 triPointInstanceData + currIndices->fTriangles);
Chris Dalton9ca27842018-01-18 12:24:50 -0700434 currIndices->fTriangles += fanSize - 2;
Chris Dalton84403d72018-02-13 21:46:17 -0500435 SkASSERT(triPointInstanceData + currIndices->fTriangles == end);
Chris Dalton9ca27842018-01-18 12:24:50 -0700436 }
437 currFan.reset();
438 continue;
439 }
440 }
441
442 fInstanceBuffer->unmap();
443
Chris Daltone1639692018-08-20 14:00:30 -0600444 SkASSERT(nextPathInfo == fPathInfos.end());
Chris Dalton9ca27842018-01-18 12:24:50 -0700445 SkASSERT(ptsIdx == pts.count() - 1);
446 SkASSERT(instanceIndices[0].fTriangles == fBaseInstances[1].fTriangles);
447 SkASSERT(instanceIndices[1].fTriangles == fBaseInstances[0].fQuadratics);
448 SkASSERT(instanceIndices[0].fQuadratics == fBaseInstances[1].fQuadratics);
449 SkASSERT(instanceIndices[1].fQuadratics == triEndIdx);
Chris Dalton703b4762018-04-06 16:11:48 -0600450 SkASSERT(instanceIndices[0].fWeightedTriangles == fBaseInstances[1].fWeightedTriangles);
451 SkASSERT(instanceIndices[1].fWeightedTriangles == fBaseInstances[0].fCubics);
Chris Dalton9ca27842018-01-18 12:24:50 -0700452 SkASSERT(instanceIndices[0].fCubics == fBaseInstances[1].fCubics);
Chris Dalton9f2dab02018-04-18 14:07:03 -0600453 SkASSERT(instanceIndices[1].fCubics == fBaseInstances[0].fConics);
454 SkASSERT(instanceIndices[0].fConics == fBaseInstances[1].fConics);
455 SkASSERT(instanceIndices[1].fConics == quadEndIdx);
Chris Dalton9ca27842018-01-18 12:24:50 -0700456
457 fMeshesScratchBuffer.reserve(fMaxMeshesPerDraw);
Brian Salomon49348902018-06-26 09:12:38 -0400458 fScissorRectScratchBuffer.reserve(fMaxMeshesPerDraw);
Chris Dalton9ca27842018-01-18 12:24:50 -0700459
460 return true;
461}
462
Chris Daltone1639692018-08-20 14:00:30 -0600463void GrCCFiller::drawFills(GrOpFlushState* flushState, BatchID batchID,
464 const SkIRect& drawBounds) const {
Chris Dalton8dfc70f2018-03-26 19:15:22 -0600465 using PrimitiveType = GrCCCoverageProcessor::PrimitiveType;
Chris Dalton9ca27842018-01-18 12:24:50 -0700466
467 SkASSERT(fInstanceBuffer);
468
Chris Daltone1639692018-08-20 14:00:30 -0600469 const PrimitiveTallies& batchTotalCounts = fBatches[batchID].fTotalPrimitiveCounts;
Chris Dalton84403d72018-02-13 21:46:17 -0500470
Chris Dalton916c4982018-08-15 00:53:25 -0600471 GrPipeline pipeline(flushState->drawOpArgs().fProxy, GrScissorTest::kEnabled,
Chris Dalton9ca27842018-01-18 12:24:50 -0700472 SkBlendMode::kPlus);
473
Chris Dalton84403d72018-02-13 21:46:17 -0500474 if (batchTotalCounts.fTriangles) {
Chris Dalton8dfc70f2018-03-26 19:15:22 -0600475 this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kTriangles,
Chris Dalton703b4762018-04-06 16:11:48 -0600476 &PrimitiveTallies::fTriangles, drawBounds);
Chris Dalton84403d72018-02-13 21:46:17 -0500477 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700478
Chris Dalton703b4762018-04-06 16:11:48 -0600479 if (batchTotalCounts.fWeightedTriangles) {
480 this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kWeightedTriangles,
481 &PrimitiveTallies::fWeightedTriangles, drawBounds);
Chris Dalton84403d72018-02-13 21:46:17 -0500482 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700483
Chris Dalton84403d72018-02-13 21:46:17 -0500484 if (batchTotalCounts.fQuadratics) {
Chris Dalton8dfc70f2018-03-26 19:15:22 -0600485 this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kQuadratics,
Chris Dalton703b4762018-04-06 16:11:48 -0600486 &PrimitiveTallies::fQuadratics, drawBounds);
Chris Dalton84403d72018-02-13 21:46:17 -0500487 }
488
489 if (batchTotalCounts.fCubics) {
Chris Dalton8dfc70f2018-03-26 19:15:22 -0600490 this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kCubics,
Chris Dalton703b4762018-04-06 16:11:48 -0600491 &PrimitiveTallies::fCubics, drawBounds);
Chris Dalton84403d72018-02-13 21:46:17 -0500492 }
Chris Dalton9f2dab02018-04-18 14:07:03 -0600493
494 if (batchTotalCounts.fConics) {
495 this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kConics,
496 &PrimitiveTallies::fConics, drawBounds);
497 }
Chris Dalton9ca27842018-01-18 12:24:50 -0700498}
499
Chris Daltone1639692018-08-20 14:00:30 -0600500void GrCCFiller::drawPrimitives(GrOpFlushState* flushState, const GrPipeline& pipeline,
501 BatchID batchID, GrCCCoverageProcessor::PrimitiveType primitiveType,
502 int PrimitiveTallies::*instanceType,
503 const SkIRect& drawBounds) const {
Brian Salomond818ebf2018-07-02 14:08:49 +0000504 SkASSERT(pipeline.isScissorEnabled());
Chris Dalton9ca27842018-01-18 12:24:50 -0700505
Chris Dalton9ca27842018-01-18 12:24:50 -0700506 // Don't call reset(), as that also resets the reserve count.
507 fMeshesScratchBuffer.pop_back_n(fMeshesScratchBuffer.count());
Brian Salomon49348902018-06-26 09:12:38 -0400508 fScissorRectScratchBuffer.pop_back_n(fScissorRectScratchBuffer.count());
Chris Dalton9ca27842018-01-18 12:24:50 -0700509
Chris Dalton703b4762018-04-06 16:11:48 -0600510 GrCCCoverageProcessor proc(flushState->resourceProvider(), primitiveType);
Chris Dalton9ca27842018-01-18 12:24:50 -0700511
512 SkASSERT(batchID > 0);
Chris Daltone1639692018-08-20 14:00:30 -0600513 SkASSERT(batchID < fBatches.count());
514 const Batch& previousBatch = fBatches[batchID - 1];
515 const Batch& batch = fBatches[batchID];
Chris Dalton84403d72018-02-13 21:46:17 -0500516 SkDEBUGCODE(int totalInstanceCount = 0);
Chris Dalton9ca27842018-01-18 12:24:50 -0700517
518 if (int instanceCount = batch.fEndNonScissorIndices.*instanceType -
519 previousBatch.fEndNonScissorIndices.*instanceType) {
520 SkASSERT(instanceCount > 0);
Chris Dalton916c4982018-08-15 00:53:25 -0600521 int baseInstance = fBaseInstances[(int)GrScissorTest::kDisabled].*instanceType +
Chris Dalton9ca27842018-01-18 12:24:50 -0700522 previousBatch.fEndNonScissorIndices.*instanceType;
523 proc.appendMesh(fInstanceBuffer.get(), instanceCount, baseInstance, &fMeshesScratchBuffer);
Brian Salomon49348902018-06-26 09:12:38 -0400524 fScissorRectScratchBuffer.push_back().setXYWH(0, 0, drawBounds.width(),
525 drawBounds.height());
Chris Dalton84403d72018-02-13 21:46:17 -0500526 SkDEBUGCODE(totalInstanceCount += instanceCount);
Chris Dalton9ca27842018-01-18 12:24:50 -0700527 }
528
529 SkASSERT(previousBatch.fEndScissorSubBatchIdx > 0);
530 SkASSERT(batch.fEndScissorSubBatchIdx <= fScissorSubBatches.count());
Chris Dalton916c4982018-08-15 00:53:25 -0600531 int baseScissorInstance = fBaseInstances[(int)GrScissorTest::kEnabled].*instanceType;
Chris Dalton9ca27842018-01-18 12:24:50 -0700532 for (int i = previousBatch.fEndScissorSubBatchIdx; i < batch.fEndScissorSubBatchIdx; ++i) {
533 const ScissorSubBatch& previousSubBatch = fScissorSubBatches[i - 1];
534 const ScissorSubBatch& scissorSubBatch = fScissorSubBatches[i];
535 int startIndex = previousSubBatch.fEndPrimitiveIndices.*instanceType;
536 int instanceCount = scissorSubBatch.fEndPrimitiveIndices.*instanceType - startIndex;
537 if (!instanceCount) {
538 continue;
539 }
540 SkASSERT(instanceCount > 0);
541 proc.appendMesh(fInstanceBuffer.get(), instanceCount,
542 baseScissorInstance + startIndex, &fMeshesScratchBuffer);
Brian Salomon49348902018-06-26 09:12:38 -0400543 fScissorRectScratchBuffer.push_back() = scissorSubBatch.fScissor;
Chris Dalton84403d72018-02-13 21:46:17 -0500544 SkDEBUGCODE(totalInstanceCount += instanceCount);
Chris Dalton9ca27842018-01-18 12:24:50 -0700545 }
546
Brian Salomon49348902018-06-26 09:12:38 -0400547 SkASSERT(fMeshesScratchBuffer.count() == fScissorRectScratchBuffer.count());
Chris Dalton9ca27842018-01-18 12:24:50 -0700548 SkASSERT(fMeshesScratchBuffer.count() <= fMaxMeshesPerDraw);
Chris Dalton84403d72018-02-13 21:46:17 -0500549 SkASSERT(totalInstanceCount == batch.fTotalPrimitiveCounts.*instanceType);
Chris Dalton9ca27842018-01-18 12:24:50 -0700550
551 if (!fMeshesScratchBuffer.empty()) {
Brian Salomon49348902018-06-26 09:12:38 -0400552 proc.draw(flushState, pipeline, fScissorRectScratchBuffer.begin(),
553 fMeshesScratchBuffer.begin(), fMeshesScratchBuffer.count(),
Chris Dalton8dfc70f2018-03-26 19:15:22 -0600554 SkRect::Make(drawBounds));
Chris Dalton9ca27842018-01-18 12:24:50 -0700555 }
556}