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
getCurrentOffset()83 size_t getCurrentOffset() const { return mCurrentOffset * kBytesPerComponent; }
84 size_t getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor);
85
86 // Called when entering/exiting a structure variable.
87 virtual void enterAggregateType(const ShaderVariable &structVar) = 0;
88 virtual void exitAggregateType(const ShaderVariable &structVar) = 0;
89
90 static constexpr size_t kBytesPerComponent = 4u;
91 static constexpr unsigned int kComponentsPerRegister = 4u;
92
93 static size_t GetBlockRegister(const BlockMemberInfo &info);
94 static size_t GetBlockRegisterElement(const BlockMemberInfo &info);
95
96 protected:
97 void align(size_t baseAlignment);
98
99 virtual void getBlockLayoutInfo(GLenum type,
100 const std::vector<unsigned int> &arraySizes,
101 bool isRowMajorMatrix,
102 int *arrayStrideOut,
103 int *matrixStrideOut) = 0;
104 virtual void advanceOffset(GLenum type,
105 const std::vector<unsigned int> &arraySizes,
106 bool isRowMajorMatrix,
107 int arrayStride,
108 int matrixStride) = 0;
109
110 size_t mCurrentOffset;
111 };
112
113 // Will return default values for everything.
114 class DummyBlockEncoder : public BlockLayoutEncoder
115 {
116 public:
117 DummyBlockEncoder() = default;
118
enterAggregateType(const ShaderVariable & structVar)119 void enterAggregateType(const ShaderVariable &structVar) override {}
exitAggregateType(const ShaderVariable & structVar)120 void exitAggregateType(const ShaderVariable &structVar) override {}
121
122 protected:
123 void getBlockLayoutInfo(GLenum type,
124 const std::vector<unsigned int> &arraySizes,
125 bool isRowMajorMatrix,
126 int *arrayStrideOut,
127 int *matrixStrideOut) override;
128
advanceOffset(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int arrayStride,int matrixStride)129 void advanceOffset(GLenum type,
130 const std::vector<unsigned int> &arraySizes,
131 bool isRowMajorMatrix,
132 int arrayStride,
133 int matrixStride) override
134 {}
135 };
136
137 // Block layout according to the std140 block layout
138 // See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification
139
140 class Std140BlockEncoder : public BlockLayoutEncoder
141 {
142 public:
143 Std140BlockEncoder();
144
145 void enterAggregateType(const ShaderVariable &structVar) override;
146 void exitAggregateType(const ShaderVariable &structVar) override;
147
148 protected:
149 void getBlockLayoutInfo(GLenum type,
150 const std::vector<unsigned int> &arraySizes,
151 bool isRowMajorMatrix,
152 int *arrayStrideOut,
153 int *matrixStrideOut) override;
154 void advanceOffset(GLenum type,
155 const std::vector<unsigned int> &arraySizes,
156 bool isRowMajorMatrix,
157 int arrayStride,
158 int matrixStride) override;
159
160 virtual size_t getBaseAlignment(const ShaderVariable &variable) const;
161 virtual size_t getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const;
162 };
163
164 class Std430BlockEncoder : public Std140BlockEncoder
165 {
166 public:
167 Std430BlockEncoder();
168
169 protected:
170 size_t getBaseAlignment(const ShaderVariable &variable) const override;
171 size_t getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const override;
172 };
173
174 using BlockLayoutMap = std::map<std::string, BlockMemberInfo>;
175
176 void GetInterfaceBlockInfo(const std::vector<ShaderVariable> &fields,
177 const std::string &prefix,
178 BlockLayoutEncoder *encoder,
179 BlockLayoutMap *blockInfoOut);
180
181 // Used for laying out the default uniform block on the Vulkan backend.
182 void GetActiveUniformBlockInfo(const std::vector<ShaderVariable> &uniforms,
183 const std::string &prefix,
184 BlockLayoutEncoder *encoder,
185 BlockLayoutMap *blockInfoOut);
186
187 class ShaderVariableVisitor
188 {
189 public:
~ShaderVariableVisitor()190 virtual ~ShaderVariableVisitor() {}
191
enterStruct(const ShaderVariable & structVar)192 virtual void enterStruct(const ShaderVariable &structVar) {}
exitStruct(const ShaderVariable & structVar)193 virtual void exitStruct(const ShaderVariable &structVar) {}
194
enterStructAccess(const ShaderVariable & structVar,bool isRowMajor)195 virtual void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) {}
exitStructAccess(const ShaderVariable & structVar,bool isRowMajor)196 virtual void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) {}
197
enterArray(const ShaderVariable & arrayVar)198 virtual void enterArray(const ShaderVariable &arrayVar) {}
exitArray(const ShaderVariable & arrayVar)199 virtual void exitArray(const ShaderVariable &arrayVar) {}
200
enterArrayElement(const ShaderVariable & arrayVar,unsigned int arrayElement)201 virtual void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {}
exitArrayElement(const ShaderVariable & arrayVar,unsigned int arrayElement)202 virtual void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {}
203
visitSampler(const sh::ShaderVariable & sampler)204 virtual void visitSampler(const sh::ShaderVariable &sampler) {}
205
206 virtual void visitVariable(const ShaderVariable &variable, bool isRowMajor) = 0;
207
208 protected:
ShaderVariableVisitor()209 ShaderVariableVisitor() {}
210 };
211
212 class VariableNameVisitor : public ShaderVariableVisitor
213 {
214 public:
215 VariableNameVisitor(const std::string &namePrefix, const std::string &mappedNamePrefix);
216 ~VariableNameVisitor() override;
217
218 void enterStruct(const ShaderVariable &structVar) override;
219 void exitStruct(const ShaderVariable &structVar) override;
220 void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override;
221 void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) override;
222 void enterArray(const ShaderVariable &arrayVar) override;
223 void exitArray(const ShaderVariable &arrayVar) override;
224 void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
225 void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
226
227 protected:
visitNamedSampler(const sh::ShaderVariable & sampler,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)228 virtual void visitNamedSampler(const sh::ShaderVariable &sampler,
229 const std::string &name,
230 const std::string &mappedName,
231 const std::vector<unsigned int> &arraySizes)
232 {}
233 virtual void visitNamedVariable(const ShaderVariable &variable,
234 bool isRowMajor,
235 const std::string &name,
236 const std::string &mappedName,
237 const std::vector<unsigned int> &arraySizes) = 0;
238
239 std::string collapseNameStack() const;
240 std::string collapseMappedNameStack() const;
241
242 private:
243 void visitSampler(const sh::ShaderVariable &sampler) final;
244 void visitVariable(const ShaderVariable &variable, bool isRowMajor) final;
245
246 std::vector<std::string> mNameStack;
247 std::vector<std::string> mMappedNameStack;
248 std::vector<unsigned int> mArraySizeStack;
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,
268 const std::vector<unsigned int> &arraySizes) override;
269
encodeVariable(const ShaderVariable & variable,const BlockMemberInfo & variableInfo,const std::string & name,const std::string & mappedName)270 virtual void encodeVariable(const ShaderVariable &variable,
271 const BlockMemberInfo &variableInfo,
272 const std::string &name,
273 const std::string &mappedName)
274 {}
275
276 protected:
277 int mTopLevelArraySize = 1;
278 int mTopLevelArrayStride = 0;
279 bool mIsTopLevelArrayStrideReady = true;
280 bool mSkipEnabled = false;
281
282 private:
283 BlockLayoutEncoder *mEncoder;
284 unsigned int mStructStackSize = 0;
285 };
286
287 void TraverseShaderVariable(const ShaderVariable &variable,
288 bool isRowMajorLayout,
289 ShaderVariableVisitor *visitor);
290
291 template <typename T>
TraverseShaderVariables(const std::vector<T> & vars,bool isRowMajorLayout,ShaderVariableVisitor * visitor)292 void TraverseShaderVariables(const std::vector<T> &vars,
293 bool isRowMajorLayout,
294 ShaderVariableVisitor *visitor)
295 {
296 for (const T &var : vars)
297 {
298 TraverseShaderVariable(var, isRowMajorLayout, visitor);
299 }
300 }
301
302 template <typename T>
TraverseActiveShaderVariables(const std::vector<T> & vars,bool isRowMajorLayout,ShaderVariableVisitor * visitor)303 void TraverseActiveShaderVariables(const std::vector<T> &vars,
304 bool isRowMajorLayout,
305 ShaderVariableVisitor *visitor)
306 {
307 for (const T &var : vars)
308 {
309 if (var.active)
310 {
311 TraverseShaderVariable(var, isRowMajorLayout, visitor);
312 }
313 }
314 }
315 } // namespace sh
316
317 #endif // COMMON_BLOCKLAYOUT_H_
318