• 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 SkCustomMesh_DEFINED
9 #define SkCustomMesh_DEFINED
10 
11 #include "include/core/SkTypes.h"
12 
13 #ifdef SK_ENABLE_SKSL
14 #include "include/core/SkColorSpace.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkRect.h"
17 #include "include/core/SkRefCnt.h"
18 #include "include/core/SkSpan.h"
19 #include "include/core/SkString.h"
20 
21 #include <vector>
22 
23 namespace SkSL { struct Program; }
24 
25 /**
26  * A specification for custom meshes. Specifies the vertex buffer attributes and stride, the
27  * vertex program that produces a user-defined set of varyings, a fragment program that ingests
28  * the interpolated varyings and produces local coordinates and optionally a color.
29  *
30  * The signature of the vertex program must be:
31  *   float2 main(Attributes, out Varyings)
32  * where the return value is a local position that will be transformed by SkCanvas's matrix.
33  *
34  * The signature of the fragment program must be either:
35  *   (float2|void) main(Varyings)
36  * or
37  *   (float2|void) main(Varyings, out (half4|float4) color)
38  *
39  * where the return value is the local coordinates that will be used to access SkShader. If the
40  * return type is void then the interpolated position from vertex shader return is used as the local
41  * coordinate. If the color variant is used it will be blended with SkShader (or SkPaint color in
42  * absence of a shader) using the SkBlender provided to the SkCanvas draw call.
43  */
44 class SkCustomMeshSpecification : public SkNVRefCnt<SkCustomMeshSpecification> {
45 public:
46     /** These values are enforced when creating a specification. */
47     static constexpr size_t kMaxStride       = 1024;
48     static constexpr size_t kMaxAttributes   = 8;
49     static constexpr size_t kStrideAlignment = 4;
50     static constexpr size_t kOffsetAlignment = 4;
51     static constexpr size_t kMaxVaryings     = 6;
52 
53     struct Attribute {
54         enum class Type : uint32_t {  // CPU representation     Shader Type
55             kFloat,                   // float                  float
56             kFloat2,                  // two floats             float2
57             kFloat3,                  // three floats           float3
58             kFloat4,                  // four floats            float4
59             kUByte4_unorm,            // four bytes             half4
60 
61             kLast = kUByte4_unorm
62         };
63         Type     type;
64         size_t   offset;
65         SkString name;
66     };
67 
68     struct Varying {
69         enum class Type : uint32_t {
70             kFloat,   // "float"
71             kFloat2,  // "float2"
72             kFloat3,  // "float3"
73             kFloat4,  // "float4"
74             kHalf,    // "half"
75             kHalf2,   // "half2"
76             kHalf3,   // "half3"
77             kHalf4,   // "half4"
78 
79             kLast = kHalf4
80         };
81         Type     type;
82         SkString name;
83     };
84 
85     ~SkCustomMeshSpecification();
86 
87     struct Result {
88         sk_sp<SkCustomMeshSpecification> specification;
89         SkString                         error;
90     };
91 
92     /**
93      * If successful the return is a specification and an empty error string. Otherwise, it is a
94      * null specification a non-empty error string.
95      *
96      * @param attributes     The vertex attributes that will be consumed by 'vs'. Attributes need
97      *                       not be tightly packed but attribute offsets must be aligned to
98      *                       kOffsetAlignment and offset + size may not be greater than
99      *                       'vertexStride'. At least one attribute is required.
100      * @param vertexStride   The offset between successive attribute values. This must be aligned to
101      *                       kStrideAlignment.
102      * @param varyings       The varyings that will be written by 'vs' and read by 'fs'. This may
103      *                       be empty.
104      * @param vs             The vertex shader code that computes a vertex position and the varyings
105      *                       from the attributes.
106      * @param fs             The fragment code that computes a local coordinate and optionally a
107      *                       color from the varyings. The local coordinate is used to sample
108      *                       SkShader.
109      * @param cs             The colorspace of the color produced by 'fs'. Ignored if 'fs's main()
110      *                       function does not have a color out param.
111      * @param at             The alpha type of the color produced by 'fs'. Ignored if 'fs's main()
112      *                       function does not have a color out param. Cannot be kUnknown.
113      */
114     static Result Make(SkSpan<const Attribute> attributes,
115                        size_t                  vertexStride,
116                        SkSpan<const Varying>   varyings,
117                        const SkString&         vs,
118                        const SkString&         fs,
119                        sk_sp<SkColorSpace>     cs = SkColorSpace::MakeSRGB(),
120                        SkAlphaType             at = kPremul_SkAlphaType);
121 
attributes()122     SkSpan<const Attribute> attributes() const { return SkMakeSpan(fAttributes); }
123 
stride()124     size_t stride() const { return fStride; }
125 
126 private:
127     friend struct SkCustomMeshSpecificationPriv;
128 
129     enum class ColorType {
130         kNone,
131         kHalf4,
132         kFloat4,
133     };
134 
135     static Result MakeFromSourceWithStructs(SkSpan<const Attribute> attributes,
136                                             size_t                  stride,
137                                             SkSpan<const Varying>   varyings,
138                                             const SkString&         vs,
139                                             const SkString&         fs,
140                                             sk_sp<SkColorSpace>     cs,
141                                             SkAlphaType             at);
142 
143     SkCustomMeshSpecification(SkSpan<const Attribute>,
144                               size_t,
145                               SkSpan<const Varying>,
146                               std::unique_ptr<SkSL::Program>,
147                               std::unique_ptr<SkSL::Program>,
148                               ColorType,
149                               bool hasLocalCoords,
150                               sk_sp<SkColorSpace>,
151                               SkAlphaType);
152 
153     SkCustomMeshSpecification(const SkCustomMeshSpecification&) = delete;
154     SkCustomMeshSpecification(SkCustomMeshSpecification&&) = delete;
155 
156     SkCustomMeshSpecification& operator=(const SkCustomMeshSpecification&) = delete;
157     SkCustomMeshSpecification& operator=(SkCustomMeshSpecification&&) = delete;
158 
159     const std::vector<Attribute>       fAttributes;
160     const std::vector<Varying>         fVaryings;
161     std::unique_ptr<SkSL::Program>     fVS;
162     std::unique_ptr<SkSL::Program>     fFS;
163     size_t                             fStride;
164     uint32_t                           fHash;
165     ColorType                          fColorType;
166     bool                               fHasLocalCoords;
167     sk_sp<SkColorSpace>                fColorSpace;
168     SkAlphaType                        fAlphaType;
169 };
170 
171 /**
172  * This is a placeholder object. We will want something that allows the client to incrementally
173  * update the mesh that can be synchronized with the GPU backend without requiring extra copies.
174  *
175  * A buffer of vertices, a topology, optionally indices, and a compatible SkCustomMeshSpecification.
176  * The data in 'vb' is expected to contain the attributes described in 'spec' for 'vcount' vertices.
177  * The size of the buffer must be at least spec->stride()*vcount (even if vertex attributes contains
178  * pad at the end of the stride). If 'bounds' does not contain all points output by 'spec''s vertex
179  * program when applied to the vertices in 'vb' a draw of the custom mesh produces undefined
180  * results.
181  *
182  * If indices is null then then 'icount' must be <= 0. 'vcount' vertices will be selected from 'vb'
183  * to create the topology indicated by 'mode'.
184  *
185  * If indices is not null then icount must be >= 3. 'vb' will be indexed by 'icount' successive
186  * values in 'indices' to create the topology indicated by 'mode'. The values in 'indices' must be
187  * less than 'vcount'
188  */
189 struct SkCustomMesh {
190     enum class Mode { kTriangles, kTriangleStrip };
191     sk_sp<SkCustomMeshSpecification>  spec;
192     Mode                              mode     = Mode::kTriangles;
193     SkRect                            bounds   = SkRect::MakeEmpty();
194     const void*                       vb       = nullptr;
195     int                               vcount   = 0;
196     const uint16_t*                   indices  = nullptr;
197     int                               icount   = 0;
198 };
199 
200 #endif  // SK_ENABLE_SKSL
201 
202 #endif
203