• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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