1 /*
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/PathCurveTessellator.h"
9
10 #include "src/gpu/tessellate/AffineMatrix.h"
11 #include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
12 #include "src/gpu/tessellate/PatchWriter.h"
13 #include "src/gpu/tessellate/WangsFormula.h"
14
15 #if SK_GPU_V1
16 #include "src/gpu/GrMeshDrawTarget.h"
17 #include "src/gpu/GrOpFlushState.h"
18 #include "src/gpu/GrResourceProvider.h"
19 #endif
20
21 namespace skgpu {
22
patchPreallocCount(int totalCombinedPathVerbCnt) const23 int PathCurveTessellator::patchPreallocCount(int totalCombinedPathVerbCnt) const {
24 // Over-allocate enough curves for 1 in 4 to chop.
25 int approxNumChops = (totalCombinedPathVerbCnt + 3) / 4;
26 // Every chop introduces 2 new patches: another curve patch and a triangle patch that glues the
27 // two chops together.
28 return totalCombinedPathVerbCnt + approxNumChops * 2;
29 }
30
writePatches(PatchWriter & patchWriter,const SkMatrix & shaderMatrix,const PathDrawList & pathDrawList)31 void PathCurveTessellator::writePatches(PatchWriter& patchWriter,
32 const SkMatrix& shaderMatrix,
33 const PathDrawList& pathDrawList) {
34 wangs_formula::VectorXform shaderXform(shaderMatrix);
35 for (auto [pathMatrix, path, color] : pathDrawList) {
36 AffineMatrix m(pathMatrix);
37 if (fAttribs & PatchAttribs::kColor) {
38 patchWriter.updateColorAttrib(color);
39 }
40 for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
41 switch (verb) {
42 case SkPathVerb::kQuad: {
43 auto [p0, p1] = m.map2Points(pts);
44 auto p2 = m.map1Point(pts+2);
45
46 patchWriter.writeQuadratic(p0, p1, p2, shaderXform);
47 break;
48 }
49
50 case SkPathVerb::kConic: {
51 auto [p0, p1] = m.map2Points(pts);
52 auto p2 = m.map1Point(pts+2);
53
54 patchWriter.writeConic(p0, p1, p2, *w, shaderXform);
55 break;
56 }
57
58 case SkPathVerb::kCubic: {
59 auto [p0, p1] = m.map2Points(pts);
60 auto [p2, p3] = m.map2Points(pts+2);
61
62 patchWriter.writeCubic(p0, p1, p2, p3, shaderXform);
63 break;
64 }
65
66 default: break;
67 }
68 }
69 }
70
71 // We already chopped curves to make sure none needed a higher resolveLevel than
72 // kMaxFixedResolveLevel.
73 fFixedResolveLevel = SkTPin(patchWriter.requiredResolveLevel(),
74 fFixedResolveLevel,
75 int(kMaxFixedResolveLevel));
76 }
77
WriteFixedVertexBuffer(VertexWriter vertexWriter,size_t bufferSize)78 void PathCurveTessellator::WriteFixedVertexBuffer(VertexWriter vertexWriter, size_t bufferSize) {
79 SkASSERT(bufferSize >= sizeof(SkPoint) * 2);
80 SkASSERT(bufferSize % sizeof(SkPoint) == 0);
81 int vertexCount = bufferSize / sizeof(SkPoint);
82 SkASSERT(vertexCount > 3);
83 SkDEBUGCODE(auto end = vertexWriter.mark(vertexCount * sizeof(SkPoint));)
84
85 // Lay out the vertices in "middle-out" order:
86 //
87 // T= 0/1, 1/1, ; resolveLevel=0
88 // 1/2, ; resolveLevel=1 (0/2 and 2/2 are already in resolveLevel 0)
89 // 1/4, 3/4, ; resolveLevel=2 (2/4 is already in resolveLevel 1)
90 // 1/8, 3/8, 5/8, 7/8, ; resolveLevel=3 (2/8 and 6/8 are already in resolveLevel 2)
91 // ... ; resolveLevel=...
92 //
93 // Resolve level 0 is just the beginning and ending vertices.
94 vertexWriter << (float)0/*resolveLevel*/ << (float)0/*idx*/;
95 vertexWriter << (float)0/*resolveLevel*/ << (float)1/*idx*/;
96
97 // Resolve levels 1..kMaxResolveLevel.
98 int maxResolveLevel = SkPrevLog2(vertexCount - 1);
99 SkASSERT((1 << maxResolveLevel) + 1 == vertexCount);
100 for (int resolveLevel = 1; resolveLevel <= maxResolveLevel; ++resolveLevel) {
101 int numSegmentsInResolveLevel = 1 << resolveLevel;
102 // Write out the odd vertices in this resolveLevel. The even vertices were already written
103 // out in previous resolveLevels and will be indexed from there.
104 for (int i = 1; i < numSegmentsInResolveLevel; i += 2) {
105 vertexWriter << (float)resolveLevel << (float)i;
106 }
107 }
108
109 SkASSERT(vertexWriter.mark() == end);
110 }
111
WriteFixedIndexBufferBaseIndex(VertexWriter vertexWriter,size_t bufferSize,uint16_t baseIndex)112 void PathCurveTessellator::WriteFixedIndexBufferBaseIndex(VertexWriter vertexWriter,
113 size_t bufferSize,
114 uint16_t baseIndex) {
115 SkASSERT(bufferSize % (sizeof(uint16_t) * 3) == 0);
116 int triangleCount = bufferSize / (sizeof(uint16_t) * 3);
117 SkASSERT(triangleCount >= 1);
118 SkTArray<std::array<uint16_t, 3>> indexData(triangleCount);
119
120 // Connect the vertices with a middle-out triangulation. Refer to InitFixedCountVertexBuffer()
121 // for the exact vertex ordering.
122 //
123 // Resolve level 1 is just a single triangle at T=[0, 1/2, 1].
124 const auto* neighborInLastResolveLevel = &indexData.push_back({baseIndex,
125 (uint16_t)(baseIndex + 2),
126 (uint16_t)(baseIndex + 1)});
127
128 // Resolve levels 2..maxResolveLevel
129 int maxResolveLevel = SkPrevLog2(triangleCount + 1);
130 uint16_t nextIndex = baseIndex + 3;
131 SkASSERT(NumCurveTrianglesAtResolveLevel(maxResolveLevel) == triangleCount);
132 for (int resolveLevel = 2; resolveLevel <= maxResolveLevel; ++resolveLevel) {
133 SkDEBUGCODE(auto* firstTriangleInCurrentResolveLevel = indexData.end());
134 int numOuterTrianglelsInResolveLevel = 1 << (resolveLevel - 1);
135 SkASSERT(numOuterTrianglelsInResolveLevel % 2 == 0);
136 int numTrianglePairsInResolveLevel = numOuterTrianglelsInResolveLevel >> 1;
137 for (int i = 0; i < numTrianglePairsInResolveLevel; ++i) {
138 // First triangle shares the left edge of "neighborInLastResolveLevel".
139 indexData.push_back({(*neighborInLastResolveLevel)[0],
140 nextIndex++,
141 (*neighborInLastResolveLevel)[1]});
142 // Second triangle shares the right edge of "neighborInLastResolveLevel".
143 indexData.push_back({(*neighborInLastResolveLevel)[1],
144 nextIndex++,
145 (*neighborInLastResolveLevel)[2]});
146 ++neighborInLastResolveLevel;
147 }
148 SkASSERT(neighborInLastResolveLevel == firstTriangleInCurrentResolveLevel);
149 }
150 SkASSERT(indexData.count() == triangleCount);
151 SkASSERT(nextIndex == baseIndex + triangleCount + 2);
152
153 vertexWriter << VertexWriter::Array(indexData.data(), indexData.count());
154 }
155
156 #if SK_GPU_V1
157
158 SKGPU_DECLARE_STATIC_UNIQUE_KEY(gFixedVertexBufferKey);
159 SKGPU_DECLARE_STATIC_UNIQUE_KEY(gFixedIndexBufferKey);
160
prepareFixedCountBuffers(GrMeshDrawTarget * target)161 void PathCurveTessellator::prepareFixedCountBuffers(GrMeshDrawTarget* target) {
162 GrResourceProvider* rp = target->resourceProvider();
163
164 SKGPU_DEFINE_STATIC_UNIQUE_KEY(gFixedVertexBufferKey);
165
166 fFixedVertexBuffer = rp->findOrMakeStaticBuffer(GrGpuBufferType::kVertex,
167 FixedVertexBufferSize(kMaxFixedResolveLevel),
168 gFixedVertexBufferKey,
169 WriteFixedVertexBuffer);
170
171 SKGPU_DEFINE_STATIC_UNIQUE_KEY(gFixedIndexBufferKey);
172
173 fFixedIndexBuffer = rp->findOrMakeStaticBuffer(GrGpuBufferType::kIndex,
174 FixedIndexBufferSize(kMaxFixedResolveLevel),
175 gFixedIndexBufferKey,
176 WriteFixedIndexBuffer);
177 }
178
drawTessellated(GrOpFlushState * flushState) const179 void PathCurveTessellator::drawTessellated(GrOpFlushState* flushState) const {
180 for (const GrVertexChunk& chunk : fVertexChunkArray) {
181 flushState->bindBuffers(nullptr, nullptr, chunk.fBuffer);
182 flushState->draw(chunk.fCount * 4, chunk.fBase * 4);
183 }
184 }
185
drawFixedCount(GrOpFlushState * flushState) const186 void PathCurveTessellator::drawFixedCount(GrOpFlushState* flushState) const {
187 if (!fFixedVertexBuffer || !fFixedIndexBuffer) {
188 return;
189 }
190 int fixedIndexCount = NumCurveTrianglesAtResolveLevel(fFixedResolveLevel) * 3;
191 for (const GrVertexChunk& chunk : fVertexChunkArray) {
192 flushState->bindBuffers(fFixedIndexBuffer, chunk.fBuffer, fFixedVertexBuffer);
193 flushState->drawIndexedInstanced(fixedIndexCount, 0, chunk.fCount, chunk.fBase, 0);
194 }
195 }
196
drawHullInstances(GrOpFlushState * flushState,sk_sp<const GrGpuBuffer> vertexBufferIfNeeded) const197 void PathCurveTessellator::drawHullInstances(GrOpFlushState* flushState,
198 sk_sp<const GrGpuBuffer> vertexBufferIfNeeded) const {
199 for (const GrVertexChunk& chunk : fVertexChunkArray) {
200 flushState->bindBuffers(nullptr, chunk.fBuffer, vertexBufferIfNeeded);
201 flushState->drawInstanced(chunk.fCount, chunk.fBase, 4, 0);
202 }
203 }
204
205 #endif
206
207 } // namespace skgpu
208