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 "src/sksl/SkSLString.h"
12#include "src/sksl/SkSLUtil.h"
13
14namespace SkSL {
15
16/**
17 * Represents a layout block appearing before a variable declaration, as in:
18 *
19 * layout (location = 0) int x;
20 */
21struct Layout {
22 enum Flag {
23 kOriginUpperLeft_Flag = 1 << 0,
24 kOverrideCoverage_Flag = 1 << 1,
25 kPushConstant_Flag = 1 << 2,
26 kBlendSupportAllEquations_Flag = 1 << 3,
27 kBlendSupportMultiply_Flag = 1 << 4,
28 kBlendSupportScreen_Flag = 1 << 5,
29 kBlendSupportOverlay_Flag = 1 << 6,
30 kBlendSupportDarken_Flag = 1 << 7,
31 kBlendSupportLighten_Flag = 1 << 8,
32 kBlendSupportColorDodge_Flag = 1 << 9,
33 kBlendSupportColorBurn_Flag = 1 << 10,
34 kBlendSupportHardLight_Flag = 1 << 11,
35 kBlendSupportSoftLight_Flag = 1 << 12,
36 kBlendSupportDifference_Flag = 1 << 13,
37 kBlendSupportExclusion_Flag = 1 << 14,
38 kBlendSupportHSLHue_Flag = 1 << 15,
39 kBlendSupportHSLSaturation_Flag = 1 << 16,
40 kBlendSupportHSLColor_Flag = 1 << 17,
41 kBlendSupportHSLLuminosity_Flag = 1 << 18,
42 kTracked_Flag = 1 << 19,
43 kSRGBUnpremul_Flag = 1 << 20,
44 };
45
46 enum Primitive {
47 kUnspecified_Primitive = -1,
48 kPoints_Primitive,
49 kLines_Primitive,
50 kLineStrip_Primitive,
51 kLinesAdjacency_Primitive,
52 kTriangles_Primitive,
53 kTriangleStrip_Primitive,
54 kTrianglesAdjacency_Primitive
55 };
56
57 // These are used by images in GLSL. We only support a subset of what GL supports.
58 enum class Format {
59 kUnspecified = -1,
60 kRGBA32F,
61 kR32F,
62 kRGBA16F,
63 kR16F,
64 kLUMINANCE16F,
65 kRGBA8,
66 kR8,
67 kRGBA8I,
68 kR8I,
69 kRG16F,
70 };
71
72 // used by SkSL processors
73 enum Key {
74 // field is not a key
75 kNo_Key,
76 // field is a key
77 kKey_Key,
78 // key is 0 or 1 depending on whether the matrix is an identity matrix
79 kIdentity_Key,
80 };
81
82 enum class CType {
83 kDefault,
84 kBool,
85 kFloat,
86 kFloat2,
87 kFloat3,
88 kFloat4,
89 kInt32,
90 kSkRect,
91 kSkIRect,
92 kSkPMColor4f,
93 kSkPMColor,
94 kSkV4,
95 kSkPoint,
96 kSkIPoint,
97 kSkMatrix,
98 kSkM44,
99 kGrSurfaceProxyView,
100 kGrFragmentProcessor,
101 };
102
103 static const char* FormatToStr(Format format) {
104 switch (format) {
105 case Format::kUnspecified: return "";
106 case Format::kRGBA32F: return "rgba32f";
107 case Format::kR32F: return "r32f";
108 case Format::kRGBA16F: return "rgba16f";
109 case Format::kR16F: return "r16f";
110 case Format::kLUMINANCE16F: return "lum16f";
111 case Format::kRGBA8: return "rgba8";
112 case Format::kR8: return "r8";
113 case Format::kRGBA8I: return "rgba8i";
114 case Format::kR8I: return "r8i";
115 case Format::kRG16F: return "rg16f";
116 }
117 ABORT("Unexpected format");
118 }
119
120 static bool ReadFormat(String str, Format* format) {
121 if (str == "rgba32f") {
122 *format = Format::kRGBA32F;
123 return true;
124 } else if (str == "r32f") {
125 *format = Format::kR32F;
126 return true;
127 } else if (str == "rgba16f") {
128 *format = Format::kRGBA16F;
129 return true;
130 } else if (str == "r16f") {
131 *format = Format::kR16F;
132 return true;
133 } else if (str == "lum16f") {
134 *format = Format::kLUMINANCE16F;
135 return true;
136 } else if (str == "rgba8") {
137 *format = Format::kRGBA8;
138 return true;
139 } else if (str == "r8") {
140 *format = Format::kR8;
141 return true;
142 } else if (str == "rgba8i") {
143 *format = Format::kRGBA8I;
144 return true;
145 } else if (str == "r8i") {
146 *format = Format::kR8I;
147 return true;
148 } else if (str == "rg16f") {
149 *format = Format::kRG16F;
150 return true;
151 }
152 return false;
153 }
154
155 static const char* CTypeToStr(CType ctype) {
156 switch (ctype) {
157 case CType::kDefault:
158 return nullptr;
159 case CType::kFloat:
160 return "float";
161 case CType::kInt32:
162 return "int32_t";
163 case CType::kSkRect:
164 return "SkRect";
165 case CType::kSkIRect:
166 return "SkIRect";
167 case CType::kSkPMColor4f:
168 return "SkPMColor4f";
169 case CType::kSkPMColor:
170 return "SkPMColor";
171 case CType::kSkV4:
172 return "SkV4";
173 case CType::kSkPoint:
174 return "SkPoint";
175 case CType::kSkIPoint:
176 return "SkIPoint";
177 case CType::kSkMatrix:
178 return "SkMatrix";
179 case CType::kSkM44:
180 return "SkM44";
181 case CType::kGrSurfaceProxyView:
182 return "GrSurfaceProxyView";
183 case CType::kGrFragmentProcessor:
184 return "std::unique_ptr<GrFragmentProcessor>";
185 default:
186 SkASSERT(false);
187 return nullptr;
188 }
189 }
190
191 Layout(int flags, int location, int offset, int binding, int index, int set, int builtin,
192 int inputAttachmentIndex, Format format, Primitive primitive, int maxVertices,
193 int invocations, StringFragment marker, StringFragment when, Key key, CType ctype)
194 : fFlags(flags)
195 , fLocation(location)
196 , fOffset(offset)
197 , fBinding(binding)
198 , fIndex(index)
199 , fSet(set)
200 , fBuiltin(builtin)
201 , fInputAttachmentIndex(inputAttachmentIndex)
202 , fFormat(format)
203 , fPrimitive(primitive)
204 , fMaxVertices(maxVertices)
205 , fInvocations(invocations)
206 , fMarker(marker)
207 , fWhen(when)
208 , fKey(key)
209 , fCType(ctype) {}
210
211 Layout()
212 : fFlags(0)
213 , fLocation(-1)
214 , fOffset(-1)
215 , fBinding(-1)
216 , fIndex(-1)
217 , fSet(-1)
218 , fBuiltin(-1)
219 , fInputAttachmentIndex(-1)
220 , fFormat(Format::kUnspecified)
221 , fPrimitive(kUnspecified_Primitive)
222 , fMaxVertices(-1)
223 , fInvocations(-1)
224 , fKey(kNo_Key)
225 , fCType(CType::kDefault) {}
226
227 static Layout builtin(int builtin) {
228 Layout result;
229 result.fBuiltin = builtin;
230 return result;
231 }
232
233 String description() const {
234 String result;
235 auto separator = [firstSeparator = true]() mutable -> String {
236 if (firstSeparator) {
237 firstSeparator = false;
238 return "";
239 } else {
240 return ", ";
241 }};
242 if (fLocation >= 0) {
243 result += separator() + "location = " + to_string(fLocation);
244 }
245 if (fOffset >= 0) {
246 result += separator() + "offset = " + to_string(fOffset);
247 }
248 if (fBinding >= 0) {
249 result += separator() + "binding = " + to_string(fBinding);
250 }
251 if (fIndex >= 0) {
252 result += separator() + "index = " + to_string(fIndex);
253 }
254 if (fSet >= 0) {
255 result += separator() + "set = " + to_string(fSet);
256 }
257 if (fBuiltin >= 0) {
258 result += separator() + "builtin = " + to_string(fBuiltin);
259 }
260 if (fInputAttachmentIndex >= 0) {
261 result += separator() + "input_attachment_index = " + to_string(fInputAttachmentIndex);
262 }
263 if (Format::kUnspecified != fFormat) {
264 result += separator() + FormatToStr(fFormat);
265 }
266 if (fFlags & kOriginUpperLeft_Flag) {
267 result += separator() + "origin_upper_left";
268 }
269 if (fFlags & kOverrideCoverage_Flag) {
270 result += separator() + "override_coverage";
271 }
272 if (fFlags & kBlendSupportAllEquations_Flag) {
273 result += separator() + "blend_support_all_equations";
274 }
275 if (fFlags & kBlendSupportMultiply_Flag) {
276 result += separator() + "blend_support_multiply";
277 }
278 if (fFlags & kBlendSupportScreen_Flag) {
279 result += separator() + "blend_support_screen";
280 }
281 if (fFlags & kBlendSupportOverlay_Flag) {
282 result += separator() + "blend_support_overlay";
283 }
284 if (fFlags & kBlendSupportDarken_Flag) {
285 result += separator() + "blend_support_darken";
286 }
287 if (fFlags & kBlendSupportLighten_Flag) {
288 result += separator() + "blend_support_lighten";
289 }
290 if (fFlags & kBlendSupportColorDodge_Flag) {
291 result += separator() + "blend_support_colordodge";
292 }
293 if (fFlags & kBlendSupportColorBurn_Flag) {
294 result += separator() + "blend_support_colorburn";
295 }
296 if (fFlags & kBlendSupportHardLight_Flag) {
297 result += separator() + "blend_support_hardlight";
298 }
299 if (fFlags & kBlendSupportSoftLight_Flag) {
300 result += separator() + "blend_support_softlight";
301 }
302 if (fFlags & kBlendSupportDifference_Flag) {
303 result += separator() + "blend_support_difference";
304 }
305 if (fFlags & kBlendSupportExclusion_Flag) {
306 result += separator() + "blend_support_exclusion";
307 }
308 if (fFlags & kBlendSupportHSLHue_Flag) {
309 result += separator() + "blend_support_hsl_hue";
310 }
311 if (fFlags & kBlendSupportHSLSaturation_Flag) {
312 result += separator() + "blend_support_hsl_saturation";
313 }
314 if (fFlags & kBlendSupportHSLColor_Flag) {
315 result += separator() + "blend_support_hsl_color";
316 }
317 if (fFlags & kBlendSupportHSLLuminosity_Flag) {
318 result += separator() + "blend_support_hsl_luminosity";
319 }
320 if (fFlags & kPushConstant_Flag) {
321 result += separator() + "push_constant";
322 }
323 if (fFlags & kTracked_Flag) {
324 result += separator() + "tracked";
325 }
326 if (fFlags & kSRGBUnpremul_Flag) {
327 result += separator() + "srgb_unpremul";
328 }
329 switch (fPrimitive) {
330 case kPoints_Primitive:
331 result += separator() + "points";
332 break;
333 case kLines_Primitive:
334 result += separator() + "lines";
335 break;
336 case kLineStrip_Primitive:
337 result += separator() + "line_strip";
338 break;
339 case kLinesAdjacency_Primitive:
340 result += separator() + "lines_adjacency";
341 break;
342 case kTriangles_Primitive:
343 result += separator() + "triangles";
344 break;
345 case kTriangleStrip_Primitive:
346 result += separator() + "triangle_strip";
347 break;
348 case kTrianglesAdjacency_Primitive:
349 result += separator() + "triangles_adjacency";
350 break;
351 case kUnspecified_Primitive:
352 break;
353 }
354 if (fMaxVertices >= 0) {
355 result += separator() + "max_vertices = " + to_string(fMaxVertices);
356 }
357 if (fInvocations >= 0) {
358 result += separator() + "invocations = " + to_string(fInvocations);
359 }
360 if (fMarker.fLength) {
361 result += separator() + "marker = " + fMarker;
362 }
363 if (fWhen.fLength) {
364 result += separator() + "when = " + fWhen;
365 }
366 if (result.size() > 0) {
367 result = "layout (" + result + ")";
368 }
369 if (fKey) {
370 result += "/* key */";
371 }
372 return result;
373 }
374
375 bool operator==(const Layout& other) const {
376 return fFlags == other.fFlags &&
377 fLocation == other.fLocation &&
378 fOffset == other.fOffset &&
379 fBinding == other.fBinding &&
380 fIndex == other.fIndex &&
381 fSet == other.fSet &&
382 fBuiltin == other.fBuiltin &&
383 fInputAttachmentIndex == other.fInputAttachmentIndex &&
384 fFormat == other.fFormat &&
385 fPrimitive == other.fPrimitive &&
386 fMaxVertices == other.fMaxVertices &&
387 fInvocations == other.fInvocations &&
388 fMarker == other.fMarker &&
389 fWhen == other.fWhen &&
390 fKey == other.fKey &&
391 fCType == other.fCType;
392 }
393
394 bool operator!=(const Layout& other) const {
395 return !(*this == other);
396 }
397
398 int fFlags;
399 int fLocation;
400 int fOffset;
401 int fBinding;
402 int fIndex;
403 int fSet;
404 // builtin comes from SPIR-V and identifies which particular builtin value this object
405 // represents.
406 int fBuiltin;
407 // input_attachment_index comes from Vulkan/SPIR-V to connect a shader variable to the a
408 // corresponding attachment on the subpass in which the shader is being used.
409 int fInputAttachmentIndex;
410 Format fFormat;
411 Primitive fPrimitive;
412 int fMaxVertices;
413 int fInvocations;
414 // marker refers to matrices tagged on the SkCanvas with markCTM
415 StringFragment fMarker;
416 StringFragment fWhen;
417 Key fKey;
418 CType fCType;
419};
420
421} // namespace SkSL
422
423#endif
424