Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
FixedCountBufferUtils.h
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
8#ifndef skgpu_tessellate_FixedCountBufferUtils_DEFINED
9#define skgpu_tessellate_FixedCountBufferUtils_DEFINED
10
13
14#include <algorithm>
15#include <cstddef>
16#include <cstdint>
17
18namespace skgpu { struct VertexWriter; }
19
20namespace skgpu::tess {
21
22/**
23 * Fixed-count tessellation operates in three modes, two for filling paths, and one for stroking.
24 * These modes may have additional sub-variations, but in terms of vertex buffer management, these
25 * three categories are sufficient:
26 *
27 * - FixedCountCurves: for filling paths where just the curves are tessellated. Additional measures
28 * to fill space between the inner control points of the paths are needed.
29 * - FixedCountWedges: for filling paths by tessellating the curves and adding an additional inline
30 * triangle with a shared vertex that all verbs connect to. Works with PatchAttribs::kFanPoint.
31 * - FixedCountStrokes: for stroking a path. Likely paired with PatchAttribs::kJoinControlPoint and
32 * PatchAttribs::kStrokeParams.
33 *
34 * The three types defined below for these three modes provide utility functions for heuristics to
35 * choose pre-allocation size when accumulating instance attributes with a PatchWriter, and
36 * functions for creating static/GPU-private vertex and index buffers that are used as the template
37 * for instanced rendering.
38 */
40 FixedCountCurves() = delete;
41public:
42 // A heuristic function for reserving instance attribute space before using a PatchWriter.
43 static constexpr int PreallocCount(int totalCombinedPathVerbCnt) {
44 // Over-allocate enough curves for 1 in 4 to chop. Every chop introduces 2 new patches:
45 // another curve patch and a triangle patch that glues the two chops together,
46 // i.e. + 2 * ((count + 3) / 4) == (count + 3) / 2
47 return totalCombinedPathVerbCnt + (totalCombinedPathVerbCnt + 3) / 2;
48 }
49
50 // Convert the accumulated worst-case tolerances into an index count passed into an instanced,
51 // indexed draw function that uses FixedCountCurves static vertex and index buffers.
52 static int VertexCount(const LinearTolerances& tolerances) {
53 // We should already chopped curves to make sure none needed a higher resolveLevel than
54 // kMaxResolveLevel.
55 int resolveLevel = std::min(tolerances.requiredResolveLevel(), kMaxResolveLevel);
56 return NumCurveTrianglesAtResolveLevel(resolveLevel) * 3;
57 }
58
59 // Return the number of bytes to allocate for a buffer filled via WriteVertexBuffer, assuming
60 // the shader and curve instances do require more than kMaxParametricSegments segments.
61 static constexpr size_t VertexBufferSize() {
62 return (kMaxParametricSegments + 1) * (2 * sizeof(float));
63 }
64
65 // As above but for the corresponding index buffer, written via WriteIndexBuffer.
66 static constexpr size_t IndexBufferSize() {
67 return NumCurveTrianglesAtResolveLevel(kMaxResolveLevel) * 3 * sizeof(uint16_t);
68 }
69
70 static void WriteVertexBuffer(VertexWriter, size_t bufferSize);
71
72 static void WriteIndexBuffer(VertexWriter, size_t bufferSize);
73};
74
76 FixedCountWedges() = delete;
77public:
78 // These functions provide equivalent functionality to the matching ones in FixedCountCurves,
79 // but are intended for use with a shader and PatchWriter that has enabled the kFanPoint attrib.
80
81 static constexpr int PreallocCount(int totalCombinedPathVerbCnt) {
82 // Over-allocate enough wedges for 1 in 4 to chop, i.e., ceil(maxWedges * 5/4)
83 return (totalCombinedPathVerbCnt * 5 + 3) / 4;
84 }
85
86 static int VertexCount(const LinearTolerances& tolerances) {
87 // Emit 3 vertices per curve triangle, plus 3 more for the wedge fan triangle.
88 int resolveLevel = std::min(tolerances.requiredResolveLevel(), kMaxResolveLevel);
89 return (NumCurveTrianglesAtResolveLevel(resolveLevel) + 1) * 3;
90 }
91
92 static constexpr size_t VertexBufferSize() {
93 return ((kMaxParametricSegments + 1) + 1/*fan vertex*/) * (2 * sizeof(float));
94 }
95
96 static constexpr size_t IndexBufferSize() {
97 return (NumCurveTrianglesAtResolveLevel(kMaxResolveLevel) + 1/*fan triangle*/) *
98 3 * sizeof(uint16_t);
99 }
100
101 static void WriteVertexBuffer(VertexWriter, size_t bufferSize);
102
103 static void WriteIndexBuffer(VertexWriter, size_t bufferSize);
104};
105
107 FixedCountStrokes() = delete;
108public:
109 // These functions provide equivalent functionality to the matching ones in FixedCountCurves,
110 // but are intended for a shader that that strokes a path instead of filling, where vertices
111 // are associated with joins, caps, radial segments, or parametric segments.
112 //
113 // NOTE: The fixed-count stroke buffer is only needed when vertex IDs are not available as an
114 // SkSL built-in. And unlike the curve and wedge variants, stroke drawing never relies on an
115 // index buffer so those functions are not provided.
116
117 // Don't draw more vertices than can be indexed by a signed short. We just have to draw the line
118 // somewhere and this seems reasonable enough. (There are two vertices per edge, so 2^14 edges
119 // make 2^15 vertices.)
120 static constexpr int kMaxEdges = (1 << 14) - 1;
121 static constexpr int kMaxEdgesNoVertexIDs = 1024;
122
123 static constexpr int PreallocCount(int totalCombinedPathVerbCnt) {
124 // Over-allocate enough patches for each stroke to chop once, and for 8 extra caps. Since
125 // we have to chop at inflections, points of 180 degree rotation, and anywhere a stroke
126 // requires too many parametric segments, many strokes will end up getting choppped.
127 return (totalCombinedPathVerbCnt * 2) + 8/* caps */;
128 }
129
130 // Does not account for falling back to kMaxEdgesNoVertexIDs
131 static int VertexCount(const LinearTolerances& tolerances) {
132 return std::min(tolerances.requiredStrokeEdges(), kMaxEdges) * 2;
133 }
134
135 static constexpr size_t VertexBufferSize() {
136 // Each vertex is a single float (explicit id) and each edge is composed of two vertices.
137 return 2 * kMaxEdgesNoVertexIDs * sizeof(float);
138 }
139
140 // Initializes the fallback vertex buffer that should be bound when sk_VertexID is not supported
141 static void WriteVertexBuffer(VertexWriter, size_t bufferSize);
142};
143
144} // namespace skgpu::tess
145
146#endif // skgpu_tessellate_FixedCountBufferUtils
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 int PreallocCount(int totalCombinedPathVerbCnt)
static void WriteVertexBuffer(VertexWriter, size_t bufferSize)
static int VertexCount(const LinearTolerances &tolerances)
static constexpr size_t VertexBufferSize()
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)
static constexpr int NumCurveTrianglesAtResolveLevel(int resolveLevel)
static constexpr int kMaxResolveLevel
static constexpr int kMaxParametricSegments