blob: afcb6e2185ff99d2adf490c2f50e5839274e62b1 [file] [log] [blame]
Chris Daltond7177432021-01-15 13:12:50 -07001/*
2 * Copyright 2021 Google LLC.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/gpu/tessellate/GrPathTessellator.h"
9
10#include "src/gpu/GrEagerVertexAllocator.h"
11#include "src/gpu/GrGpu.h"
12#include "src/gpu/geometry/GrPathUtils.h"
Michael Ludwig4e9d5e22021-05-11 10:00:12 -040013#include "src/gpu/geometry/GrWangsFormula.h"
Chris Daltond7177432021-01-15 13:12:50 -070014#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
15#include "src/gpu/tessellate/GrMidpointContourParser.h"
16#include "src/gpu/tessellate/GrStencilPathShader.h"
Chris Daltond7177432021-01-15 13:12:50 -070017
18GrPathIndirectTessellator::GrPathIndirectTessellator(const SkMatrix& viewMatrix, const SkPath& path,
19 DrawInnerFan drawInnerFan)
20 : fDrawInnerFan(drawInnerFan != DrawInnerFan::kNo) {
21 // Count the number of instances at each resolveLevel.
22 GrVectorXform xform(viewMatrix);
23 for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
24 int level;
25 switch (verb) {
26 case SkPathVerb::kConic:
Chris Dalton50f5e682021-04-16 22:47:03 -060027 level = GrWangsFormula::conic_log2(1.f / kLinearizationPrecision, pts, *w, xform);
Tyler Dennistonbc2fa2b2021-02-08 11:39:34 -050028 break;
Chris Daltond7177432021-01-15 13:12:50 -070029 case SkPathVerb::kQuad:
Chris Dalton50f5e682021-04-16 22:47:03 -060030 level = GrWangsFormula::quadratic_log2(kLinearizationPrecision, pts, xform);
Chris Daltond7177432021-01-15 13:12:50 -070031 break;
32 case SkPathVerb::kCubic:
Chris Dalton50f5e682021-04-16 22:47:03 -060033 level = GrWangsFormula::cubic_log2(kLinearizationPrecision, pts, xform);
Chris Daltond7177432021-01-15 13:12:50 -070034 break;
35 default:
36 continue;
37 }
38 SkASSERT(level >= 0);
39 // Instances with 2^0=1 segments are empty (zero area). We ignore them completely.
40 if (level > 0) {
41 level = std::min(level, kMaxResolveLevel);
42 ++fResolveLevelCounts[level];
43 ++fOuterCurveInstanceCount;
44 }
45 }
46}
47
Chris Dalton2758a312021-05-20 10:46:25 -060048// Returns an upper bound on the number of segments (lineTo, quadTo, conicTo, cubicTo) in a path,
49// also accounting for any implicit lineTos from closing contours.
50static int max_segments_in_path(const SkPath& path) {
51 // There might be an implicit kClose at the end, but the path always begins with kMove. So the
52 // max number of segments in the path is equal to the number of verbs.
53 SkASSERT(path.countVerbs() == 0 || SkPathPriv::VerbData(path)[0] == SkPath::kMove_Verb);
54 return path.countVerbs();
55}
56
57// Returns an upper bound on the number of triangles it would require to fan a path's inner polygon,
58// in the case where no additional vertices are introduced.
59static int max_triangles_in_inner_fan(const SkPath& path) {
60 int maxEdgesInFan = max_segments_in_path(path);
Chris Dalton80175812021-05-20 18:55:50 -060061 return std::max(maxEdgesInFan - 2, 0); // An n-sided polygon is fanned by n-2 triangles.
Chris Dalton2758a312021-05-20 10:46:25 -060062}
63
64static int write_breadcrumb_triangles(
65 GrVertexWriter* writer,
66 const GrInnerFanTriangulator::BreadcrumbTriangleList* breadcrumbTriangleList) {
67 int numWritten = 0;
68 SkDEBUGCODE(int count = 0;)
69 for (const auto* tri = breadcrumbTriangleList->head(); tri; tri = tri->fNext) {
70 SkDEBUGCODE(++count;)
71 const SkPoint* p = tri->fPts;
72 if ((p[0].fX == p[1].fX && p[1].fX == p[2].fX) ||
73 (p[0].fY == p[1].fY && p[1].fY == p[2].fY)) {
74 // Completely degenerate triangles have undefined winding. And T-junctions shouldn't
75 // happen on axis-aligned edges.
76 continue;
77 }
78 writer->writeArray(p, 3);
79 // Mark this instance as a triangle by setting it to a conic with w=Inf.
80 writer->fill(GrVertexWriter::kIEEE_32_infinity, 2);
81 ++numWritten;
82 }
83 SkASSERT(count == breadcrumbTriangleList->count());
84 return numWritten;
85}
86
Chris Daltond7177432021-01-15 13:12:50 -070087void GrPathIndirectTessellator::prepare(GrMeshDrawOp::Target* target, const SkMatrix& viewMatrix,
Chris Daltonebb37e72021-01-27 17:59:45 -070088 const SkPath& path,
89 const BreadcrumbTriangleList* breadcrumbTriangleList) {
Chris Daltond7177432021-01-15 13:12:50 -070090 SkASSERT(fTotalInstanceCount == 0);
91 SkASSERT(fIndirectDrawCount == 0);
Chris Daltonb849f7a2021-02-10 12:55:48 -070092 SkASSERT(target->caps().drawInstancedSupport());
Chris Daltond7177432021-01-15 13:12:50 -070093
94 int instanceLockCount = fOuterCurveInstanceCount;
95 if (fDrawInnerFan) {
Chris Dalton2758a312021-05-20 10:46:25 -060096 instanceLockCount += max_triangles_in_inner_fan(path);
Chris Daltond7177432021-01-15 13:12:50 -070097 }
Chris Daltonebb37e72021-01-27 17:59:45 -070098 if (breadcrumbTriangleList) {
99 instanceLockCount += breadcrumbTriangleList->count();
100 }
Chris Daltond7177432021-01-15 13:12:50 -0700101 if (instanceLockCount == 0) {
102 return;
103 }
104
105 // Allocate a buffer to store the instance data.
106 GrEagerDynamicVertexAllocator vertexAlloc(target, &fInstanceBuffer, &fBaseInstance);
Chris Dalton8731a712021-05-14 14:48:54 -0600107 GrVertexWriter instanceWriter = static_cast<SkPoint*>(vertexAlloc.lock(sizeof(SkPoint) * 4,
108 instanceLockCount));
109 if (!instanceWriter) {
Chris Daltond7177432021-01-15 13:12:50 -0700110 return;
111 }
112
Chris Daltondf2dbad2021-05-14 16:21:15 -0600113 // Write out any triangles at the beginning of the cubic data. Since this shader draws curves,
114 // output the triangles as conics with w=infinity (which is equivalent to a triangle).
Chris Daltond7177432021-01-15 13:12:50 -0700115 int numTrianglesAtBeginningOfData = 0;
116 if (fDrawInnerFan) {
117 numTrianglesAtBeginningOfData = GrMiddleOutPolygonTriangulator::WritePathInnerFan(
Chris Daltondf2dbad2021-05-14 16:21:15 -0600118 &instanceWriter,
119 GrMiddleOutPolygonTriangulator::OutputType::kConicsWithInfiniteWeight, path);
Chris Daltonebb37e72021-01-27 17:59:45 -0700120 }
121 if (breadcrumbTriangleList) {
Chris Dalton2758a312021-05-20 10:46:25 -0600122 numTrianglesAtBeginningOfData += write_breadcrumb_triangles(&instanceWriter,
123 breadcrumbTriangleList);
Chris Daltond7177432021-01-15 13:12:50 -0700124 }
125
Chris Daltond7177432021-01-15 13:12:50 -0700126 // Allocate space for the GrDrawIndexedIndirectCommand structs. Allocate enough for each
127 // possible resolve level (kMaxResolveLevel; resolveLevel=0 never has any instances), plus one
128 // more for the optional inner fan triangles.
129 int indirectLockCnt = kMaxResolveLevel + 1;
Chris Dalton489fa0b2021-05-14 17:41:17 -0600130 GrDrawIndirectWriter indirectWriter = target->makeDrawIndirectSpace(indirectLockCnt,
131 &fIndirectDrawBuffer,
132 &fIndirectDrawOffset);
Chris Dalton8ed7a8d2021-03-31 10:40:29 -0600133 if (!indirectWriter) {
Chris Daltond7177432021-01-15 13:12:50 -0700134 SkASSERT(!fIndirectDrawBuffer);
Chris Dalton8ed7a8d2021-03-31 10:40:29 -0600135 vertexAlloc.unlock(0);
Chris Daltond7177432021-01-15 13:12:50 -0700136 return;
137 }
138
139 // Fill out the GrDrawIndexedIndirectCommand structs and determine the starting instance data
140 // location at each resolve level.
Chris Dalton8731a712021-05-14 14:48:54 -0600141 GrVertexWriter instanceLocations[kMaxResolveLevel + 1];
142 int currentBaseInstance = fBaseInstance;
Chris Daltond7177432021-01-15 13:12:50 -0700143 SkASSERT(fResolveLevelCounts[0] == 0);
Chris Dalton489fa0b2021-05-14 17:41:17 -0600144 for (int resolveLevel=1, numExtraInstances=numTrianglesAtBeginningOfData;
145 resolveLevel <= kMaxResolveLevel;
146 ++resolveLevel, numExtraInstances=0) {
Chris Daltond7177432021-01-15 13:12:50 -0700147 int instanceCountAtCurrLevel = fResolveLevelCounts[resolveLevel];
Chris Dalton489fa0b2021-05-14 17:41:17 -0600148 if (!(instanceCountAtCurrLevel + numExtraInstances)) {
Chris Daltond7177432021-01-15 13:12:50 -0700149 SkDEBUGCODE(instanceLocations[resolveLevel] = nullptr;)
150 continue;
151 }
Chris Dalton8731a712021-05-14 14:48:54 -0600152 instanceLocations[resolveLevel] = instanceWriter.makeOffset(0);
Chris Daltond7177432021-01-15 13:12:50 -0700153 SkASSERT(fIndirectDrawCount < indirectLockCnt);
Chris Daltona9f759d2021-05-18 12:37:08 -0600154 GrCurveMiddleOutShader::WriteDrawIndirectCmd(&indirectWriter, resolveLevel,
Chris Dalton489fa0b2021-05-14 17:41:17 -0600155 instanceCountAtCurrLevel + numExtraInstances,
156 currentBaseInstance);
Chris Daltona6a3d052021-02-07 20:56:36 -0700157 ++fIndirectDrawCount;
Chris Dalton489fa0b2021-05-14 17:41:17 -0600158 currentBaseInstance += instanceCountAtCurrLevel + numExtraInstances;
Chris Dalton8731a712021-05-14 14:48:54 -0600159 instanceWriter = instanceWriter.makeOffset(instanceCountAtCurrLevel * 4 * sizeof(SkPoint));
Chris Daltond7177432021-01-15 13:12:50 -0700160 }
161
162 target->putBackIndirectDraws(indirectLockCnt - fIndirectDrawCount);
163
164#ifdef SK_DEBUG
Chris Dalton8731a712021-05-14 14:48:54 -0600165 SkASSERT(currentBaseInstance ==
166 fBaseInstance + numTrianglesAtBeginningOfData + fOuterCurveInstanceCount);
Chris Daltond7177432021-01-15 13:12:50 -0700167
Chris Dalton8731a712021-05-14 14:48:54 -0600168 GrVertexWriter endLocations[kMaxResolveLevel + 1];
Chris Daltond7177432021-01-15 13:12:50 -0700169 int lastResolveLevel = 0;
170 for (int resolveLevel = 1; resolveLevel <= kMaxResolveLevel; ++resolveLevel) {
171 if (!instanceLocations[resolveLevel]) {
172 endLocations[resolveLevel] = nullptr;
173 continue;
174 }
Chris Dalton8731a712021-05-14 14:48:54 -0600175 endLocations[lastResolveLevel] = instanceLocations[resolveLevel].makeOffset(0);
Chris Daltond7177432021-01-15 13:12:50 -0700176 lastResolveLevel = resolveLevel;
177 }
Chris Dalton8731a712021-05-14 14:48:54 -0600178 endLocations[lastResolveLevel] = instanceWriter.makeOffset(0);
Chris Daltond7177432021-01-15 13:12:50 -0700179#endif
180
181 fTotalInstanceCount = numTrianglesAtBeginningOfData;
182
183 // Write out the cubic instances.
184 if (fOuterCurveInstanceCount) {
185 GrVectorXform xform(viewMatrix);
186 for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
187 int level;
188 switch (verb) {
189 default:
190 continue;
191 case SkPathVerb::kConic:
Chris Dalton50f5e682021-04-16 22:47:03 -0600192 level = GrWangsFormula::conic_log2(1.f / kLinearizationPrecision, pts, *w,
Tyler Dennistonbc2fa2b2021-02-08 11:39:34 -0500193 xform);
194 break;
Chris Daltond7177432021-01-15 13:12:50 -0700195 case SkPathVerb::kQuad:
Chris Dalton50f5e682021-04-16 22:47:03 -0600196 level = GrWangsFormula::quadratic_log2(kLinearizationPrecision, pts, xform);
Chris Daltond7177432021-01-15 13:12:50 -0700197 break;
198 case SkPathVerb::kCubic:
Chris Dalton50f5e682021-04-16 22:47:03 -0600199 level = GrWangsFormula::cubic_log2(kLinearizationPrecision, pts, xform);
Chris Daltond7177432021-01-15 13:12:50 -0700200 break;
201 }
202 if (level == 0) {
203 continue;
204 }
205 level = std::min(level, kMaxResolveLevel);
206 switch (verb) {
207 case SkPathVerb::kQuad:
Chris Dalton8731a712021-05-14 14:48:54 -0600208 GrPathUtils::writeQuadAsCubic(pts, &instanceLocations[level]);
Chris Daltond7177432021-01-15 13:12:50 -0700209 break;
210 case SkPathVerb::kCubic:
Chris Dalton8731a712021-05-14 14:48:54 -0600211 instanceLocations[level].writeArray(pts, 4);
Chris Daltond7177432021-01-15 13:12:50 -0700212 break;
213 case SkPathVerb::kConic:
Chris Dalton8731a712021-05-14 14:48:54 -0600214 GrPathShader::WriteConicPatch(pts, *w, &instanceLocations[level]);
Chris Daltond7177432021-01-15 13:12:50 -0700215 break;
216 default:
217 SkUNREACHABLE;
218 }
Chris Daltond7177432021-01-15 13:12:50 -0700219 ++fTotalInstanceCount;
220 }
221 }
222
223#ifdef SK_DEBUG
224 for (int i = 1; i <= kMaxResolveLevel; ++i) {
225 SkASSERT(instanceLocations[i] == endLocations[i]);
226 }
227 SkASSERT(fTotalInstanceCount == numTrianglesAtBeginningOfData + fOuterCurveInstanceCount);
228#endif
229
230 vertexAlloc.unlock(fTotalInstanceCount);
231}
232
233void GrPathIndirectTessellator::draw(GrOpFlushState* flushState) const {
234 if (fIndirectDrawCount) {
Chris Dalton489fa0b2021-05-14 17:41:17 -0600235 flushState->bindBuffers(nullptr, fInstanceBuffer, nullptr);
236 flushState->drawIndirect(fIndirectDrawBuffer.get(), fIndirectDrawOffset,
237 fIndirectDrawCount);
Chris Daltond7177432021-01-15 13:12:50 -0700238 }
239}
240
241void GrPathIndirectTessellator::drawHullInstances(GrOpFlushState* flushState) const {
242 if (fTotalInstanceCount) {
243 flushState->bindBuffers(nullptr, fInstanceBuffer, nullptr);
244 flushState->drawInstanced(fTotalInstanceCount, fBaseInstance, 4, 0);
245 }
246}
247
248void GrPathOuterCurveTessellator::prepare(GrMeshDrawOp::Target* target, const SkMatrix& matrix,
Chris Daltonebb37e72021-01-27 17:59:45 -0700249 const SkPath& path,
250 const BreadcrumbTriangleList* breadcrumbTriangleList) {
Chris Daltond7177432021-01-15 13:12:50 -0700251 SkASSERT(target->caps().shaderCaps()->tessellationSupport());
252 SkASSERT(!fPatchBuffer);
253 SkASSERT(fPatchVertexCount == 0);
254
255 int vertexLockCount = path.countVerbs() * 4;
Chris Dalton2758a312021-05-20 10:46:25 -0600256 if (fDrawInnerFan) {
257 vertexLockCount += max_triangles_in_inner_fan(path) * 4;
258 }
259 if (breadcrumbTriangleList) {
260 vertexLockCount += breadcrumbTriangleList->count() * 4;
261 }
Chris Daltond7177432021-01-15 13:12:50 -0700262 GrEagerDynamicVertexAllocator vertexAlloc(target, &fPatchBuffer, &fBasePatchVertex);
Chris Dalton2758a312021-05-20 10:46:25 -0600263 GrVertexWriter vertexWriter = vertexAlloc.lock<SkPoint>(vertexLockCount);
264 if (!vertexWriter) {
Chris Daltond7177432021-01-15 13:12:50 -0700265 return;
266 }
267
Chris Dalton2758a312021-05-20 10:46:25 -0600268 GrMiddleOutPolygonTriangulator middleOut(
269 &vertexWriter, GrMiddleOutPolygonTriangulator::OutputType::kConicsWithInfiniteWeight,
270 path.countVerbs());
Chris Daltond7177432021-01-15 13:12:50 -0700271 for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
272 switch (verb) {
Chris Dalton2758a312021-05-20 10:46:25 -0600273 case SkPathVerb::kMove:
274 if (fDrawInnerFan) {
275 middleOut.closeAndMove(pts[0]);
276 }
Chris Daltond7177432021-01-15 13:12:50 -0700277 continue;
Chris Dalton2758a312021-05-20 10:46:25 -0600278 case SkPathVerb::kClose:
279 continue;
280 case SkPathVerb::kLine:
281 break;
Chris Daltond7177432021-01-15 13:12:50 -0700282 case SkPathVerb::kQuad:
Chris Dalton2758a312021-05-20 10:46:25 -0600283 GrPathUtils::writeQuadAsCubic(pts, &vertexWriter);
284 fPatchVertexCount += 4;
Chris Daltond7177432021-01-15 13:12:50 -0700285 break;
286 case SkPathVerb::kCubic:
Chris Dalton2758a312021-05-20 10:46:25 -0600287 vertexWriter.writeArray(pts, 4);
288 fPatchVertexCount += 4;
Chris Daltond7177432021-01-15 13:12:50 -0700289 break;
290 case SkPathVerb::kConic:
Chris Dalton2758a312021-05-20 10:46:25 -0600291 GrPathShader::WriteConicPatch(pts, *w, &vertexWriter);
292 fPatchVertexCount += 4;
Chris Daltond7177432021-01-15 13:12:50 -0700293 break;
294 }
Chris Dalton2758a312021-05-20 10:46:25 -0600295 if (fDrawInnerFan) {
296 middleOut.pushVertex(pts[SkPathPriv::PtsInIter((unsigned)verb) - 1]);
297 }
Chris Daltond7177432021-01-15 13:12:50 -0700298 }
Chris Dalton2758a312021-05-20 10:46:25 -0600299 if (fDrawInnerFan) {
300 fPatchVertexCount += middleOut.close() * 4;
301 }
302 if (breadcrumbTriangleList) {
303 fPatchVertexCount += write_breadcrumb_triangles(&vertexWriter, breadcrumbTriangleList) * 4;
304 }
305 SkASSERT(fPatchVertexCount <= vertexLockCount);
Chris Daltond7177432021-01-15 13:12:50 -0700306
307 vertexAlloc.unlock(fPatchVertexCount);
308}
309
310void GrPathWedgeTessellator::prepare(GrMeshDrawOp::Target* target, const SkMatrix& matrix,
Chris Daltonebb37e72021-01-27 17:59:45 -0700311 const SkPath& path,
312 const BreadcrumbTriangleList* breadcrumbTriangleList) {
Chris Daltond7177432021-01-15 13:12:50 -0700313 SkASSERT(target->caps().shaderCaps()->tessellationSupport());
Chris Daltonebb37e72021-01-27 17:59:45 -0700314 SkASSERT(!breadcrumbTriangleList);
Chris Daltond7177432021-01-15 13:12:50 -0700315 SkASSERT(!fPatchBuffer);
316 SkASSERT(fPatchVertexCount == 0);
317
Chris Dalton2758a312021-05-20 10:46:25 -0600318 // We emit one wedge per path segment. Each wedge has 5 vertices.
319 int maxVertices = max_segments_in_path(path) * 5;
Chris Daltond7177432021-01-15 13:12:50 -0700320
321 GrEagerDynamicVertexAllocator vertexAlloc(target, &fPatchBuffer, &fBasePatchVertex);
322 auto* vertexData = vertexAlloc.lock<SkPoint>(maxVertices);
323 if (!vertexData) {
324 return;
325 }
326
327 GrMidpointContourParser parser(path);
328 while (parser.parseNextContour()) {
329 SkPoint midpoint = parser.currentMidpoint();
330 SkPoint startPoint = {0, 0};
331 SkPoint lastPoint = startPoint;
332 for (auto [verb, pts, w] : parser.currentContour()) {
333 switch (verb) {
334 case SkPathVerb::kMove:
335 startPoint = lastPoint = pts[0];
336 continue;
337 case SkPathVerb::kClose:
338 continue; // Ignore. We can assume an implicit close at the end.
339 case SkPathVerb::kLine:
340 GrPathUtils::convertLineToCubic(pts[0], pts[1], vertexData + fPatchVertexCount);
341 lastPoint = pts[1];
342 break;
343 case SkPathVerb::kQuad:
344 GrPathUtils::convertQuadToCubic(pts, vertexData + fPatchVertexCount);
345 lastPoint = pts[2];
346 break;
347 case SkPathVerb::kCubic:
348 memcpy(vertexData + fPatchVertexCount, pts, sizeof(SkPoint) * 4);
349 lastPoint = pts[3];
350 break;
351 case SkPathVerb::kConic:
352 GrPathShader::WriteConicPatch(pts, *w, vertexData + fPatchVertexCount);
353 lastPoint = pts[2];
354 break;
355 }
356 vertexData[fPatchVertexCount + 4] = midpoint;
357 fPatchVertexCount += 5;
358 }
359 if (lastPoint != startPoint) {
360 GrPathUtils::convertLineToCubic(lastPoint, startPoint, vertexData + fPatchVertexCount);
361 vertexData[fPatchVertexCount + 4] = midpoint;
362 fPatchVertexCount += 5;
363 }
364 }
365
366 vertexAlloc.unlock(fPatchVertexCount);
367}
368
369void GrPathHardwareTessellator::draw(GrOpFlushState* flushState) const {
370 if (fPatchVertexCount) {
371 flushState->bindBuffers(nullptr, nullptr, fPatchBuffer);
372 flushState->draw(fPatchVertexCount, fBasePatchVertex);
373 if (flushState->caps().requiresManualFBBarrierAfterTessellatedStencilDraw()) {
374 flushState->gpu()->insertManualFramebufferBarrier(); // http://skbug.com/9739
375 }
376 }
377}