1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2021 Google LLC.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/gpu/tessellate/PathCurveTessellator.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrPathUtils.h"
11cb93a386Sopenharmony_ci#include "src/gpu/tessellate/AffineMatrix.h"
12cb93a386Sopenharmony_ci#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
13cb93a386Sopenharmony_ci#include "src/gpu/tessellate/PatchWriter.h"
14cb93a386Sopenharmony_ci#include "src/gpu/tessellate/WangsFormula.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci#if SK_GPU_V1
17cb93a386Sopenharmony_ci#include "src/gpu/GrMeshDrawTarget.h"
18cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h"
19cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h"
20cb93a386Sopenharmony_ci#endif
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_cinamespace skgpu {
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ciusing CubicPatch = PatchWriter::CubicPatch;
25cb93a386Sopenharmony_ciusing ConicPatch = PatchWriter::ConicPatch;
26cb93a386Sopenharmony_ciusing TrianglePatch = PatchWriter::TrianglePatch;
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_ciint PathCurveTessellator::patchPreallocCount(int totalCombinedPathVerbCnt) const {
29cb93a386Sopenharmony_ci    // Over-allocate enough curves for 1 in 4 to chop.
30cb93a386Sopenharmony_ci    int approxNumChops = (totalCombinedPathVerbCnt + 3) / 4;
31cb93a386Sopenharmony_ci    // Every chop introduces 2 new patches: another curve patch and a triangle patch that glues the
32cb93a386Sopenharmony_ci    // two chops together.
33cb93a386Sopenharmony_ci    return totalCombinedPathVerbCnt + approxNumChops * 2;
34cb93a386Sopenharmony_ci}
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_civoid PathCurveTessellator::writePatches(PatchWriter& patchWriter,
37cb93a386Sopenharmony_ci                                        int maxTessellationSegments,
38cb93a386Sopenharmony_ci                                        const SkMatrix& shaderMatrix,
39cb93a386Sopenharmony_ci                                        const PathDrawList& pathDrawList) {
40cb93a386Sopenharmony_ci    float maxSegments_pow2 = pow2(maxTessellationSegments);
41cb93a386Sopenharmony_ci    float maxSegments_pow4 = pow2(maxSegments_pow2);
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_ci    // If using fixed count, this is the number of segments we need to emit per instance. Always
44cb93a386Sopenharmony_ci    // emit at least 2 segments so we can support triangles.
45cb93a386Sopenharmony_ci    float numFixedSegments_pow4 = 2*2*2*2;
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci    for (auto [pathMatrix, path, color] : pathDrawList) {
48cb93a386Sopenharmony_ci        AffineMatrix m(pathMatrix);
49cb93a386Sopenharmony_ci        wangs_formula::VectorXform totalXform(SkMatrix::Concat(shaderMatrix, pathMatrix));
50cb93a386Sopenharmony_ci        if (fAttribs & PatchAttribs::kColor) {
51cb93a386Sopenharmony_ci            patchWriter.updateColorAttrib(color);
52cb93a386Sopenharmony_ci        }
53cb93a386Sopenharmony_ci        for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
54cb93a386Sopenharmony_ci            switch (verb) {
55cb93a386Sopenharmony_ci                case SkPathVerb::kQuad: {
56cb93a386Sopenharmony_ci                    auto [p0, p1] = m.map2Points(pts);
57cb93a386Sopenharmony_ci                    auto p2 = m.map1Point(pts+2);
58cb93a386Sopenharmony_ci                    float n4 = wangs_formula::quadratic_pow4(kTessellationPrecision,
59cb93a386Sopenharmony_ci                                                             pts,
60cb93a386Sopenharmony_ci                                                             totalXform);
61cb93a386Sopenharmony_ci                    if (n4 <= 1) {
62cb93a386Sopenharmony_ci                        break;  // This quad only needs 1 segment, which is empty.
63cb93a386Sopenharmony_ci                    }
64cb93a386Sopenharmony_ci                    if (n4 <= maxSegments_pow4) {
65cb93a386Sopenharmony_ci                        // This quad already fits in "maxTessellationSegments".
66cb93a386Sopenharmony_ci                        CubicPatch(patchWriter) << QuadToCubic{p0, p1, p2};
67cb93a386Sopenharmony_ci                    } else {
68cb93a386Sopenharmony_ci                        // Chop until each quad tessellation requires "maxSegments" or fewer.
69cb93a386Sopenharmony_ci                        int numPatches =
70cb93a386Sopenharmony_ci                                SkScalarCeilToInt(wangs_formula::root4(n4/maxSegments_pow4));
71cb93a386Sopenharmony_ci                        patchWriter.chopAndWriteQuads(p0, p1, p2, numPatches);
72cb93a386Sopenharmony_ci                    }
73cb93a386Sopenharmony_ci                    numFixedSegments_pow4 = std::max(n4, numFixedSegments_pow4);
74cb93a386Sopenharmony_ci                    break;
75cb93a386Sopenharmony_ci                }
76cb93a386Sopenharmony_ci
77cb93a386Sopenharmony_ci                case SkPathVerb::kConic: {
78cb93a386Sopenharmony_ci                    auto [p0, p1] = m.map2Points(pts);
79cb93a386Sopenharmony_ci                    auto p2 = m.map1Point(pts+2);
80cb93a386Sopenharmony_ci                    float n2 = wangs_formula::conic_pow2(kTessellationPrecision,
81cb93a386Sopenharmony_ci                                                         pts,
82cb93a386Sopenharmony_ci                                                         *w,
83cb93a386Sopenharmony_ci                                                         totalXform);
84cb93a386Sopenharmony_ci                    if (n2 <= 1) {
85cb93a386Sopenharmony_ci                        break;  // This conic only needs 1 segment, which is empty.
86cb93a386Sopenharmony_ci                    }
87cb93a386Sopenharmony_ci                    if (n2 <= maxSegments_pow2) {
88cb93a386Sopenharmony_ci                        // This conic already fits in "maxTessellationSegments".
89cb93a386Sopenharmony_ci                        ConicPatch(patchWriter) << p0 << p1 << p2 << *w;
90cb93a386Sopenharmony_ci                    } else {
91cb93a386Sopenharmony_ci                        // Chop until each conic tessellation requires "maxSegments" or fewer.
92cb93a386Sopenharmony_ci                        int numPatches = SkScalarCeilToInt(sqrtf(n2/maxSegments_pow2));
93cb93a386Sopenharmony_ci                        patchWriter.chopAndWriteConics(p0, p1, p2, *w, numPatches);
94cb93a386Sopenharmony_ci                    }
95cb93a386Sopenharmony_ci                    numFixedSegments_pow4 = std::max(n2*n2, numFixedSegments_pow4);
96cb93a386Sopenharmony_ci                    break;
97cb93a386Sopenharmony_ci                }
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci                case SkPathVerb::kCubic: {
100cb93a386Sopenharmony_ci                    auto [p0, p1] = m.map2Points(pts);
101cb93a386Sopenharmony_ci                    auto [p2, p3] = m.map2Points(pts+2);
102cb93a386Sopenharmony_ci                    float n4 = wangs_formula::cubic_pow4(kTessellationPrecision,
103cb93a386Sopenharmony_ci                                                         pts,
104cb93a386Sopenharmony_ci                                                         totalXform);
105cb93a386Sopenharmony_ci                    if (n4 <= 1) {
106cb93a386Sopenharmony_ci                        break;  // This cubic only needs 1 segment, which is empty.
107cb93a386Sopenharmony_ci                    }
108cb93a386Sopenharmony_ci                    if (n4 <= maxSegments_pow4) {
109cb93a386Sopenharmony_ci                        // This cubic already fits in "maxTessellationSegments".
110cb93a386Sopenharmony_ci                        CubicPatch(patchWriter) << p0 << p1 << p2 << p3;
111cb93a386Sopenharmony_ci                    } else {
112cb93a386Sopenharmony_ci                        // Chop until each cubic tessellation requires "maxSegments" or fewer.
113cb93a386Sopenharmony_ci                        int numPatches =
114cb93a386Sopenharmony_ci                                SkScalarCeilToInt(wangs_formula::root4(n4/maxSegments_pow4));
115cb93a386Sopenharmony_ci                        patchWriter.chopAndWriteCubics(p0, p1, p2, p3, numPatches);
116cb93a386Sopenharmony_ci                    }
117cb93a386Sopenharmony_ci                    numFixedSegments_pow4 = std::max(n4, numFixedSegments_pow4);
118cb93a386Sopenharmony_ci                    break;
119cb93a386Sopenharmony_ci                }
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_ci                default: break;
122cb93a386Sopenharmony_ci            }
123cb93a386Sopenharmony_ci        }
124cb93a386Sopenharmony_ci    }
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci    // log16(n^4) == log2(n).
127cb93a386Sopenharmony_ci    // We already chopped curves to make sure none needed a higher resolveLevel than
128cb93a386Sopenharmony_ci    // kMaxFixedResolveLevel.
129cb93a386Sopenharmony_ci    fFixedResolveLevel = SkTPin(wangs_formula::nextlog16(numFixedSegments_pow4),
130cb93a386Sopenharmony_ci                                fFixedResolveLevel,
131cb93a386Sopenharmony_ci                                int(kMaxFixedResolveLevel));
132cb93a386Sopenharmony_ci}
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_civoid PathCurveTessellator::WriteFixedVertexBuffer(VertexWriter vertexWriter, size_t bufferSize) {
135cb93a386Sopenharmony_ci    SkASSERT(bufferSize >= sizeof(SkPoint) * 2);
136cb93a386Sopenharmony_ci    SkASSERT(bufferSize % sizeof(SkPoint) == 0);
137cb93a386Sopenharmony_ci    int vertexCount = bufferSize / sizeof(SkPoint);
138cb93a386Sopenharmony_ci    SkASSERT(vertexCount > 3);
139cb93a386Sopenharmony_ci    SkDEBUGCODE(VertexWriter end = vertexWriter.makeOffset(vertexCount * sizeof(SkPoint));)
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci    // Lay out the vertices in "middle-out" order:
142cb93a386Sopenharmony_ci    //
143cb93a386Sopenharmony_ci    // T= 0/1, 1/1,              ; resolveLevel=0
144cb93a386Sopenharmony_ci    //    1/2,                   ; resolveLevel=1  (0/2 and 2/2 are already in resolveLevel 0)
145cb93a386Sopenharmony_ci    //    1/4, 3/4,              ; resolveLevel=2  (2/4 is already in resolveLevel 1)
146cb93a386Sopenharmony_ci    //    1/8, 3/8, 5/8, 7/8,    ; resolveLevel=3  (2/8 and 6/8 are already in resolveLevel 2)
147cb93a386Sopenharmony_ci    //    ...                    ; resolveLevel=...
148cb93a386Sopenharmony_ci    //
149cb93a386Sopenharmony_ci    // Resolve level 0 is just the beginning and ending vertices.
150cb93a386Sopenharmony_ci    vertexWriter << (float)0/*resolveLevel*/ << (float)0/*idx*/;
151cb93a386Sopenharmony_ci    vertexWriter << (float)0/*resolveLevel*/ << (float)1/*idx*/;
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_ci    // Resolve levels 1..kMaxResolveLevel.
154cb93a386Sopenharmony_ci    int maxResolveLevel = SkPrevLog2(vertexCount - 1);
155cb93a386Sopenharmony_ci    SkASSERT((1 << maxResolveLevel) + 1 == vertexCount);
156cb93a386Sopenharmony_ci    for (int resolveLevel = 1; resolveLevel <= maxResolveLevel; ++resolveLevel) {
157cb93a386Sopenharmony_ci        int numSegmentsInResolveLevel = 1 << resolveLevel;
158cb93a386Sopenharmony_ci        // Write out the odd vertices in this resolveLevel. The even vertices were already written
159cb93a386Sopenharmony_ci        // out in previous resolveLevels and will be indexed from there.
160cb93a386Sopenharmony_ci        for (int i = 1; i < numSegmentsInResolveLevel; i += 2) {
161cb93a386Sopenharmony_ci            vertexWriter << (float)resolveLevel << (float)i;
162cb93a386Sopenharmony_ci        }
163cb93a386Sopenharmony_ci    }
164cb93a386Sopenharmony_ci
165cb93a386Sopenharmony_ci    SkASSERT(vertexWriter == end);
166cb93a386Sopenharmony_ci}
167cb93a386Sopenharmony_ci
168cb93a386Sopenharmony_civoid PathCurveTessellator::WriteFixedIndexBufferBaseIndex(VertexWriter vertexWriter,
169cb93a386Sopenharmony_ci                                                          size_t bufferSize,
170cb93a386Sopenharmony_ci                                                          uint16_t baseIndex) {
171cb93a386Sopenharmony_ci    SkASSERT(bufferSize % (sizeof(uint16_t) * 3) == 0);
172cb93a386Sopenharmony_ci    int triangleCount = bufferSize / (sizeof(uint16_t) * 3);
173cb93a386Sopenharmony_ci    SkASSERT(triangleCount >= 1);
174cb93a386Sopenharmony_ci    SkTArray<std::array<uint16_t, 3>> indexData(triangleCount);
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci    // Connect the vertices with a middle-out triangulation. Refer to InitFixedCountVertexBuffer()
177cb93a386Sopenharmony_ci    // for the exact vertex ordering.
178cb93a386Sopenharmony_ci    //
179cb93a386Sopenharmony_ci    // Resolve level 1 is just a single triangle at T=[0, 1/2, 1].
180cb93a386Sopenharmony_ci    const auto* neighborInLastResolveLevel = &indexData.push_back({baseIndex,
181cb93a386Sopenharmony_ci                                                                   (uint16_t)(baseIndex + 2),
182cb93a386Sopenharmony_ci                                                                   (uint16_t)(baseIndex + 1)});
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_ci    // Resolve levels 2..maxResolveLevel
185cb93a386Sopenharmony_ci    int maxResolveLevel = SkPrevLog2(triangleCount + 1);
186cb93a386Sopenharmony_ci    uint16_t nextIndex = baseIndex + 3;
187cb93a386Sopenharmony_ci    SkASSERT(NumCurveTrianglesAtResolveLevel(maxResolveLevel) == triangleCount);
188cb93a386Sopenharmony_ci    for (int resolveLevel = 2; resolveLevel <= maxResolveLevel; ++resolveLevel) {
189cb93a386Sopenharmony_ci        SkDEBUGCODE(auto* firstTriangleInCurrentResolveLevel = indexData.end());
190cb93a386Sopenharmony_ci        int numOuterTrianglelsInResolveLevel = 1 << (resolveLevel - 1);
191cb93a386Sopenharmony_ci        SkASSERT(numOuterTrianglelsInResolveLevel % 2 == 0);
192cb93a386Sopenharmony_ci        int numTrianglePairsInResolveLevel = numOuterTrianglelsInResolveLevel >> 1;
193cb93a386Sopenharmony_ci        for (int i = 0; i < numTrianglePairsInResolveLevel; ++i) {
194cb93a386Sopenharmony_ci            // First triangle shares the left edge of "neighborInLastResolveLevel".
195cb93a386Sopenharmony_ci            indexData.push_back({(*neighborInLastResolveLevel)[0],
196cb93a386Sopenharmony_ci                                 nextIndex++,
197cb93a386Sopenharmony_ci                                 (*neighborInLastResolveLevel)[1]});
198cb93a386Sopenharmony_ci            // Second triangle shares the right edge of "neighborInLastResolveLevel".
199cb93a386Sopenharmony_ci            indexData.push_back({(*neighborInLastResolveLevel)[1],
200cb93a386Sopenharmony_ci                                 nextIndex++,
201cb93a386Sopenharmony_ci                                 (*neighborInLastResolveLevel)[2]});
202cb93a386Sopenharmony_ci            ++neighborInLastResolveLevel;
203cb93a386Sopenharmony_ci        }
204cb93a386Sopenharmony_ci        SkASSERT(neighborInLastResolveLevel == firstTriangleInCurrentResolveLevel);
205cb93a386Sopenharmony_ci    }
206cb93a386Sopenharmony_ci    SkASSERT(indexData.count() == triangleCount);
207cb93a386Sopenharmony_ci    SkASSERT(nextIndex == baseIndex + triangleCount + 2);
208cb93a386Sopenharmony_ci
209cb93a386Sopenharmony_ci    vertexWriter.writeArray(indexData.data(), indexData.count());
210cb93a386Sopenharmony_ci}
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_ci#if SK_GPU_V1
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_ciGR_DECLARE_STATIC_UNIQUE_KEY(gFixedVertexBufferKey);
215cb93a386Sopenharmony_ciGR_DECLARE_STATIC_UNIQUE_KEY(gFixedIndexBufferKey);
216cb93a386Sopenharmony_ci
217cb93a386Sopenharmony_civoid PathCurveTessellator::prepareFixedCountBuffers(GrMeshDrawTarget* target) {
218cb93a386Sopenharmony_ci    GrResourceProvider* rp = target->resourceProvider();
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci    GR_DEFINE_STATIC_UNIQUE_KEY(gFixedVertexBufferKey);
221cb93a386Sopenharmony_ci
222cb93a386Sopenharmony_ci    fFixedVertexBuffer = rp->findOrMakeStaticBuffer(GrGpuBufferType::kVertex,
223cb93a386Sopenharmony_ci                                                    FixedVertexBufferSize(kMaxFixedResolveLevel),
224cb93a386Sopenharmony_ci                                                    gFixedVertexBufferKey,
225cb93a386Sopenharmony_ci                                                    WriteFixedVertexBuffer);
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ci    GR_DEFINE_STATIC_UNIQUE_KEY(gFixedIndexBufferKey);
228cb93a386Sopenharmony_ci
229cb93a386Sopenharmony_ci    fFixedIndexBuffer = rp->findOrMakeStaticBuffer(GrGpuBufferType::kIndex,
230cb93a386Sopenharmony_ci                                                   FixedIndexBufferSize(kMaxFixedResolveLevel),
231cb93a386Sopenharmony_ci                                                   gFixedIndexBufferKey,
232cb93a386Sopenharmony_ci                                                   WriteFixedIndexBuffer);
233cb93a386Sopenharmony_ci}
234cb93a386Sopenharmony_ci
235cb93a386Sopenharmony_civoid PathCurveTessellator::drawTessellated(GrOpFlushState* flushState) const {
236cb93a386Sopenharmony_ci    for (const GrVertexChunk& chunk : fVertexChunkArray) {
237cb93a386Sopenharmony_ci        flushState->bindBuffers(nullptr, nullptr, chunk.fBuffer);
238cb93a386Sopenharmony_ci        flushState->draw(chunk.fCount * 4, chunk.fBase * 4);
239cb93a386Sopenharmony_ci    }
240cb93a386Sopenharmony_ci}
241cb93a386Sopenharmony_ci
242cb93a386Sopenharmony_civoid PathCurveTessellator::drawFixedCount(GrOpFlushState* flushState) const {
243cb93a386Sopenharmony_ci    if (!fFixedVertexBuffer || !fFixedIndexBuffer) {
244cb93a386Sopenharmony_ci        return;
245cb93a386Sopenharmony_ci    }
246cb93a386Sopenharmony_ci    int fixedIndexCount = NumCurveTrianglesAtResolveLevel(fFixedResolveLevel) * 3;
247cb93a386Sopenharmony_ci    for (const GrVertexChunk& chunk : fVertexChunkArray) {
248cb93a386Sopenharmony_ci        flushState->bindBuffers(fFixedIndexBuffer, chunk.fBuffer, fFixedVertexBuffer);
249cb93a386Sopenharmony_ci        flushState->drawIndexedInstanced(fixedIndexCount, 0, chunk.fCount, chunk.fBase, 0);
250cb93a386Sopenharmony_ci    }
251cb93a386Sopenharmony_ci}
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_civoid PathCurveTessellator::drawHullInstances(GrOpFlushState* flushState,
254cb93a386Sopenharmony_ci                                             sk_sp<const GrGpuBuffer> vertexBufferIfNeeded) const {
255cb93a386Sopenharmony_ci    for (const GrVertexChunk& chunk : fVertexChunkArray) {
256cb93a386Sopenharmony_ci        flushState->bindBuffers(nullptr, chunk.fBuffer, vertexBufferIfNeeded);
257cb93a386Sopenharmony_ci        flushState->drawInstanced(chunk.fCount, chunk.fBase, 4, 0);
258cb93a386Sopenharmony_ci    }
259cb93a386Sopenharmony_ci}
260cb93a386Sopenharmony_ci
261cb93a386Sopenharmony_ci#endif
262cb93a386Sopenharmony_ci
263cb93a386Sopenharmony_ci}  // namespace skgpu
264