Flutter Engine
The Flutter Engine
PathTessellator.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 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
9
10#include "src/core/SkPathPriv.h"
21
22namespace skgpu::ganesh {
23
24namespace {
25
26using namespace skgpu::tess;
27
28using CurveWriter = PatchWriter<VertexChunkPatchAllocator,
34
35void write_curve_patches(CurveWriter&& patchWriter,
36 const SkMatrix& shaderMatrix,
37 const PathTessellator::PathDrawList& pathDrawList) {
38 patchWriter.setShaderTransform(wangs_formula::VectorXform{shaderMatrix});
39 for (auto [pathMatrix, path, color] : pathDrawList) {
40 AffineMatrix m(pathMatrix);
41 if (patchWriter.attribs() & PatchAttribs::kColor) {
42 patchWriter.updateColorAttrib(color);
43 }
44 for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
45 switch (verb) {
46 case SkPathVerb::kQuad: {
47 auto [p0, p1] = m.map2Points(pts);
48 auto p2 = m.map1Point(pts+2);
49
50 patchWriter.writeQuadratic(p0, p1, p2);
51 break;
52 }
53
54 case SkPathVerb::kConic: {
55 auto [p0, p1] = m.map2Points(pts);
56 auto p2 = m.map1Point(pts+2);
57
58 patchWriter.writeConic(p0, p1, p2, *w);
59 break;
60 }
61
62 case SkPathVerb::kCubic: {
63 auto [p0, p1] = m.map2Points(pts);
64 auto [p2, p3] = m.map2Points(pts+2);
65
66 patchWriter.writeCubic(p0, p1, p2, p3);
67 break;
68 }
69
70 default: break;
71 }
72 }
73 }
74}
75
76using WedgeWriter = PatchWriter<VertexChunkPatchAllocator,
81
82void write_wedge_patches(WedgeWriter&& patchWriter,
83 const SkMatrix& shaderMatrix,
84 const PathTessellator::PathDrawList& pathDrawList) {
85 patchWriter.setShaderTransform(wangs_formula::VectorXform{shaderMatrix});
86 for (auto [pathMatrix, path, color] : pathDrawList) {
87 AffineMatrix m(pathMatrix);
88 if (patchWriter.attribs() & PatchAttribs::kColor) {
89 patchWriter.updateColorAttrib(color);
90 }
92 while (parser.parseNextContour()) {
93 patchWriter.updateFanPointAttrib(m.mapPoint(parser.currentMidpoint()));
94 SkPoint lastPoint = {0, 0};
95 SkPoint startPoint = {0, 0};
96 for (auto [verb, pts, w] : parser.currentContour()) {
97 switch (verb) {
98 case SkPathVerb::kMove: {
99 startPoint = lastPoint = pts[0];
100 break;
101 }
102
103 case SkPathVerb::kLine: {
104 // Explicitly convert the line to an equivalent cubic w/ four distinct
105 // control points because it fans better and avoids double-hitting pixels.
106 patchWriter.writeLine(m.map2Points(pts));
107 lastPoint = pts[1];
108 break;
109 }
110
111 case SkPathVerb::kQuad: {
112 auto [p0, p1] = m.map2Points(pts);
113 auto p2 = m.map1Point(pts+2);
114
115 patchWriter.writeQuadratic(p0, p1, p2);
116 lastPoint = pts[2];
117 break;
118 }
119
120 case SkPathVerb::kConic: {
121 auto [p0, p1] = m.map2Points(pts);
122 auto p2 = m.map1Point(pts+2);
123
124 patchWriter.writeConic(p0, p1, p2, *w);
125 lastPoint = pts[2];
126 break;
127 }
128
129 case SkPathVerb::kCubic: {
130 auto [p0, p1] = m.map2Points(pts);
131 auto [p2, p3] = m.map2Points(pts+2);
132
133 patchWriter.writeCubic(p0, p1, p2, p3);
134 lastPoint = pts[3];
135 break;
136 }
137
138 case SkPathVerb::kClose: {
139 break; // Ignore. We can assume an implicit close at the end.
140 }
141 }
142 }
143 if (lastPoint != startPoint) {
144 SkPoint pts[2] = {lastPoint, startPoint};
145 patchWriter.writeLine(m.map2Points(pts));
146 }
147 }
148 }
149}
150
151} // namespace
152
153SKGPU_DECLARE_STATIC_UNIQUE_KEY(gFixedCountCurveVertexBufferKey);
154SKGPU_DECLARE_STATIC_UNIQUE_KEY(gFixedCountCurveIndexBufferKey);
155
158 const SkMatrix& shaderMatrix,
160 const PathDrawList& pathDrawList,
161 int totalCombinedPathVerbCnt) {
162#if !defined(SK_ENABLE_OPTIMIZE_SIZE)
163 int patchPreallocCount = FixedCountCurves::PreallocCount(totalCombinedPathVerbCnt) +
164 (extraTriangles ? extraTriangles->count() : 0);
165#else
166 SkASSERT(!extraTriangles);
167 int patchPreallocCount = FixedCountCurves::PreallocCount(totalCombinedPathVerbCnt);
168#endif
169
170
171 if (patchPreallocCount) {
172 LinearTolerances worstCase;
173 CurveWriter writer{fAttribs, &worstCase, target, &fVertexChunkArray, patchPreallocCount};
174
175#if !defined(SK_ENABLE_OPTIMIZE_SIZE)
176 // Write out extra space-filling triangles to connect the curve patches with any external
177 // source of geometry (e.g. inner triangulation that handles winding explicitly).
178 if (extraTriangles) {
179 SkDEBUGCODE(int breadcrumbCount = 0;)
180 for (const auto* tri = extraTriangles->head(); tri; tri = tri->fNext) {
181 SkDEBUGCODE(++breadcrumbCount;)
182 auto p0 = skvx::float2::Load(tri->fPts);
183 auto p1 = skvx::float2::Load(tri->fPts + 1);
184 auto p2 = skvx::float2::Load(tri->fPts + 2);
185 if (any((p0 == p1) & (p1 == p2))) {
186 // Cull completely horizontal or vertical triangles. GrTriangulator can't always
187 // get these breadcrumb edges right when they run parallel to the sweep
188 // direction because their winding is undefined by its current definition.
189 // FIXME(skia:12060): This seemed safe, but if there is a view matrix it will
190 // introduce T-junctions.
191 continue;
192 }
193 writer.writeTriangle(p0, p1, p2);
194 }
195 SkASSERT(breadcrumbCount == extraTriangles->count());
196 }
197#endif
198
199 write_curve_patches(std::move(writer), shaderMatrix, pathDrawList);
201 }
202
203 GrResourceProvider* rp = target->resourceProvider();
204
205 SKGPU_DEFINE_STATIC_UNIQUE_KEY(gFixedCountCurveVertexBufferKey);
206
209 gFixedCountCurveVertexBufferKey,
211
212 SKGPU_DEFINE_STATIC_UNIQUE_KEY(gFixedCountCurveIndexBufferKey);
213
216 gFixedCountCurveIndexBufferKey,
218}
219
222 return;
223 }
224 for (const GrVertexChunk& chunk : fVertexChunkArray) {
225 flushState->bindBuffers(fFixedIndexBuffer, chunk.fBuffer, fFixedVertexBuffer);
226 // The max vertex count is the logical number of vertices that the GPU needs to emit, so
227 // since we're using drawIndexedInstanced, it's provided as the "index count" parameter.
228 flushState->drawIndexedInstanced(fMaxVertexCount, 0, chunk.fCount, chunk.fBase, 0);
229 }
230}
231
233 sk_sp<const GrGpuBuffer> vertexBufferIfNeeded) const {
234 for (const GrVertexChunk& chunk : fVertexChunkArray) {
235 flushState->bindBuffers(nullptr, chunk.fBuffer, vertexBufferIfNeeded);
236 flushState->drawInstanced(chunk.fCount, chunk.fBase, 4, 0);
237 }
238}
239
240
241SKGPU_DECLARE_STATIC_UNIQUE_KEY(gFixedCountWedgesVertexBufferKey);
242SKGPU_DECLARE_STATIC_UNIQUE_KEY(gFixedCountWedgesIndexBufferKey);
243
245 const SkMatrix& shaderMatrix,
246 const PathDrawList& pathDrawList,
247 int totalCombinedPathVerbCnt) {
248 if (int patchPreallocCount = FixedCountWedges::PreallocCount(totalCombinedPathVerbCnt)) {
249 LinearTolerances worstCase;
250 WedgeWriter writer{fAttribs, &worstCase, target, &fVertexChunkArray, patchPreallocCount};
251 write_wedge_patches(std::move(writer), shaderMatrix, pathDrawList);
253 }
254
255 GrResourceProvider* rp = target->resourceProvider();
256
257 SKGPU_DEFINE_STATIC_UNIQUE_KEY(gFixedCountWedgesVertexBufferKey);
258
261 gFixedCountWedgesVertexBufferKey,
263
264 SKGPU_DEFINE_STATIC_UNIQUE_KEY(gFixedCountWedgesIndexBufferKey);
265
268 gFixedCountWedgesIndexBufferKey,
270}
271
274 return;
275 }
276 for (const GrVertexChunk& chunk : fVertexChunkArray) {
277 flushState->bindBuffers(fFixedIndexBuffer, chunk.fBuffer, fFixedVertexBuffer);
278 flushState->drawIndexedInstanced(fMaxVertexCount, 0, chunk.fCount, chunk.fBase, 0);
279 }
280}
281
282} // namespace skgpu::ganesh
#define SKGPU_DEFINE_STATIC_UNIQUE_KEY(name)
Definition: ResourceKey.h:324
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kClose
SkPath::RawIter returns 0 points.
@ kCubic
SkPath::RawIter returns 4 points.
@ kConic
SkPath::RawIter returns 3 points + 1 weight.
@ kQuad
SkPath::RawIter returns 3 points.
@ kMove
SkPath::RawIter returns 1 point.
@ kLine
SkPath::RawIter returns 2 points.
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
void drawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, int baseInstance, int baseVertex)
void bindBuffers(sk_sp< const GrBuffer > indexBuffer, sk_sp< const GrBuffer > instanceBuffer, sk_sp< const GrBuffer > vertexBuffer, GrPrimitiveRestart primitiveRestart=GrPrimitiveRestart::kNo)
void drawInstanced(int instanceCount, int baseInstance, int vertexCount, int baseVertex)
sk_sp< const GrGpuBuffer > findOrMakeStaticBuffer(GrGpuBufferType intendedType, size_t size, const skgpu::UniqueKey &key, InitializeBufferFn)
void drawHullInstances(GrOpFlushState *, sk_sp< const GrGpuBuffer > vertexBufferIfNeeded) const
void prepareWithTriangles(GrMeshDrawTarget *target, const SkMatrix &shaderMatrix, GrInnerFanTriangulator::BreadcrumbTriangleList *extraTriangles, const PathDrawList &pathDrawList, int totalCombinedPathVerbCnt)
void draw(GrOpFlushState *) const final
GrVertexChunkArray fVertexChunkArray
sk_sp< const GrGpuBuffer > fFixedIndexBuffer
sk_sp< const GrGpuBuffer > fFixedVertexBuffer
void prepare(GrMeshDrawTarget *target, const SkMatrix &shaderMatrix, const PathDrawList &pathDrawList, int totalCombinedPathVerbCnt) final
void draw(GrOpFlushState *) const final
static void WriteIndexBuffer(VertexWriter, size_t bufferSize)
static constexpr size_t VertexBufferSize()
static int VertexCount(const LinearTolerances &tolerances)
static constexpr int PreallocCount(int totalCombinedPathVerbCnt)
static constexpr size_t IndexBufferSize()
static void WriteVertexBuffer(VertexWriter, size_t bufferSize)
static constexpr size_t IndexBufferSize()
static int VertexCount(const LinearTolerances &tolerances)
static constexpr int PreallocCount(int totalCombinedPathVerbCnt)
static constexpr size_t VertexBufferSize()
static void WriteVertexBuffer(VertexWriter, size_t bufferSize)
static void WriteIndexBuffer(VertexWriter, size_t bufferSize)
DlColor color
uint32_t * target
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
SKGPU_DECLARE_STATIC_UNIQUE_KEY(gUnitQuadBufferKey)
SIT bool any(const Vec< 1, T > &x)
Definition: SkVx.h:530
parser
Definition: zip.py:78
SkScalar w
static SKVX_ALWAYS_INLINE Vec Load(const void *ptr)
Definition: SkVx.h:109