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