xref: /aosp_15_r20/external/skia/include/core/SkMesh.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 SkMesh_DEFINED
9 #define SkMesh_DEFINED
10 
11 #include "include/core/SkData.h"
12 #include "include/core/SkRect.h"
13 #include "include/core/SkRefCnt.h"
14 #include "include/core/SkSpan.h"
15 #include "include/core/SkString.h"
16 #include "include/effects/SkRuntimeEffect.h"
17 #include "include/private/base/SkAPI.h"
18 #include "include/private/base/SkTArray.h"
19 
20 #include <cstddef>
21 #include <cstdint>
22 #include <memory>
23 #include <string_view>
24 #include <tuple>
25 #include <vector>
26 
27 class GrDirectContext;
28 class SkColorSpace;
29 enum SkAlphaType : int;
30 
31 namespace SkSL { struct Program; }
32 
33 /**
34  * A specification for custom meshes. Specifies the vertex buffer attributes and stride, the
35  * vertex program that produces a user-defined set of varyings, and a fragment program that ingests
36  * the interpolated varyings and produces local coordinates for shading and optionally a color.
37  *
38  * The varyings must include a float2 named "position". If the passed varyings does not
39  * contain such a varying then one is implicitly added to the final specification and the SkSL
40  * Varyings struct described below. It is an error to have a varying named "position" that has a
41  * type other than float2.
42  *
43  * The provided attributes and varyings are used to create Attributes and Varyings structs in SkSL
44  * that are used by the shaders. Each attribute from the Attribute span becomes a member of the
45  * SkSL Attributes struct and likewise for the varyings.
46  *
47  * The signature of the vertex program must be:
48  *   Varyings main(const Attributes).
49  *
50  * The signature of the fragment program must be either:
51  *   float2 main(const Varyings)
52  * or
53  *   float2 main(const Varyings, out (half4|float4) color)
54  *
55  * where the return value is the local coordinates that will be used to access SkShader. If the
56  * color variant is used, the returned color will be blended with SkPaint's SkShader (or SkPaint
57  * color in absence of a SkShader) using the SkBlender passed to SkCanvas drawMesh(). To use
58  * interpolated local space positions as the shader coordinates, equivalent to how SkPaths are
59  * shaded, return the position field from the Varying struct as the coordinates.
60  *
61  * The vertex and fragment programs may both contain uniforms. Uniforms with the same name are
62  * assumed to be shared between stages. It is an error to specify uniforms in the vertex and
63  * fragment program with the same name but different types, dimensionality, or layouts.
64  */
65 class SK_API SkMeshSpecification : public SkNVRefCnt<SkMeshSpecification> {
66 public:
67     /** These values are enforced when creating a specification. */
68     static constexpr size_t kMaxStride       = 1024;
69     static constexpr size_t kMaxAttributes   = 8;
70     static constexpr size_t kStrideAlignment = 4;
71     static constexpr size_t kOffsetAlignment = 4;
72     static constexpr size_t kMaxVaryings     = 6;
73 
74     struct Attribute {
75         enum class Type : uint32_t {  // CPU representation     Shader Type
76             kFloat,                   // float                  float
77             kFloat2,                  // two floats             float2
78             kFloat3,                  // three floats           float3
79             kFloat4,                  // four floats            float4
80             kUByte4_unorm,            // four bytes             half4
81 
82             kLast = kUByte4_unorm
83         };
84         Type     type;
85         size_t   offset;
86         SkString name;
87     };
88 
89     struct Varying {
90         enum class Type : uint32_t {
91             kFloat,   // "float"
92             kFloat2,  // "float2"
93             kFloat3,  // "float3"
94             kFloat4,  // "float4"
95             kHalf,    // "half"
96             kHalf2,   // "half2"
97             kHalf3,   // "half3"
98             kHalf4,   // "half4"
99 
100             kLast = kHalf4
101         };
102         Type     type;
103         SkString name;
104     };
105 
106     using Uniform = SkRuntimeEffect::Uniform;
107     using Child = SkRuntimeEffect::Child;
108 
109     ~SkMeshSpecification();
110 
111     struct Result {
112         sk_sp<SkMeshSpecification> specification;
113         SkString                   error;
114     };
115 
116     /**
117      * If successful the return is a specification and an empty error string. Otherwise, it is a
118      * null specification a non-empty error string.
119      *
120      * @param attributes     The vertex attributes that will be consumed by 'vs'. Attributes need
121      *                       not be tightly packed but attribute offsets must be aligned to
122      *                       kOffsetAlignment and offset + size may not be greater than
123      *                       'vertexStride'. At least one attribute is required.
124      * @param vertexStride   The offset between successive attribute values. This must be aligned to
125      *                       kStrideAlignment.
126      * @param varyings       The varyings that will be written by 'vs' and read by 'fs'. This may
127      *                       be empty.
128      * @param vs             The vertex shader code that computes a vertex position and the varyings
129      *                       from the attributes.
130      * @param fs             The fragment code that computes a local coordinate and optionally a
131      *                       color from the varyings. The local coordinate is used to sample
132      *                       SkShader.
133      * @param cs             The colorspace of the color produced by 'fs'. Ignored if 'fs's main()
134      *                       function does not have a color out param.
135      * @param at             The alpha type of the color produced by 'fs'. Ignored if 'fs's main()
136      *                       function does not have a color out param. Cannot be kUnknown.
137      */
138     static Result Make(SkSpan<const Attribute> attributes,
139                        size_t                  vertexStride,
140                        SkSpan<const Varying>   varyings,
141                        const SkString&         vs,
142                        const SkString&         fs);
143     static Result Make(SkSpan<const Attribute> attributes,
144                        size_t                  vertexStride,
145                        SkSpan<const Varying>   varyings,
146                        const SkString&         vs,
147                        const SkString&         fs,
148                        sk_sp<SkColorSpace>     cs);
149     static Result Make(SkSpan<const Attribute> attributes,
150                        size_t                  vertexStride,
151                        SkSpan<const Varying>   varyings,
152                        const SkString&         vs,
153                        const SkString&         fs,
154                        sk_sp<SkColorSpace>     cs,
155                        SkAlphaType             at);
156 
attributes()157     SkSpan<const Attribute> attributes() const { return SkSpan(fAttributes); }
158 
159     /**
160      * Combined size of all 'uniform' variables. When creating a SkMesh with this specification
161      * provide an SkData of this size, containing values for all of those variables. Use uniforms()
162      * to get the offset of each uniform within the SkData.
163      */
164     size_t uniformSize() const;
165 
166     /**
167      * Provides info about individual uniforms including the offset into an SkData where each
168      * uniform value should be placed.
169      */
uniforms()170     SkSpan<const Uniform> uniforms() const { return SkSpan(fUniforms); }
171 
172     /** Provides basic info about individual children: names, indices and runtime effect type. */
children()173     SkSpan<const Child> children() const { return SkSpan(fChildren); }
174 
175     /** Returns a pointer to the named child's description, or nullptr if not found. */
176     const Child* findChild(std::string_view name) const;
177 
178     /** Returns a pointer to the named uniform variable's description, or nullptr if not found. */
179     const Uniform* findUniform(std::string_view name) const;
180 
181     /** Returns a pointer to the named attribute, or nullptr if not found. */
182     const Attribute* findAttribute(std::string_view name) const;
183 
184     /** Returns a pointer to the named varying, or nullptr if not found. */
185     const Varying* findVarying(std::string_view name) const;
186 
stride()187     size_t stride() const { return fStride; }
188 
colorSpace()189     SkColorSpace* colorSpace() const { return fColorSpace.get(); }
190 
191 private:
192     friend struct SkMeshSpecificationPriv;
193 
194     enum class ColorType {
195         kNone,
196         kHalf4,
197         kFloat4,
198     };
199 
200     static Result MakeFromSourceWithStructs(SkSpan<const Attribute> attributes,
201                                             size_t                  stride,
202                                             SkSpan<const Varying>   varyings,
203                                             const SkString&         vs,
204                                             const SkString&         fs,
205                                             sk_sp<SkColorSpace>     cs,
206                                             SkAlphaType             at);
207 
208     SkMeshSpecification(SkSpan<const Attribute>,
209                         size_t,
210                         SkSpan<const Varying>,
211                         int passthroughLocalCoordsVaryingIndex,
212                         uint32_t deadVaryingMask,
213                         std::vector<Uniform> uniforms,
214                         std::vector<Child> children,
215                         std::unique_ptr<const SkSL::Program>,
216                         std::unique_ptr<const SkSL::Program>,
217                         ColorType,
218                         sk_sp<SkColorSpace>,
219                         SkAlphaType);
220 
221     SkMeshSpecification(const SkMeshSpecification&) = delete;
222     SkMeshSpecification(SkMeshSpecification&&) = delete;
223 
224     SkMeshSpecification& operator=(const SkMeshSpecification&) = delete;
225     SkMeshSpecification& operator=(SkMeshSpecification&&) = delete;
226 
227     const std::vector<Attribute>               fAttributes;
228     const std::vector<Varying>                 fVaryings;
229     const std::vector<Uniform>                 fUniforms;
230     const std::vector<Child>                   fChildren;
231     const std::unique_ptr<const SkSL::Program> fVS;
232     const std::unique_ptr<const SkSL::Program> fFS;
233     const size_t                               fStride;
234           uint32_t                             fHash;
235     const int                                  fPassthroughLocalCoordsVaryingIndex;
236     const uint32_t                             fDeadVaryingMask;
237     const ColorType                            fColorType;
238     const sk_sp<SkColorSpace>                  fColorSpace;
239     const SkAlphaType                          fAlphaType;
240 };
241 
242 /**
243  * A vertex buffer, a topology, optionally an index buffer, and a compatible SkMeshSpecification.
244  *
245  * The data in the vertex buffer is expected to contain the attributes described by the spec
246  * for vertexCount vertices, beginning at vertexOffset. vertexOffset must be aligned to the
247  * SkMeshSpecification's vertex stride. The size of the buffer must be at least vertexOffset +
248  * spec->stride()*vertexCount (even if vertex attributes contains pad at the end of the stride). If
249  * the specified bounds do not contain all the points output by the spec's vertex program when
250  * applied to the vertices in the custom mesh, then the result is undefined.
251  *
252  * MakeIndexed may be used to create an indexed mesh. indexCount indices are read from the index
253  * buffer at the specified offset, which must be aligned to 2. The indices are always unsigned
254  * 16-bit integers. The index count must be at least 3.
255  *
256  * If Make() is used, the implicit index sequence is 0, 1, 2, 3, ... and vertexCount must be at
257  * least 3.
258  *
259  * Both Make() and MakeIndexed() take a SkData with the uniform values. See
260  * SkMeshSpecification::uniformSize() and SkMeshSpecification::uniforms() for sizing and packing
261  * uniforms into the SkData.
262  */
263 class SK_API SkMesh {
264 public:
265     class IndexBuffer : public SkRefCnt {
266     public:
267         virtual size_t size() const = 0;
268 
269         /**
270          * Modifies the data in the IndexBuffer by copying size bytes from data into the buffer
271          * at offset. Fails if offset + size > this->size() or if either offset or size is not
272          * aligned to 4 bytes. The GrDirectContext* must match that used to create the buffer. We
273          * take it as a parameter to emphasize that the context must be used to update the data and
274          * thus the context must be valid for the current thread.
275          */
276         bool update(GrDirectContext*, const void* data, size_t offset, size_t size);
277 
278     private:
279         virtual bool onUpdate(GrDirectContext*, const void* data, size_t offset, size_t size) = 0;
280     };
281 
282     class VertexBuffer : public SkRefCnt {
283     public:
284         virtual size_t size() const = 0;
285 
286         /**
287          * Modifies the data in the IndexBuffer by copying size bytes from data into the buffer
288          * at offset. Fails if offset + size > this->size() or if either offset or size is not
289          * aligned to 4 bytes. The GrDirectContext* must match that used to create the buffer. We
290          * take it as a parameter to emphasize that the context must be used to update the data and
291          * thus the context must be valid for the current thread.
292          */
293         bool update(GrDirectContext*, const void* data, size_t offset, size_t size);
294 
295     private:
296         virtual bool onUpdate(GrDirectContext*, const void* data, size_t offset, size_t size) = 0;
297     };
298 
299     SkMesh();
300     ~SkMesh();
301 
302     SkMesh(const SkMesh&);
303     SkMesh(SkMesh&&);
304 
305     SkMesh& operator=(const SkMesh&);
306     SkMesh& operator=(SkMesh&&);
307 
308     enum class Mode { kTriangles, kTriangleStrip };
309 
310     struct Result;
311 
312     using ChildPtr = SkRuntimeEffect::ChildPtr;
313 
314     /**
315      * Creates a non-indexed SkMesh. The returned SkMesh can be tested for validity using
316      * SkMesh::isValid(). An invalid mesh simply fails to draws if passed to SkCanvas::drawMesh().
317      * If the mesh is invalid the returned string give contain the reason for the failure (e.g. the
318      * vertex buffer was null or uniform data too small).
319      */
320     static Result Make(sk_sp<SkMeshSpecification>,
321                        Mode,
322                        sk_sp<VertexBuffer>,
323                        size_t vertexCount,
324                        size_t vertexOffset,
325                        sk_sp<const SkData> uniforms,
326                        SkSpan<ChildPtr> children,
327                        const SkRect& bounds);
328 
329     /**
330      * Creates an indexed SkMesh. The returned SkMesh can be tested for validity using
331      * SkMesh::isValid(). A invalid mesh simply fails to draw if passed to SkCanvas::drawMesh().
332      * If the mesh is invalid the returned string give contain the reason for the failure (e.g. the
333      * index buffer was null or uniform data too small).
334      */
335     static Result MakeIndexed(sk_sp<SkMeshSpecification>,
336                               Mode,
337                               sk_sp<VertexBuffer>,
338                               size_t vertexCount,
339                               size_t vertexOffset,
340                               sk_sp<IndexBuffer>,
341                               size_t indexCount,
342                               size_t indexOffset,
343                               sk_sp<const SkData> uniforms,
344                               SkSpan<ChildPtr> children,
345                               const SkRect& bounds);
346 
refSpec()347     sk_sp<SkMeshSpecification> refSpec() const { return fSpec; }
spec()348     SkMeshSpecification* spec() const { return fSpec.get(); }
349 
mode()350     Mode mode() const { return fMode; }
351 
refVertexBuffer()352     sk_sp<VertexBuffer> refVertexBuffer() const { return fVB; }
vertexBuffer()353     VertexBuffer* vertexBuffer() const { return fVB.get(); }
354 
vertexOffset()355     size_t vertexOffset() const { return fVOffset; }
vertexCount()356     size_t vertexCount()  const { return fVCount;  }
357 
refIndexBuffer()358     sk_sp<IndexBuffer> refIndexBuffer() const { return fIB; }
indexBuffer()359     IndexBuffer* indexBuffer() const { return fIB.get(); }
360 
indexOffset()361     size_t indexOffset() const { return fIOffset; }
indexCount()362     size_t indexCount()  const { return fICount;  }
363 
refUniforms()364     sk_sp<const SkData> refUniforms() const { return fUniforms; }
uniforms()365     const SkData* uniforms() const { return fUniforms.get(); }
366 
children()367     SkSpan<const ChildPtr> children() const { return SkSpan(fChildren); }
368 
bounds()369     SkRect bounds() const { return fBounds; }
370 
371     bool isValid() const;
372 
373 private:
374     std::tuple<bool, SkString> validate() const;
375 
376     sk_sp<SkMeshSpecification> fSpec;
377 
378     sk_sp<VertexBuffer> fVB;
379     sk_sp<IndexBuffer>  fIB;
380 
381     sk_sp<const SkData> fUniforms;
382     skia_private::STArray<2, ChildPtr> fChildren;
383 
384     size_t fVOffset = 0;  // Must be a multiple of spec->stride()
385     size_t fVCount  = 0;
386 
387     size_t fIOffset = 0;  // Must be a multiple of sizeof(uint16_t)
388     size_t fICount  = 0;
389 
390     Mode fMode = Mode::kTriangles;
391 
392     SkRect fBounds = SkRect::MakeEmpty();
393 };
394 
395 struct SkMesh::Result { SkMesh mesh; SkString error; };
396 
397 namespace SkMeshes {
398 /**
399  * Makes a CPU-backed index buffer to be used with SkMeshes.
400  *
401  * @param  data              The data used to populate the buffer, or nullptr to create a zero-
402  *                           initialized buffer.
403  * @param  size              Both the size of the data in 'data' and the size of the resulting
404  *                           buffer, in bytes.
405  */
406 SK_API sk_sp<SkMesh::IndexBuffer> MakeIndexBuffer(const void* data, size_t size);
407 
408 /**
409  * Makes a copy of an index buffer. The copy will be CPU-backed.
410  */
411 SK_API sk_sp<SkMesh::IndexBuffer> CopyIndexBuffer(const sk_sp<SkMesh::IndexBuffer>&);
412 
413 /**
414  * Makes a CPU-backed vertex buffer to be used with SkMeshes.
415  *
416  * @param  data              The data used to populate the buffer, or nullptr to create a zero-
417  *                           initialized buffer.
418  * @param  size              Both the size of the data in 'data' and the size of the resulting
419  *                           buffer, in bytes.
420  */
421 SK_API sk_sp<SkMesh::VertexBuffer> MakeVertexBuffer(const void*, size_t size);
422 
423 /**
424  * Makes a copy of a vertex buffer.  The copy will be CPU-backed.
425  */
426 SK_API sk_sp<SkMesh::VertexBuffer> CopyVertexBuffer(const sk_sp<SkMesh::VertexBuffer>&);
427 }  // namespace SkMeshes
428 
429 #endif
430