1//
2// Copyright (c) 2013-2014 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
20namespace sh
21{
22struct ShaderVariable;
23struct InterfaceBlockField;
24struct Uniform;
25struct Varying;
26struct InterfaceBlock;
27
28struct BlockMemberInfo
29{
30 constexpr BlockMemberInfo() = default;
31
32 constexpr BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix)
33 : offset(offset),
34 arrayStride(arrayStride),
35 matrixStride(matrixStride),
36 isRowMajorMatrix(isRowMajorMatrix)
37 {}
38
39 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
69constexpr size_t ComponentAlignment(size_t numComponents)
70{
71 return (numComponents == 3u ? 4u : numComponents);
72}
73
74constexpr BlockMemberInfo kDefaultBlockMemberInfo;
75
76class BlockLayoutEncoder
77{
78 public:
79 BlockLayoutEncoder();
80 virtual ~BlockLayoutEncoder() {}
81
82 BlockMemberInfo encodeType(GLenum type,
83 const std::vector<unsigned int> &arraySizes,
84 bool isRowMajorMatrix);
85
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.
117class DummyBlockEncoder : public BlockLayoutEncoder
118{
119 public:
120 DummyBlockEncoder() = default;
121
122 void enterAggregateType(const ShaderVariable &structVar) override {}
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
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
143class 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
167class 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
177using BlockLayoutMap = std::map<std::string, BlockMemberInfo>;
178
179void 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.
185void GetUniformBlockInfo(const std::vector<Uniform> &uniforms,
186 const std::string &prefix,
187 BlockLayoutEncoder *encoder,
188 BlockLayoutMap *blockInfoOut);
189
190class ShaderVariableVisitor
191{
192 public:
193 virtual ~ShaderVariableVisitor() {}
194
195 virtual void enterStruct(const ShaderVariable &structVar) {}
196 virtual void exitStruct(const ShaderVariable &structVar) {}
197
198 virtual void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) {}
199 virtual void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) {}
200
201 virtual void enterArray(const ShaderVariable &arrayVar) {}
202 virtual void exitArray(const ShaderVariable &arrayVar) {}
203
204 virtual void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {}
205 virtual void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {}
206
207 virtual void visitSampler(const sh::ShaderVariable &sampler) {}
208
209 virtual void visitVariable(const ShaderVariable &variable, bool isRowMajor) = 0;
210
211 protected:
212 ShaderVariableVisitor() {}
213};
214
215class 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:
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
251class 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
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
286void TraverseShaderVariable(const ShaderVariable &variable,
287 bool isRowMajorLayout,
288 ShaderVariableVisitor *visitor);
289
290template <typename T>
291void 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