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