• 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 #ifndef tessellate_PatchWriter_DEFINED
9 #define tessellate_PatchWriter_DEFINED
10 
11 #include "src/gpu/GrVertexChunkArray.h"
12 #include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
13 #include "src/gpu/tessellate/Tessellation.h"
14 #include "src/gpu/tessellate/shaders/GrTessellationShader.h"
15 
16 namespace skgpu {
17 
18 #if SK_GPU_V1
19 class PathTessellator;
20 #endif
21 
22 // Writes out tessellation patches, formatted with their specific attribs, to a GPU buffer.
23 class PatchWriter {
24 public:
PatchWriter(GrMeshDrawTarget * target,GrVertexChunkArray * vertexChunkArray,PatchAttribs attribs,size_t patchStride,int initialAllocCount)25     PatchWriter(GrMeshDrawTarget* target,
26                 GrVertexChunkArray* vertexChunkArray,
27                 PatchAttribs attribs,
28                 size_t patchStride,
29                 int initialAllocCount)
30             : fPatchAttribs(attribs)
31             , fChunker(target, vertexChunkArray, patchStride, initialAllocCount) {
32     }
33 
34 #if SK_GPU_V1
35     // Creates a PatchWriter that writes directly to the GrVertexChunkArray stored on the provided
36     // PathTessellator.
37     PatchWriter(GrMeshDrawTarget*, PathTessellator* tessellator, int initialPatchAllocCount);
38 #endif
39 
40     // Updates the fan point that will be written out with each patch (i.e., the point that wedges
41     // fan around).
42     // PathPatchAttrib::kFanPoint must be enabled.
updateFanPointAttrib(SkPoint fanPoint)43     void updateFanPointAttrib(SkPoint fanPoint) {
44         SkASSERT(fPatchAttribs & PatchAttribs::kFanPoint);
45         fFanPointAttrib = fanPoint;
46     }
47 
48     // Updates the color that will be written out with each patch.
49     // PathPatchAttrib::kColor must be enabled.
updateColorAttrib(const SkPMColor4f & color)50     void updateColorAttrib(const SkPMColor4f& color) {
51         SkASSERT(fPatchAttribs & PatchAttribs::kColor);
52         fColorAttrib.set(color, fPatchAttribs & PatchAttribs::kWideColorIfEnabled);
53     }
54 
55     // RAII. Appends a patch during construction and writes the remaining data for a cubic during
56     // destruction. The caller outputs p0,p1,p2,p3 (8 floats):
57     //
58     //    CubicPatch(patchWriter) << p0 << p1 << p2 << p3;
59     //
60     struct CubicPatch {
CubicPatchCubicPatch61         CubicPatch(PatchWriter& w) : fPatchWriter(w), fVertexWriter(w.appendPatch()) {}
~CubicPatchCubicPatch62         ~CubicPatch() {
63             fPatchWriter.outputPatchAttribs(std::move(fVertexWriter),
64                                             GrTessellationShader::kCubicCurveType);
65         }
66         operator VertexWriter&() { return fVertexWriter; }
67         PatchWriter& fPatchWriter;
68         VertexWriter fVertexWriter;
69     };
70 
71     // RAII. Appends a patch during construction and writes the remaining data for a conic during
72     // destruction. The caller outputs p0,p1,p2,w (7 floats):
73     //
74     //     ConicPatch(patchWriter) << p0 << p1 << p2 << w;
75     //
76     struct ConicPatch {
ConicPatchConicPatch77         ConicPatch(PatchWriter& w) : fPatchWriter(w), fVertexWriter(w.appendPatch()) {}
~ConicPatchConicPatch78         ~ConicPatch() {
79             fVertexWriter << VertexWriter::kIEEE_32_infinity;  // p3.y=Inf indicates a conic.
80             fPatchWriter.outputPatchAttribs(std::move(fVertexWriter),
81                                             GrTessellationShader::kConicCurveType);
82         }
83         operator VertexWriter&() { return fVertexWriter; }
84         PatchWriter& fPatchWriter;
85         VertexWriter fVertexWriter;
86     };
87 
88     // RAII. Appends a patch during construction and writes the remaining data for a triangle during
89     // destruction. The caller outputs p0,p1,p2 (6 floats):
90     //
91     //     TrianglePatch(patchWriter) << p0 << p1 << p2;
92     //
93     struct TrianglePatch {
TrianglePatchTrianglePatch94         TrianglePatch(PatchWriter& w) : fPatchWriter(w), fVertexWriter(w.appendPatch()) {}
~TrianglePatchTrianglePatch95         ~TrianglePatch() {
96             // Mark this patch as a triangle by setting it to a conic with w=Inf.
97             fVertexWriter.fill(VertexWriter::kIEEE_32_infinity, 2);
98             fPatchWriter.outputPatchAttribs(std::move(fVertexWriter),
99                                             GrTessellationShader::kTriangularConicCurveType);
100         }
101         operator VertexWriter&() { return fVertexWriter; }
102         PatchWriter& fPatchWriter;
103         VertexWriter fVertexWriter;
104     };
105 
106     // Chops the given quadratic into 'numPatches' equal segments (in the parametric sense) and
107     // writes them to the GPU buffer.
108     //
109     // Fills space between chops with triangles if PathPatchAttrib::kFanPoint is not enabled.
110     void chopAndWriteQuads(float2 p0, float2 p1, float2 p2, int numPatches);
111 
112     // Chops the given conic into 'numPatches' equal segments (in the parametric sense) and
113     // writes them to the GPU buffer.
114     //
115     // Fills space between chops with triangles if PathPatchAttrib::kFanPoint is not enabled.
116     void chopAndWriteConics(float2 p0, float2 p1, float2 p2, float w, int numPatches);
117 
118     // Chops the given cubic into 'numPatches' equal segments (in the parametric sense) and
119     // writes them to the GPU buffer.
120     //
121     // Fills space between chops with triangles if PathPatchAttrib::kFanPoint is not enabled.
122     void chopAndWriteCubics(float2 p0, float2 p1, float2 p2, float2 p3, int numPatches);
123 
124 private:
appendPatch()125     VertexWriter appendPatch() {
126         VertexWriter vertexWriter = fChunker.appendVertex();
127         if (!vertexWriter) {
128             // Failed to allocate GPU storage for the patch. Write to a throwaway location so the
129             // callsites don't have to do null checks.
130             if (!fFallbackPatchStorage) {
131                 fFallbackPatchStorage.reset(fChunker.stride());
132             }
133             vertexWriter = fFallbackPatchStorage.data();
134         }
135         return vertexWriter;
136     }
137 
138     template <typename T>
If(bool c,const T & v)139     static VertexWriter::Conditional<T> If(bool c, const T& v) { return VertexWriter::If(c,v); }
140 
outputPatchAttribs(VertexWriter vertexWriter,float explicitCurveType)141     void outputPatchAttribs(VertexWriter vertexWriter, float explicitCurveType) {
142         vertexWriter << If((fPatchAttribs & PatchAttribs::kFanPoint), fFanPointAttrib)
143                      << If((fPatchAttribs & PatchAttribs::kColor), fColorAttrib)
144                      << If((fPatchAttribs & PatchAttribs::kExplicitCurveType), explicitCurveType);
145     }
146 
147     const PatchAttribs fPatchAttribs;
148     SkPoint fFanPointAttrib;
149     GrVertexColor fColorAttrib;
150 
151     GrVertexChunkBuilder fChunker;
152 
153     // For when fChunker fails to allocate a patch in GPU memory.
154     SkAutoTMalloc<char> fFallbackPatchStorage;
155 };
156 
157 // Converts a line to a cubic when being output via '<<' to a VertexWriter.
158 struct LineToCubic {
159     float4 fP0P1;
160 };
161 
162 SK_MAYBE_UNUSED SK_ALWAYS_INLINE VertexWriter& operator<<(VertexWriter& vertexWriter,
163                                                           const LineToCubic& line) {
164     float4 p0p1 = line.fP0P1;
165     float4 v = p0p1.zwxy() - p0p1;
166     return vertexWriter << p0p1.lo << (v * (1/3.f) + p0p1) << p0p1.hi;
167 }
168 
169 // Converts a quadratic to a cubic when being output via '<<' to a VertexWriter.
170 struct QuadToCubic {
171     float2 fP0, fP1, fP2;
172 };
173 
174 SK_MAYBE_UNUSED SK_ALWAYS_INLINE VertexWriter& operator<<(VertexWriter& vertexWriter,
175                                                           const QuadToCubic& quadratic) {
176     auto [p0, p1, p2] = quadratic;
177     return vertexWriter << p0 << mix(float4(p0,p2), p1.xyxy(), 2/3.f) << p2;
178 }
179 
180 SK_MAYBE_UNUSED SK_ALWAYS_INLINE void operator<<(
181         PatchWriter& w, MiddleOutPolygonTriangulator::PoppedTriangleStack&& stack) {
182     for (auto [p0, p1, p2] : stack) {
183         PatchWriter::TrianglePatch(w) << p0 << p1 << p2;
184     }
185 }
186 
187 }  // namespace skgpu
188 
189 #endif  // tessellate_PatchWriter_DEFINED
190