1 //
2 // Copyright 2013 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // blocklayout.h:
7 // Methods and classes related to uniform layout and packing in GLSL and HLSL.
8 //
9
10 #ifndef COMMON_BLOCKLAYOUT_H_
11 #define COMMON_BLOCKLAYOUT_H_
12
13 #include <cstddef>
14 #include <map>
15 #include <vector>
16
17 #include <GLSLANG/ShaderLang.h>
18 #include "angle_gl.h"
19
20 namespace sh
21 {
22 struct ShaderVariable;
23 struct InterfaceBlockField;
24 struct Uniform;
25 struct Varying;
26 struct InterfaceBlock;
27
28 struct BlockMemberInfo
29 {
30 constexpr BlockMemberInfo() = default;
31
BlockMemberInfoBlockMemberInfo32 constexpr BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix)
33 : offset(offset),
34 arrayStride(arrayStride),
35 matrixStride(matrixStride),
36 isRowMajorMatrix(isRowMajorMatrix)
37 {}
38
BlockMemberInfoBlockMemberInfo39 constexpr BlockMemberInfo(int offset,
40 int arrayStride,
41 int matrixStride,
42 bool isRowMajorMatrix,
43 int topLevelArrayStride)
44 : offset(offset),
45 arrayStride(arrayStride),
46 matrixStride(matrixStride),
47 isRowMajorMatrix(isRowMajorMatrix),
48 topLevelArrayStride(topLevelArrayStride)
49 {}
50
51 // A single integer identifying the offset of an active variable.
52 int offset = -1;
53
54 // A single integer identifying the stride between array elements in an active variable.
55 int arrayStride = -1;
56
57 // A single integer identifying the stride between columns of a column-major matrix or rows of a
58 // row-major matrix.
59 int matrixStride = -1;
60
61 // A single integer identifying whether an active variable is a row-major matrix.
62 bool isRowMajorMatrix = false;
63
64 // A single integer identifying the number of active array elements of the top-level shader
65 // storage block member containing the active variable.
66 int topLevelArrayStride = -1;
67 };
68
ComponentAlignment(size_t numComponents)69 constexpr size_t ComponentAlignment(size_t numComponents)
70 {
71 return (numComponents == 3u ? 4u : numComponents);
72 }
73
74 constexpr BlockMemberInfo kDefaultBlockMemberInfo;
75
76 class BlockLayoutEncoder
77 {
78 public:
79 BlockLayoutEncoder();
~BlockLayoutEncoder()80 virtual ~BlockLayoutEncoder() {}
81
82 BlockMemberInfo encodeType(GLenum type,
83 const std::vector<unsigned int> &arraySizes,
84 bool isRowMajorMatrix);
85
getCurrentOffset()86 size_t getCurrentOffset() const { return mCurrentOffset * kBytesPerComponent; }
87 size_t getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor);
88
89 // Called when entering/exiting a structure variable.
90 virtual void enterAggregateType(const ShaderVariable &structVar) = 0;
91 virtual void exitAggregateType(const ShaderVariable &structVar) = 0;
92
93 static constexpr size_t kBytesPerComponent = 4u;
94 static constexpr unsigned int kComponentsPerRegister = 4u;
95
96 static size_t GetBlockRegister(const BlockMemberInfo &info);
97 static size_t GetBlockRegisterElement(const BlockMemberInfo &info);
98
99 protected:
100 void align(size_t baseAlignment);
101
102 virtual void getBlockLayoutInfo(GLenum type,
103 const std::vector<unsigned int> &arraySizes,
104 bool isRowMajorMatrix,
105 int *arrayStrideOut,
106 int *matrixStrideOut) = 0;
107 virtual void advanceOffset(GLenum type,
108 const std::vector<unsigned int> &arraySizes,
109 bool isRowMajorMatrix,
110 int arrayStride,
111 int matrixStride) = 0;
112
113 size_t mCurrentOffset;
114 };
115
116 // Will return default values for everything.
117 class DummyBlockEncoder : public BlockLayoutEncoder
118 {
119 public:
120 DummyBlockEncoder() = default;
121
enterAggregateType(const ShaderVariable & structVar)122 void enterAggregateType(const ShaderVariable &structVar) override {}
exitAggregateType(const ShaderVariable & structVar)123 void exitAggregateType(const ShaderVariable &structVar) override {}
124
125 protected:
126 void getBlockLayoutInfo(GLenum type,
127 const std::vector<unsigned int> &arraySizes,
128 bool isRowMajorMatrix,
129 int *arrayStrideOut,
130 int *matrixStrideOut) override;
131
advanceOffset(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int arrayStride,int matrixStride)132 void advanceOffset(GLenum type,
133 const std::vector<unsigned int> &arraySizes,
134 bool isRowMajorMatrix,
135 int arrayStride,
136 int matrixStride) override
137 {}
138 };
139
140 // Block layout according to the std140 block layout
141 // See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification
142
143 class Std140BlockEncoder : public BlockLayoutEncoder
144 {
145 public:
146 Std140BlockEncoder();
147
148 void enterAggregateType(const ShaderVariable &structVar) override;
149 void exitAggregateType(const ShaderVariable &structVar) override;
150
151 protected:
152 void getBlockLayoutInfo(GLenum type,
153 const std::vector<unsigned int> &arraySizes,
154 bool isRowMajorMatrix,
155 int *arrayStrideOut,
156 int *matrixStrideOut) override;
157 void advanceOffset(GLenum type,
158 const std::vector<unsigned int> &arraySizes,
159 bool isRowMajorMatrix,
160 int arrayStride,
161 int matrixStride) override;
162
163 virtual size_t getBaseAlignment(const ShaderVariable &variable) const;
164 virtual size_t getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const;
165 };
166
167 class Std430BlockEncoder : public Std140BlockEncoder
168 {
169 public:
170 Std430BlockEncoder();
171
172 protected:
173 size_t getBaseAlignment(const ShaderVariable &variable) const override;
174 size_t getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const override;
175 };
176
177 using BlockLayoutMap = std::map<std::string, BlockMemberInfo>;
178
179 void GetInterfaceBlockInfo(const std::vector<InterfaceBlockField> &fields,
180 const std::string &prefix,
181 BlockLayoutEncoder *encoder,
182 BlockLayoutMap *blockInfoOut);
183
184 // Used for laying out the default uniform block on the Vulkan backend.
185 void GetUniformBlockInfo(const std::vector<Uniform> &uniforms,
186 const std::string &prefix,
187 BlockLayoutEncoder *encoder,
188 BlockLayoutMap *blockInfoOut);
189
190 class ShaderVariableVisitor
191 {
192 public:
~ShaderVariableVisitor()193 virtual ~ShaderVariableVisitor() {}
194
enterStruct(const ShaderVariable & structVar)195 virtual void enterStruct(const ShaderVariable &structVar) {}
exitStruct(const ShaderVariable & structVar)196 virtual void exitStruct(const ShaderVariable &structVar) {}
197
enterStructAccess(const ShaderVariable & structVar,bool isRowMajor)198 virtual void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) {}
exitStructAccess(const ShaderVariable & structVar,bool isRowMajor)199 virtual void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) {}
200
enterArray(const ShaderVariable & arrayVar)201 virtual void enterArray(const ShaderVariable &arrayVar) {}
exitArray(const ShaderVariable & arrayVar)202 virtual void exitArray(const ShaderVariable &arrayVar) {}
203
enterArrayElement(const ShaderVariable & arrayVar,unsigned int arrayElement)204 virtual void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {}
exitArrayElement(const ShaderVariable & arrayVar,unsigned int arrayElement)205 virtual void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {}
206
visitSampler(const sh::ShaderVariable & sampler)207 virtual void visitSampler(const sh::ShaderVariable &sampler) {}
208
209 virtual void visitVariable(const ShaderVariable &variable, bool isRowMajor) = 0;
210
211 protected:
ShaderVariableVisitor()212 ShaderVariableVisitor() {}
213 };
214
215 class VariableNameVisitor : public ShaderVariableVisitor
216 {
217 public:
218 VariableNameVisitor(const std::string &namePrefix, const std::string &mappedNamePrefix);
219 ~VariableNameVisitor() override;
220
221 void enterStruct(const ShaderVariable &structVar) override;
222 void exitStruct(const ShaderVariable &structVar) override;
223 void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override;
224 void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) override;
225 void enterArray(const ShaderVariable &arrayVar) override;
226 void exitArray(const ShaderVariable &arrayVar) override;
227 void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
228 void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
229
230 protected:
visitNamedSampler(const sh::ShaderVariable & sampler,const std::string & name,const std::string & mappedName)231 virtual void visitNamedSampler(const sh::ShaderVariable &sampler,
232 const std::string &name,
233 const std::string &mappedName)
234 {}
235 virtual void visitNamedVariable(const ShaderVariable &variable,
236 bool isRowMajor,
237 const std::string &name,
238 const std::string &mappedName) = 0;
239
240 std::string collapseNameStack() const;
241 std::string collapseMappedNameStack() const;
242
243 private:
244 void visitSampler(const sh::ShaderVariable &sampler) final;
245 void visitVariable(const ShaderVariable &variable, bool isRowMajor) final;
246
247 std::vector<std::string> mNameStack;
248 std::vector<std::string> mMappedNameStack;
249 };
250
251 class BlockEncoderVisitor : public VariableNameVisitor
252 {
253 public:
254 BlockEncoderVisitor(const std::string &namePrefix,
255 const std::string &mappedNamePrefix,
256 BlockLayoutEncoder *encoder);
257 ~BlockEncoderVisitor() override;
258
259 void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override;
260 void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) override;
261 void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
262 void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
263
264 void visitNamedVariable(const ShaderVariable &variable,
265 bool isRowMajor,
266 const std::string &name,
267 const std::string &mappedName) override;
268
encodeVariable(const ShaderVariable & variable,const BlockMemberInfo & variableInfo,const std::string & name,const std::string & mappedName)269 virtual void encodeVariable(const ShaderVariable &variable,
270 const BlockMemberInfo &variableInfo,
271 const std::string &name,
272 const std::string &mappedName)
273 {}
274
275 protected:
276 int mTopLevelArraySize = 1;
277 int mTopLevelArrayStride = 0;
278 bool mIsTopLevelArrayStrideReady = true;
279 bool mSkipEnabled = false;
280
281 private:
282 BlockLayoutEncoder *mEncoder;
283 unsigned int mStructStackSize = 0;
284 };
285
286 void TraverseShaderVariable(const ShaderVariable &variable,
287 bool isRowMajorLayout,
288 ShaderVariableVisitor *visitor);
289
290 template <typename T>
TraverseShaderVariables(const std::vector<T> & vars,bool isRowMajorLayout,ShaderVariableVisitor * visitor)291 void TraverseShaderVariables(const std::vector<T> &vars,
292 bool isRowMajorLayout,
293 ShaderVariableVisitor *visitor)
294 {
295 for (const T &var : vars)
296 {
297 TraverseShaderVariable(var, isRowMajorLayout, visitor);
298 }
299 }
300 } // namespace sh
301
302 #endif // COMMON_BLOCKLAYOUT_H_
303