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 "SkString.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 Primitive {
23        kUnspecified_Primitive = -1,
24        kPoints_Primitive,
25        kLines_Primitive,
26        kLineStrip_Primitive,
27        kLinesAdjacency_Primitive,
28        kTriangles_Primitive,
29        kTriangleStrip_Primitive,
30        kTrianglesAdjacency_Primitive
31    };
32
33    // These are used by images in GLSL. We only support a subset of what GL supports.
34    enum class Format {
35        kUnspecified = -1,
36        kRGBA32F,
37        kR32F,
38        kRGBA16F,
39        kR16F,
40        kRGBA8,
41        kR8,
42        kRGBA8I,
43        kR8I,
44    };
45
46    static const char* FormatToStr(Format format) {
47        switch (format) {
48            case Format::kUnspecified:  return "";
49            case Format::kRGBA32F:      return "rgba32f";
50            case Format::kR32F:         return "r32f";
51            case Format::kRGBA16F:      return "rgba16f";
52            case Format::kR16F:         return "r16f";
53            case Format::kRGBA8:        return "rgba8";
54            case Format::kR8:           return "r8";
55            case Format::kRGBA8I:       return "rgba8i";
56            case Format::kR8I:          return "r8i";
57        }
58        SkFAIL("Unexpected format");
59        return "";
60    }
61
62    static bool ReadFormat(SkString str, Format* format) {
63        if (str == "rgba32f") {
64            *format = Format::kRGBA32F;
65            return true;
66        } else if (str == "r32f") {
67            *format = Format::kR32F;
68            return true;
69        } else if (str == "rgba16f") {
70            *format = Format::kRGBA16F;
71            return true;
72        } else if (str == "r16f") {
73            *format = Format::kR16F;
74            return true;
75        } else if (str == "rgba8") {
76            *format = Format::kRGBA8;
77            return true;
78        } else if (str == "r8") {
79            *format = Format::kR8;
80            return true;
81        } else if (str == "rgba8i") {
82            *format = Format::kRGBA8I;
83            return true;
84        } else if (str == "r8i") {
85            *format = Format::kR8I;
86            return true;
87        }
88        return false;
89    }
90
91    Layout(int location, int offset, int binding, int index, int set, int builtin,
92           int inputAttachmentIndex, bool originUpperLeft, bool overrideCoverage,
93           bool blendSupportAllEquations, Format format, bool pushconstant, Primitive primitive,
94           int maxVertices, int invocations)
95    : fLocation(location)
96    , fOffset(offset)
97    , fBinding(binding)
98    , fIndex(index)
99    , fSet(set)
100    , fBuiltin(builtin)
101    , fInputAttachmentIndex(inputAttachmentIndex)
102    , fOriginUpperLeft(originUpperLeft)
103    , fOverrideCoverage(overrideCoverage)
104    , fBlendSupportAllEquations(blendSupportAllEquations)
105    , fFormat(format)
106    , fPushConstant(pushconstant)
107    , fPrimitive(primitive)
108    , fMaxVertices(maxVertices)
109    , fInvocations(invocations) {}
110
111    Layout()
112    : fLocation(-1)
113    , fOffset(-1)
114    , fBinding(-1)
115    , fIndex(-1)
116    , fSet(-1)
117    , fBuiltin(-1)
118    , fInputAttachmentIndex(-1)
119    , fOriginUpperLeft(false)
120    , fOverrideCoverage(false)
121    , fBlendSupportAllEquations(false)
122    , fFormat(Format::kUnspecified)
123    , fPushConstant(false)
124    , fPrimitive(kUnspecified_Primitive)
125    , fMaxVertices(-1)
126    , fInvocations(-1) {}
127
128    SkString description() const {
129        SkString result;
130        SkString separator;
131        if (fLocation >= 0) {
132            result += separator + "location = " + to_string(fLocation);
133            separator = ", ";
134        }
135        if (fOffset >= 0) {
136            result += separator + "offset = " + to_string(fOffset);
137            separator = ", ";
138        }
139        if (fBinding >= 0) {
140            result += separator + "binding = " + to_string(fBinding);
141            separator = ", ";
142        }
143        if (fIndex >= 0) {
144            result += separator + "index = " + to_string(fIndex);
145            separator = ", ";
146        }
147        if (fSet >= 0) {
148            result += separator + "set = " + to_string(fSet);
149            separator = ", ";
150        }
151        if (fBuiltin >= 0) {
152            result += separator + "builtin = " + to_string(fBuiltin);
153            separator = ", ";
154        }
155        if (fInputAttachmentIndex >= 0) {
156            result += separator + "input_attachment_index = " + to_string(fBuiltin);
157            separator = ", ";
158        }
159        if (fOriginUpperLeft) {
160            result += separator + "origin_upper_left";
161            separator = ", ";
162        }
163        if (fOverrideCoverage) {
164            result += separator + "override_coverage";
165            separator = ", ";
166        }
167        if (fBlendSupportAllEquations) {
168            result += separator + "blend_support_all_equations";
169            separator = ", ";
170        }
171        if (Format::kUnspecified != fFormat) {
172            result += separator + FormatToStr(fFormat);
173            separator = ", ";
174        }
175        if (fPushConstant) {
176            result += separator + "push_constant";
177            separator = ", ";
178        }
179        switch (fPrimitive) {
180            case kPoints_Primitive:
181                result += separator + "points";
182                separator = ", ";
183                break;
184            case kLines_Primitive:
185                result += separator + "lines";
186                separator = ", ";
187                break;
188            case kLineStrip_Primitive:
189                result += separator + "line_strip";
190                separator = ", ";
191                break;
192            case kLinesAdjacency_Primitive:
193                result += separator + "lines_adjacency";
194                separator = ", ";
195                break;
196            case kTriangles_Primitive:
197                result += separator + "triangles";
198                separator = ", ";
199                break;
200            case kTriangleStrip_Primitive:
201                result += separator + "triangle_strip";
202                separator = ", ";
203                break;
204            case kTrianglesAdjacency_Primitive:
205                result += separator + "triangles_adjacency";
206                separator = ", ";
207                break;
208            case kUnspecified_Primitive:
209                break;
210        }
211        if (fMaxVertices >= 0) {
212            result += separator + "max_vertices = " + to_string(fMaxVertices);
213            separator = ", ";
214        }
215        if (fInvocations >= 0) {
216            result += separator + "invocations = " + to_string(fInvocations);
217            separator = ", ";
218        }
219        if (result.size() > 0) {
220            result = "layout (" + result + ")";
221        }
222        return result;
223    }
224
225    bool operator==(const Layout& other) const {
226        return fLocation                 == other.fLocation &&
227               fOffset                   == other.fOffset &&
228               fBinding                  == other.fBinding &&
229               fIndex                    == other.fIndex &&
230               fSet                      == other.fSet &&
231               fBuiltin                  == other.fBuiltin &&
232               fInputAttachmentIndex     == other.fInputAttachmentIndex &&
233               fOriginUpperLeft          == other.fOriginUpperLeft &&
234               fOverrideCoverage         == other.fOverrideCoverage &&
235               fBlendSupportAllEquations == other.fBlendSupportAllEquations &&
236               fFormat                   == other.fFormat &&
237               fPrimitive                == other.fPrimitive &&
238               fMaxVertices              == other.fMaxVertices &&
239               fInvocations              == other.fInvocations;
240    }
241
242    bool operator!=(const Layout& other) const {
243        return !(*this == other);
244    }
245
246    int fLocation;
247    int fOffset;
248    int fBinding;
249    int fIndex;
250    int fSet;
251    // builtin comes from SPIR-V and identifies which particular builtin value this object
252    // represents.
253    int fBuiltin;
254    // input_attachment_index comes from Vulkan/SPIR-V to connect a shader variable to the a
255    // corresponding attachment on the subpass in which the shader is being used.
256    int fInputAttachmentIndex;
257    bool fOriginUpperLeft;
258    bool fOverrideCoverage;
259    bool fBlendSupportAllEquations;
260    Format fFormat;
261    bool fPushConstant;
262    Primitive fPrimitive;
263    int fMaxVertices;
264    int fInvocations;
265};
266
267} // namespace
268
269#endif
270