1 /*
2  * Copyright 2016 Google Inc.
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 SKSL_LAYOUT
9 #define SKSL_LAYOUT
10 
11 #include "include/private/SkSLString.h"
12 
13 namespace SkSL {
14 
15 /**
16  * Represents a layout block appearing before a variable declaration, as in:
17  *
18  * layout (location = 0) int x;
19  */
20 struct Layout {
21     enum Flag {
22         kOriginUpperLeft_Flag            = 1 <<  0,
23         kOverrideCoverage_Flag           = 1 <<  1,
24         kPushConstant_Flag               = 1 <<  2,
25         kBlendSupportAllEquations_Flag   = 1 <<  3,
26         kTracked_Flag                    = 1 <<  4,
27         kSRGBUnpremul_Flag               = 1 <<  5,
28         kKey_Flag                        = 1 <<  6,
29 
30         // These flags indicate if the qualifier appeared, regardless of the accompanying value.
31         kLocation_Flag                   = 1 <<  7,
32         kOffset_Flag                     = 1 <<  8,
33         kBinding_Flag                    = 1 <<  9,
34         kIndex_Flag                      = 1 << 10,
35         kSet_Flag                        = 1 << 11,
36         kBuiltin_Flag                    = 1 << 12,
37         kInputAttachmentIndex_Flag       = 1 << 13,
38         kPrimitive_Flag                  = 1 << 14,
39         kMaxVertices_Flag                = 1 << 15,
40         kInvocations_Flag                = 1 << 16,
41         kWhen_Flag                       = 1 << 17,
42         kCType_Flag                      = 1 << 18,
43     };
44 
45     enum Primitive {
46         kUnspecified_Primitive = -1,
47         kPoints_Primitive,
48         kLines_Primitive,
49         kLineStrip_Primitive,
50         kLinesAdjacency_Primitive,
51         kTriangles_Primitive,
52         kTriangleStrip_Primitive,
53         kTrianglesAdjacency_Primitive
54     };
55 
56     enum class CType {
57         kDefault,
58         kBool,
59         kFloat,
60         kFloat2,
61         kFloat3,
62         kFloat4,
63         kInt32,
64         kSkRect,
65         kSkIRect,
66         kSkPMColor4f,
67         kSkPMColor,
68         kSkV4,
69         kSkPoint,
70         kSkIPoint,
71         kSkMatrix,
72         kSkM44,
73         kGrSurfaceProxyView,
74         kGrFragmentProcessor,
75     };
76 
CTypeToStrLayout77     static const char* CTypeToStr(CType ctype) {
78         switch (ctype) {
79             case CType::kDefault:
80                 return nullptr;
81             case CType::kFloat:
82                 return "float";
83             case CType::kInt32:
84                 return "int32_t";
85             case CType::kSkRect:
86                 return "SkRect";
87             case CType::kSkIRect:
88                 return "SkIRect";
89             case CType::kSkPMColor4f:
90                 return "SkPMColor4f";
91             case CType::kSkPMColor:
92                 return "SkPMColor";
93             case CType::kSkV4:
94                 return "SkV4";
95             case CType::kSkPoint:
96                 return "SkPoint";
97             case CType::kSkIPoint:
98                 return "SkIPoint";
99             case CType::kSkMatrix:
100                 return "SkMatrix";
101             case CType::kSkM44:
102                 return "SkM44";
103             case CType::kGrSurfaceProxyView:
104                 return "GrSurfaceProxyView";
105             case CType::kGrFragmentProcessor:
106                 return "std::unique_ptr<GrFragmentProcessor>";
107             default:
108                 SkASSERT(false);
109                 return nullptr;
110         }
111     }
112 
LayoutLayout113     Layout(int flags, int location, int offset, int binding, int index, int set, int builtin,
114            int inputAttachmentIndex, Primitive primitive, int maxVertices, int invocations,
115            StringFragment when, CType ctype)
116     : fFlags(flags)
117     , fLocation(location)
118     , fOffset(offset)
119     , fBinding(binding)
120     , fIndex(index)
121     , fSet(set)
122     , fBuiltin(builtin)
123     , fInputAttachmentIndex(inputAttachmentIndex)
124     , fPrimitive(primitive)
125     , fMaxVertices(maxVertices)
126     , fInvocations(invocations)
127     , fWhen(when)
128     , fCType(ctype) {}
129 
LayoutLayout130     Layout()
131     : fFlags(0)
132     , fLocation(-1)
133     , fOffset(-1)
134     , fBinding(-1)
135     , fIndex(-1)
136     , fSet(-1)
137     , fBuiltin(-1)
138     , fInputAttachmentIndex(-1)
139     , fPrimitive(kUnspecified_Primitive)
140     , fMaxVertices(-1)
141     , fInvocations(-1)
142     , fCType(CType::kDefault) {}
143 
builtinLayout144     static Layout builtin(int builtin) {
145         Layout result;
146         result.fBuiltin = builtin;
147         return result;
148     }
149 
descriptionLayout150     String description() const {
151         String result;
152         auto separator = [firstSeparator = true]() mutable -> String {
153             if (firstSeparator) {
154                 firstSeparator = false;
155                 return "";
156             } else {
157                 return ", ";
158             }};
159         if (fLocation >= 0) {
160             result += separator() + "location = " + to_string(fLocation);
161         }
162         if (fOffset >= 0) {
163             result += separator() + "offset = " + to_string(fOffset);
164         }
165         if (fBinding >= 0) {
166             result += separator() + "binding = " + to_string(fBinding);
167         }
168         if (fIndex >= 0) {
169             result += separator() + "index = " + to_string(fIndex);
170         }
171         if (fSet >= 0) {
172             result += separator() + "set = " + to_string(fSet);
173         }
174         if (fBuiltin >= 0) {
175             result += separator() + "builtin = " + to_string(fBuiltin);
176         }
177         if (fInputAttachmentIndex >= 0) {
178             result += separator() + "input_attachment_index = " + to_string(fInputAttachmentIndex);
179         }
180         if (fFlags & kOriginUpperLeft_Flag) {
181             result += separator() + "origin_upper_left";
182         }
183         if (fFlags & kOverrideCoverage_Flag) {
184             result += separator() + "override_coverage";
185         }
186         if (fFlags & kBlendSupportAllEquations_Flag) {
187             result += separator() + "blend_support_all_equations";
188         }
189         if (fFlags & kPushConstant_Flag) {
190             result += separator() + "push_constant";
191         }
192         if (fFlags & kTracked_Flag) {
193             result += separator() + "tracked";
194         }
195         if (fFlags & kSRGBUnpremul_Flag) {
196             result += separator() + "srgb_unpremul";
197         }
198         switch (fPrimitive) {
199             case kPoints_Primitive:
200                 result += separator() + "points";
201                 break;
202             case kLines_Primitive:
203                 result += separator() + "lines";
204                 break;
205             case kLineStrip_Primitive:
206                 result += separator() + "line_strip";
207                 break;
208             case kLinesAdjacency_Primitive:
209                 result += separator() + "lines_adjacency";
210                 break;
211             case kTriangles_Primitive:
212                 result += separator() + "triangles";
213                 break;
214             case kTriangleStrip_Primitive:
215                 result += separator() + "triangle_strip";
216                 break;
217             case kTrianglesAdjacency_Primitive:
218                 result += separator() + "triangles_adjacency";
219                 break;
220             case kUnspecified_Primitive:
221                 break;
222         }
223         if (fMaxVertices >= 0) {
224             result += separator() + "max_vertices = " + to_string(fMaxVertices);
225         }
226         if (fInvocations >= 0) {
227             result += separator() + "invocations = " + to_string(fInvocations);
228         }
229         if (fWhen.fLength) {
230             result += separator() + "when = " + fWhen;
231         }
232         if (result.size() > 0) {
233             result = "layout (" + result + ")";
234         }
235         if (fFlags & kKey_Flag) {
236             result += "/* key */ const";
237         }
238         return result;
239     }
240 
241     bool operator==(const Layout& other) const {
242         return fFlags                == other.fFlags &&
243                fLocation             == other.fLocation &&
244                fOffset               == other.fOffset &&
245                fBinding              == other.fBinding &&
246                fIndex                == other.fIndex &&
247                fSet                  == other.fSet &&
248                fBuiltin              == other.fBuiltin &&
249                fInputAttachmentIndex == other.fInputAttachmentIndex &&
250                fPrimitive            == other.fPrimitive &&
251                fMaxVertices          == other.fMaxVertices &&
252                fInvocations          == other.fInvocations &&
253                fWhen                 == other.fWhen &&
254                fCType                == other.fCType;
255     }
256 
257     bool operator!=(const Layout& other) const {
258         return !(*this == other);
259     }
260 
261     int fFlags;
262     int fLocation;
263     int fOffset;
264     int fBinding;
265     int fIndex;
266     int fSet;
267     // builtin comes from SPIR-V and identifies which particular builtin value this object
268     // represents.
269     int fBuiltin;
270     // input_attachment_index comes from Vulkan/SPIR-V to connect a shader variable to the a
271     // corresponding attachment on the subpass in which the shader is being used.
272     int fInputAttachmentIndex;
273     Primitive fPrimitive;
274     int fMaxVertices;
275     int fInvocations;
276     StringFragment fWhen;
277     CType fCType;
278 };
279 
280 }  // namespace SkSL
281 
282 #endif
283