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 "SkSLString.h"
12#include "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    };
43
44    enum Primitive {
45        kUnspecified_Primitive = -1,
46        kPoints_Primitive,
47        kLines_Primitive,
48        kLineStrip_Primitive,
49        kLinesAdjacency_Primitive,
50        kTriangles_Primitive,
51        kTriangleStrip_Primitive,
52        kTrianglesAdjacency_Primitive
53    };
54
55    // These are used by images in GLSL. We only support a subset of what GL supports.
56    enum class Format {
57        kUnspecified = -1,
58        kRGBA32F,
59        kR32F,
60        kRGBA16F,
61        kR16F,
62        kRGBA8,
63        kR8,
64        kRGBA8I,
65        kR8I,
66    };
67
68    // used by SkSL processors
69    enum Key {
70        // field is not a key
71        kNo_Key,
72        // field is a key
73        kKey_Key,
74        // key is 0 or 1 depending on whether the matrix is an identity matrix
75        kIdentity_Key,
76    };
77
78    static const char* FormatToStr(Format format) {
79        switch (format) {
80            case Format::kUnspecified:  return "";
81            case Format::kRGBA32F:      return "rgba32f";
82            case Format::kR32F:         return "r32f";
83            case Format::kRGBA16F:      return "rgba16f";
84            case Format::kR16F:         return "r16f";
85            case Format::kRGBA8:        return "rgba8";
86            case Format::kR8:           return "r8";
87            case Format::kRGBA8I:       return "rgba8i";
88            case Format::kR8I:          return "r8i";
89        }
90        ABORT("Unexpected format");
91    }
92
93    static bool ReadFormat(String str, Format* format) {
94        if (str == "rgba32f") {
95            *format = Format::kRGBA32F;
96            return true;
97        } else if (str == "r32f") {
98            *format = Format::kR32F;
99            return true;
100        } else if (str == "rgba16f") {
101            *format = Format::kRGBA16F;
102            return true;
103        } else if (str == "r16f") {
104            *format = Format::kR16F;
105            return true;
106        } else if (str == "rgba8") {
107            *format = Format::kRGBA8;
108            return true;
109        } else if (str == "r8") {
110            *format = Format::kR8;
111            return true;
112        } else if (str == "rgba8i") {
113            *format = Format::kRGBA8I;
114            return true;
115        } else if (str == "r8i") {
116            *format = Format::kR8I;
117            return true;
118        }
119        return false;
120    }
121
122    Layout(int flags, int location, int offset, int binding, int index, int set, int builtin,
123           int inputAttachmentIndex, Format format, Primitive primitive, int maxVertices,
124           int invocations, String when, Key key, StringFragment ctype)
125    : fFlags(flags)
126    , fLocation(location)
127    , fOffset(offset)
128    , fBinding(binding)
129    , fIndex(index)
130    , fSet(set)
131    , fBuiltin(builtin)
132    , fInputAttachmentIndex(inputAttachmentIndex)
133    , fFormat(format)
134    , fPrimitive(primitive)
135    , fMaxVertices(maxVertices)
136    , fInvocations(invocations)
137    , fWhen(when)
138    , fKey(key)
139    , fCType(ctype) {}
140
141    Layout()
142    : fFlags(0)
143    , fLocation(-1)
144    , fOffset(-1)
145    , fBinding(-1)
146    , fIndex(-1)
147    , fSet(-1)
148    , fBuiltin(-1)
149    , fInputAttachmentIndex(-1)
150    , fFormat(Format::kUnspecified)
151    , fPrimitive(kUnspecified_Primitive)
152    , fMaxVertices(-1)
153    , fInvocations(-1)
154    , fKey(kNo_Key) {}
155
156    String description() const {
157        String result;
158        String separator;
159        if (fLocation >= 0) {
160            result += separator + "location = " + to_string(fLocation);
161            separator = ", ";
162        }
163        if (fOffset >= 0) {
164            result += separator + "offset = " + to_string(fOffset);
165            separator = ", ";
166        }
167        if (fBinding >= 0) {
168            result += separator + "binding = " + to_string(fBinding);
169            separator = ", ";
170        }
171        if (fIndex >= 0) {
172            result += separator + "index = " + to_string(fIndex);
173            separator = ", ";
174        }
175        if (fSet >= 0) {
176            result += separator + "set = " + to_string(fSet);
177            separator = ", ";
178        }
179        if (fBuiltin >= 0) {
180            result += separator + "builtin = " + to_string(fBuiltin);
181            separator = ", ";
182        }
183        if (fInputAttachmentIndex >= 0) {
184            result += separator + "input_attachment_index = " + to_string(fBuiltin);
185            separator = ", ";
186        }
187        if (Format::kUnspecified != fFormat) {
188            result += separator + FormatToStr(fFormat);
189            separator = ", ";
190        }
191        if (fFlags & kOriginUpperLeft_Flag) {
192            result += separator + "origin_upper_left";
193            separator = ", ";
194        }
195        if (fFlags & kOverrideCoverage_Flag) {
196            result += separator + "override_coverage";
197            separator = ", ";
198        }
199        if (fFlags & kBlendSupportAllEquations_Flag) {
200            result += separator + "blend_support_all_equations";
201            separator = ", ";
202        }
203        if (fFlags & kBlendSupportMultiply_Flag) {
204            result += separator + "blend_support_multiply";
205            separator = ", ";
206        }
207        if (fFlags & kBlendSupportScreen_Flag) {
208            result += separator + "blend_support_screen";
209            separator = ", ";
210        }
211        if (fFlags & kBlendSupportOverlay_Flag) {
212            result += separator + "blend_support_overlay";
213            separator = ", ";
214        }
215        if (fFlags & kBlendSupportDarken_Flag) {
216            result += separator + "blend_support_darken";
217            separator = ", ";
218        }
219        if (fFlags & kBlendSupportLighten_Flag) {
220            result += separator + "blend_support_lighten";
221            separator = ", ";
222        }
223        if (fFlags & kBlendSupportColorDodge_Flag) {
224            result += separator + "blend_support_colordodge";
225            separator = ", ";
226        }
227        if (fFlags & kBlendSupportColorBurn_Flag) {
228            result += separator + "blend_support_colorburn";
229            separator = ", ";
230        }
231        if (fFlags & kBlendSupportHardLight_Flag) {
232            result += separator + "blend_support_hardlight";
233            separator = ", ";
234        }
235        if (fFlags & kBlendSupportSoftLight_Flag) {
236            result += separator + "blend_support_softlight";
237            separator = ", ";
238        }
239        if (fFlags & kBlendSupportDifference_Flag) {
240            result += separator + "blend_support_difference";
241            separator = ", ";
242        }
243        if (fFlags & kBlendSupportExclusion_Flag) {
244            result += separator + "blend_support_exclusion";
245            separator = ", ";
246        }
247        if (fFlags & kBlendSupportHSLHue_Flag) {
248            result += separator + "blend_support_hsl_hue";
249            separator = ", ";
250        }
251        if (fFlags & kBlendSupportHSLSaturation_Flag) {
252            result += separator + "blend_support_hsl_saturation";
253            separator = ", ";
254        }
255        if (fFlags & kBlendSupportHSLColor_Flag) {
256            result += separator + "blend_support_hsl_color";
257            separator = ", ";
258        }
259        if (fFlags & kBlendSupportHSLLuminosity_Flag) {
260            result += separator + "blend_support_hsl_luminosity";
261            separator = ", ";
262        }
263        if (fFlags & kPushConstant_Flag) {
264            result += separator + "push_constant";
265            separator = ", ";
266        }
267        switch (fPrimitive) {
268            case kPoints_Primitive:
269                result += separator + "points";
270                separator = ", ";
271                break;
272            case kLines_Primitive:
273                result += separator + "lines";
274                separator = ", ";
275                break;
276            case kLineStrip_Primitive:
277                result += separator + "line_strip";
278                separator = ", ";
279                break;
280            case kLinesAdjacency_Primitive:
281                result += separator + "lines_adjacency";
282                separator = ", ";
283                break;
284            case kTriangles_Primitive:
285                result += separator + "triangles";
286                separator = ", ";
287                break;
288            case kTriangleStrip_Primitive:
289                result += separator + "triangle_strip";
290                separator = ", ";
291                break;
292            case kTrianglesAdjacency_Primitive:
293                result += separator + "triangles_adjacency";
294                separator = ", ";
295                break;
296            case kUnspecified_Primitive:
297                break;
298        }
299        if (fMaxVertices >= 0) {
300            result += separator + "max_vertices = " + to_string(fMaxVertices);
301            separator = ", ";
302        }
303        if (fInvocations >= 0) {
304            result += separator + "invocations = " + to_string(fInvocations);
305            separator = ", ";
306        }
307        if (fWhen.size()) {
308            result += separator + "when = " + fWhen;
309            separator = ", ";
310        }
311        if (result.size() > 0) {
312            result = "layout (" + result + ")";
313        }
314        return result;
315    }
316
317    bool operator==(const Layout& other) const {
318        return fFlags                == other.fFlags &&
319               fLocation             == other.fLocation &&
320               fOffset               == other.fOffset &&
321               fBinding              == other.fBinding &&
322               fIndex                == other.fIndex &&
323               fSet                  == other.fSet &&
324               fBuiltin              == other.fBuiltin &&
325               fInputAttachmentIndex == other.fInputAttachmentIndex &&
326               fFormat               == other.fFormat &&
327               fPrimitive            == other.fPrimitive &&
328               fMaxVertices          == other.fMaxVertices &&
329               fInvocations          == other.fInvocations;
330    }
331
332    bool operator!=(const Layout& other) const {
333        return !(*this == other);
334    }
335
336    int fFlags;
337    int fLocation;
338    int fOffset;
339    int fBinding;
340    int fIndex;
341    int fSet;
342    // builtin comes from SPIR-V and identifies which particular builtin value this object
343    // represents.
344    int fBuiltin;
345    // input_attachment_index comes from Vulkan/SPIR-V to connect a shader variable to the a
346    // corresponding attachment on the subpass in which the shader is being used.
347    int fInputAttachmentIndex;
348    Format fFormat;
349    Primitive fPrimitive;
350    int fMaxVertices;
351    int fInvocations;
352    String fWhen;
353    Key fKey;
354    StringFragment fCType;
355};
356
357} // namespace
358
359#endif
360