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