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