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#ifndef tessellate_PathTessellator_DEFINED
9cb93a386Sopenharmony_ci#define tessellate_PathTessellator_DEFINED
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include "src/gpu/tessellate/Tessellation.h"
12cb93a386Sopenharmony_ci
13cb93a386Sopenharmony_ciclass SkPath;
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci#if SK_GPU_V1
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ci#include "src/gpu/GrVertexChunkArray.h"
18cb93a386Sopenharmony_ci#include "src/gpu/tessellate/PatchWriter.h"
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_ciclass GrGpuBuffer;
21cb93a386Sopenharmony_ciclass GrMeshDrawTarget;
22cb93a386Sopenharmony_ciclass GrOpFlushState;
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci#endif
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_cinamespace skgpu {
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_ciclass PatchWriter;
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ci// Prepares GPU data for, and then draws a path's tessellated geometry. Depending on the subclass,
31cb93a386Sopenharmony_ci// the caller may or may not be required to draw the path's inner fan separately.
32cb93a386Sopenharmony_ciclass PathTessellator {
33cb93a386Sopenharmony_cipublic:
34cb93a386Sopenharmony_ci    // This is the maximum number of segments contained in our vertex and index buffers for
35cb93a386Sopenharmony_ci    // fixed-count rendering. If rendering in fixed-count mode and a curve requires more segments,
36cb93a386Sopenharmony_ci    // it must be chopped.
37cb93a386Sopenharmony_ci    constexpr static int kMaxFixedResolveLevel = 5;
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci    struct PathDrawList {
40cb93a386Sopenharmony_ci        PathDrawList(const SkMatrix& pathMatrix,
41cb93a386Sopenharmony_ci                     const SkPath& path,
42cb93a386Sopenharmony_ci                     const SkPMColor4f& color,
43cb93a386Sopenharmony_ci                     PathDrawList* next = nullptr)
44cb93a386Sopenharmony_ci                : fPathMatrix(pathMatrix), fPath(path), fColor(color), fNext(next) {}
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ci        SkMatrix fPathMatrix;
47cb93a386Sopenharmony_ci        SkPath fPath;
48cb93a386Sopenharmony_ci        SkPMColor4f fColor;
49cb93a386Sopenharmony_ci        PathDrawList* fNext;
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ci        struct Iter {
52cb93a386Sopenharmony_ci            void operator++() { fHead = fHead->fNext; }
53cb93a386Sopenharmony_ci            bool operator!=(const Iter& b) const { return fHead != b.fHead; }
54cb93a386Sopenharmony_ci            std::tuple<const SkMatrix&, const SkPath&, const SkPMColor4f&> operator*() const {
55cb93a386Sopenharmony_ci                return {fHead->fPathMatrix, fHead->fPath, fHead->fColor};
56cb93a386Sopenharmony_ci            }
57cb93a386Sopenharmony_ci            const PathDrawList* fHead;
58cb93a386Sopenharmony_ci        };
59cb93a386Sopenharmony_ci        Iter begin() const { return {this}; }
60cb93a386Sopenharmony_ci        Iter end() const { return {nullptr}; }
61cb93a386Sopenharmony_ci    };
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ci    virtual ~PathTessellator() {}
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_ci    PatchAttribs patchAttribs() const { return fAttribs; }
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_ci    // Gives an approximate initial buffer size for this class to write patches into. Ideally the
68cb93a386Sopenharmony_ci    // whole path will fit into this initial buffer, but if it requires a lot of chopping, the
69cb93a386Sopenharmony_ci    // PatchWriter will allocate more buffer(s).
70cb93a386Sopenharmony_ci    virtual int patchPreallocCount(int totalCombinedPathVerbCnt) const = 0;
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_ci    // Writes out patches to the given PatchWriter, chopping as necessary so the curves all fit in
73cb93a386Sopenharmony_ci    // maxTessellationSegments or fewer.
74cb93a386Sopenharmony_ci    //
75cb93a386Sopenharmony_ci    // Each path's fPathMatrix in the list is applied on the CPU while the geometry is being written
76cb93a386Sopenharmony_ci    // out. This is a tool for batching, and is applied in addition to the shader's on-GPU matrix.
77cb93a386Sopenharmony_ci    virtual void writePatches(PatchWriter&,
78cb93a386Sopenharmony_ci                              int maxTessellationSegments,
79cb93a386Sopenharmony_ci                              const SkMatrix& shaderMatrix,
80cb93a386Sopenharmony_ci                              const PathDrawList&) = 0;
81cb93a386Sopenharmony_ci
82cb93a386Sopenharmony_ci#if SK_GPU_V1
83cb93a386Sopenharmony_ci    // Initializes the internal vertex and index buffers required for drawFixedCount().
84cb93a386Sopenharmony_ci    virtual void prepareFixedCountBuffers(GrMeshDrawTarget*) = 0;
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci    // Called before draw(). Prepares GPU buffers containing the geometry to tessellate.
87cb93a386Sopenharmony_ci    void prepare(GrMeshDrawTarget* target,
88cb93a386Sopenharmony_ci                 int maxTessellationSegments,
89cb93a386Sopenharmony_ci                 const SkMatrix& shaderMatrix,
90cb93a386Sopenharmony_ci                 const PathDrawList& pathDrawList,
91cb93a386Sopenharmony_ci                 int totalCombinedPathVerbCnt,
92cb93a386Sopenharmony_ci                 bool willUseTessellationShaders) {
93cb93a386Sopenharmony_ci        if (int patchPreallocCount = this->patchPreallocCount(totalCombinedPathVerbCnt)) {
94cb93a386Sopenharmony_ci            PatchWriter patchWriter(target, this, patchPreallocCount);
95cb93a386Sopenharmony_ci            this->writePatches(patchWriter, maxTessellationSegments, shaderMatrix, pathDrawList);
96cb93a386Sopenharmony_ci        }
97cb93a386Sopenharmony_ci        if (!willUseTessellationShaders) {
98cb93a386Sopenharmony_ci            this->prepareFixedCountBuffers(target);
99cb93a386Sopenharmony_ci        }
100cb93a386Sopenharmony_ci    }
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ci    // Issues hardware tessellation draw calls over the patches. The caller is responsible for
103cb93a386Sopenharmony_ci    // binding its desired pipeline ahead of time.
104cb93a386Sopenharmony_ci    virtual void drawTessellated(GrOpFlushState*) const = 0;
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci    // Issues fixed-count instanced draw calls over the patches. The caller is responsible for
107cb93a386Sopenharmony_ci    // binding its desired pipeline ahead of time.
108cb93a386Sopenharmony_ci    virtual void drawFixedCount(GrOpFlushState*) const = 0;
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci    void draw(GrOpFlushState* flushState, bool willUseTessellationShaders) {
111cb93a386Sopenharmony_ci        if (willUseTessellationShaders) {
112cb93a386Sopenharmony_ci            this->drawTessellated(flushState);
113cb93a386Sopenharmony_ci        } else {
114cb93a386Sopenharmony_ci            this->drawFixedCount(flushState);
115cb93a386Sopenharmony_ci        }
116cb93a386Sopenharmony_ci    }
117cb93a386Sopenharmony_ci#endif
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci    // Returns an upper bound on the number of combined edges there might be from all inner fans in
120cb93a386Sopenharmony_ci    // a PathDrawList.
121cb93a386Sopenharmony_ci    static int MaxCombinedFanEdgesInPathDrawList(int totalCombinedPathVerbCnt) {
122cb93a386Sopenharmony_ci        // Path fans might have an extra edge from an implicit kClose at the end, but they also
123cb93a386Sopenharmony_ci        // always begin with kMove. So the max possible number of edges in a single path is equal to
124cb93a386Sopenharmony_ci        // the number of verbs. Therefore, the max number of combined fan edges in a PathDrawList is
125cb93a386Sopenharmony_ci        // the number of combined path verbs in that PathDrawList.
126cb93a386Sopenharmony_ci        return totalCombinedPathVerbCnt;
127cb93a386Sopenharmony_ci    }
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ciprotected:
130cb93a386Sopenharmony_ci    // How many triangles are in a curve with 2^resolveLevel line segments?
131cb93a386Sopenharmony_ci    constexpr static int NumCurveTrianglesAtResolveLevel(int resolveLevel) {
132cb93a386Sopenharmony_ci        // resolveLevel=0 -> 0 line segments -> 0 triangles
133cb93a386Sopenharmony_ci        // resolveLevel=1 -> 2 line segments -> 1 triangle
134cb93a386Sopenharmony_ci        // resolveLevel=2 -> 4 line segments -> 3 triangles
135cb93a386Sopenharmony_ci        // resolveLevel=3 -> 8 line segments -> 7 triangles
136cb93a386Sopenharmony_ci        // ...
137cb93a386Sopenharmony_ci        return (1 << resolveLevel) - 1;
138cb93a386Sopenharmony_ci    }
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ci    PathTessellator(bool infinitySupport, PatchAttribs attribs) : fAttribs(attribs) {
141cb93a386Sopenharmony_ci        if (!infinitySupport) {
142cb93a386Sopenharmony_ci            fAttribs |= PatchAttribs::kExplicitCurveType;
143cb93a386Sopenharmony_ci        }
144cb93a386Sopenharmony_ci    }
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci    PatchAttribs fAttribs;
147cb93a386Sopenharmony_ci
148cb93a386Sopenharmony_ci    // Calculated during prepare(). If using fixed count, this is the resolveLevel to use on our
149cb93a386Sopenharmony_ci    // instanced draws. 2^resolveLevel == numSegments.
150cb93a386Sopenharmony_ci    int fFixedResolveLevel = 0;
151cb93a386Sopenharmony_ci
152cb93a386Sopenharmony_ci#if SK_GPU_V1
153cb93a386Sopenharmony_ci    friend class PatchWriter;  // To access fVertexChunkArray.
154cb93a386Sopenharmony_ci
155cb93a386Sopenharmony_ci    GrVertexChunkArray fVertexChunkArray;
156cb93a386Sopenharmony_ci
157cb93a386Sopenharmony_ci    // If using fixed-count rendering, these are the vertex and index buffers.
158cb93a386Sopenharmony_ci    sk_sp<const GrGpuBuffer> fFixedVertexBuffer;
159cb93a386Sopenharmony_ci    sk_sp<const GrGpuBuffer> fFixedIndexBuffer;
160cb93a386Sopenharmony_ci#endif
161cb93a386Sopenharmony_ci};
162cb93a386Sopenharmony_ci
163cb93a386Sopenharmony_ci}  // namespace skgpu
164cb93a386Sopenharmony_ci
165cb93a386Sopenharmony_ci#endif  // tessellate_PathTessellator_DEFINED
166