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.cpp:
7 //   Implementation for block layout classes and methods.
8 //
9 
10 #include "compiler/translator/blocklayout.h"
11 
12 #include "common/mathutil.h"
13 #include "common/utilities.h"
14 
15 namespace sh
16 {
17 
18 namespace
19 {
IsRowMajorLayout(const InterfaceBlockField & var)20 bool IsRowMajorLayout(const InterfaceBlockField &var)
21 {
22     return var.isRowMajorLayout;
23 }
24 
IsRowMajorLayout(const ShaderVariable & var)25 bool IsRowMajorLayout(const ShaderVariable &var)
26 {
27     return false;
28 }
29 
30 template <typename VarT>
31 void GetUniformBlockInfo(const std::vector<VarT> &fields,
32                          const std::string &prefix,
33                          sh::BlockLayoutEncoder *encoder,
34                          bool inRowMajorLayout,
35                          BlockLayoutMap *blockInfoOut);
36 
37 template <typename VarT>
GetUniformBlockStructMemberInfo(const std::vector<VarT> & fields,const std::string & fieldName,sh::BlockLayoutEncoder * encoder,bool inRowMajorLayout,BlockLayoutMap * blockInfoOut)38 void GetUniformBlockStructMemberInfo(const std::vector<VarT> &fields,
39                                      const std::string &fieldName,
40                                      sh::BlockLayoutEncoder *encoder,
41                                      bool inRowMajorLayout,
42                                      BlockLayoutMap *blockInfoOut)
43 {
44     encoder->enterAggregateType();
45     GetUniformBlockInfo(fields, fieldName, encoder, inRowMajorLayout, blockInfoOut);
46     encoder->exitAggregateType();
47 }
48 
49 template <typename VarT>
GetUniformBlockStructArrayMemberInfo(const VarT & field,unsigned int arrayNestingIndex,const std::string & arrayName,sh::BlockLayoutEncoder * encoder,bool inRowMajorLayout,BlockLayoutMap * blockInfoOut)50 void GetUniformBlockStructArrayMemberInfo(const VarT &field,
51                                           unsigned int arrayNestingIndex,
52                                           const std::string &arrayName,
53                                           sh::BlockLayoutEncoder *encoder,
54                                           bool inRowMajorLayout,
55                                           BlockLayoutMap *blockInfoOut)
56 {
57     // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
58     // innermost.
59     const unsigned int currentArraySize = field.getNestedArraySize(arrayNestingIndex);
60     for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
61     {
62         const std::string elementName = arrayName + ArrayString(arrayElement);
63         if (arrayNestingIndex + 1u < field.arraySizes.size())
64         {
65             GetUniformBlockStructArrayMemberInfo(field, arrayNestingIndex + 1u, elementName,
66                                                  encoder, inRowMajorLayout, blockInfoOut);
67         }
68         else
69         {
70             GetUniformBlockStructMemberInfo(field.fields, elementName, encoder, inRowMajorLayout,
71                                             blockInfoOut);
72         }
73     }
74 }
75 
76 template <typename VarT>
GetUniformBlockArrayOfArraysMemberInfo(const VarT & field,unsigned int arrayNestingIndex,const std::string & arrayName,sh::BlockLayoutEncoder * encoder,bool isRowMajorMatrix,BlockLayoutMap * blockInfoOut)77 void GetUniformBlockArrayOfArraysMemberInfo(const VarT &field,
78                                             unsigned int arrayNestingIndex,
79                                             const std::string &arrayName,
80                                             sh::BlockLayoutEncoder *encoder,
81                                             bool isRowMajorMatrix,
82                                             BlockLayoutMap *blockInfoOut)
83 {
84     const unsigned int currentArraySize = field.getNestedArraySize(arrayNestingIndex);
85     for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
86     {
87         const std::string elementName = arrayName + ArrayString(arrayElement);
88         if (arrayNestingIndex + 2u < field.arraySizes.size())
89         {
90             GetUniformBlockArrayOfArraysMemberInfo(field, arrayNestingIndex + 1u, elementName,
91                                                    encoder, isRowMajorMatrix, blockInfoOut);
92         }
93         else
94         {
95             std::vector<unsigned int> innermostArraySize(
96                 1u, field.getNestedArraySize(arrayNestingIndex + 1u));
97             (*blockInfoOut)[elementName] =
98                 encoder->encodeType(field.type, innermostArraySize, isRowMajorMatrix);
99         }
100     }
101 }
102 
103 template <typename VarT>
GetUniformBlockInfo(const std::vector<VarT> & fields,const std::string & prefix,sh::BlockLayoutEncoder * encoder,bool inRowMajorLayout,BlockLayoutMap * blockInfoOut)104 void GetUniformBlockInfo(const std::vector<VarT> &fields,
105                          const std::string &prefix,
106                          sh::BlockLayoutEncoder *encoder,
107                          bool inRowMajorLayout,
108                          BlockLayoutMap *blockInfoOut)
109 {
110     for (const VarT &field : fields)
111     {
112         // Skip samplers. On Vulkan we use this for the default uniform block, so samplers may be
113         // included.
114         if (gl::IsSamplerType(field.type))
115         {
116             continue;
117         }
118 
119         const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
120 
121         bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
122 
123         if (field.isStruct())
124         {
125             if (field.isArray())
126             {
127                 GetUniformBlockStructArrayMemberInfo(field, 0u, fieldName, encoder, rowMajorLayout,
128                                                      blockInfoOut);
129             }
130             else
131             {
132                 GetUniformBlockStructMemberInfo(field.fields, fieldName, encoder, rowMajorLayout,
133                                                 blockInfoOut);
134             }
135         }
136         else if (field.isArrayOfArrays())
137         {
138             GetUniformBlockArrayOfArraysMemberInfo(field, 0u, fieldName, encoder,
139                                                    rowMajorLayout && gl::IsMatrixType(field.type),
140                                                    blockInfoOut);
141         }
142         else
143         {
144             (*blockInfoOut)[fieldName] = encoder->encodeType(
145                 field.type, field.arraySizes, rowMajorLayout && gl::IsMatrixType(field.type));
146         }
147     }
148 }
149 
150 }  // anonymous namespace
151 
BlockLayoutEncoder()152 BlockLayoutEncoder::BlockLayoutEncoder() : mCurrentOffset(0)
153 {
154 }
155 
encodeType(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix)156 BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type,
157                                                const std::vector<unsigned int> &arraySizes,
158                                                bool isRowMajorMatrix)
159 {
160     int arrayStride;
161     int matrixStride;
162 
163     getBlockLayoutInfo(type, arraySizes, isRowMajorMatrix, &arrayStride, &matrixStride);
164 
165     const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * BytesPerComponent),
166                                      static_cast<int>(arrayStride * BytesPerComponent),
167                                      static_cast<int>(matrixStride * BytesPerComponent),
168                                      isRowMajorMatrix);
169 
170     advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride, matrixStride);
171 
172     return memberInfo;
173 }
174 
175 // static
getBlockRegister(const BlockMemberInfo & info)176 size_t BlockLayoutEncoder::getBlockRegister(const BlockMemberInfo &info)
177 {
178     return (info.offset / BytesPerComponent) / ComponentsPerRegister;
179 }
180 
181 // static
getBlockRegisterElement(const BlockMemberInfo & info)182 size_t BlockLayoutEncoder::getBlockRegisterElement(const BlockMemberInfo &info)
183 {
184     return (info.offset / BytesPerComponent) % ComponentsPerRegister;
185 }
186 
nextRegister()187 void BlockLayoutEncoder::nextRegister()
188 {
189     mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, ComponentsPerRegister);
190 }
191 
Std140BlockEncoder()192 Std140BlockEncoder::Std140BlockEncoder()
193 {
194 }
195 
enterAggregateType()196 void Std140BlockEncoder::enterAggregateType()
197 {
198     nextRegister();
199 }
200 
exitAggregateType()201 void Std140BlockEncoder::exitAggregateType()
202 {
203     nextRegister();
204 }
205 
getBlockLayoutInfo(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int * arrayStrideOut,int * matrixStrideOut)206 void Std140BlockEncoder::getBlockLayoutInfo(GLenum type,
207                                             const std::vector<unsigned int> &arraySizes,
208                                             bool isRowMajorMatrix,
209                                             int *arrayStrideOut,
210                                             int *matrixStrideOut)
211 {
212     // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
213     ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent);
214 
215     size_t baseAlignment = 0;
216     int matrixStride     = 0;
217     int arrayStride      = 0;
218 
219     if (gl::IsMatrixType(type))
220     {
221         baseAlignment = ComponentsPerRegister;
222         matrixStride  = ComponentsPerRegister;
223 
224         if (!arraySizes.empty())
225         {
226             const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
227             arrayStride            = ComponentsPerRegister * numRegisters;
228         }
229     }
230     else if (!arraySizes.empty())
231     {
232         baseAlignment = ComponentsPerRegister;
233         arrayStride   = ComponentsPerRegister;
234     }
235     else
236     {
237         const int numComponents = gl::VariableComponentCount(type);
238         baseAlignment           = (numComponents == 3 ? 4u : static_cast<size_t>(numComponents));
239     }
240 
241     mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment);
242 
243     *matrixStrideOut = matrixStride;
244     *arrayStrideOut  = arrayStride;
245 }
246 
advanceOffset(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int arrayStride,int matrixStride)247 void Std140BlockEncoder::advanceOffset(GLenum type,
248                                        const std::vector<unsigned int> &arraySizes,
249                                        bool isRowMajorMatrix,
250                                        int arrayStride,
251                                        int matrixStride)
252 {
253     if (!arraySizes.empty())
254     {
255         mCurrentOffset += arrayStride * gl::ArraySizeProduct(arraySizes);
256     }
257     else if (gl::IsMatrixType(type))
258     {
259         ASSERT(matrixStride == ComponentsPerRegister);
260         const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
261         mCurrentOffset += ComponentsPerRegister * numRegisters;
262     }
263     else
264     {
265         mCurrentOffset += gl::VariableComponentCount(type);
266     }
267 }
268 
GetUniformBlockInfo(const std::vector<InterfaceBlockField> & fields,const std::string & prefix,sh::BlockLayoutEncoder * encoder,BlockLayoutMap * blockInfoOut)269 void GetUniformBlockInfo(const std::vector<InterfaceBlockField> &fields,
270                          const std::string &prefix,
271                          sh::BlockLayoutEncoder *encoder,
272                          BlockLayoutMap *blockInfoOut)
273 {
274     // Matrix packing is always recorded in individual fields, so they'll set the row major layout
275     // flag to true if needed.
276     GetUniformBlockInfo(fields, prefix, encoder, false, blockInfoOut);
277 }
278 
GetUniformBlockInfo(const std::vector<Uniform> & uniforms,const std::string & prefix,sh::BlockLayoutEncoder * encoder,BlockLayoutMap * blockInfoOut)279 void GetUniformBlockInfo(const std::vector<Uniform> &uniforms,
280                          const std::string &prefix,
281                          sh::BlockLayoutEncoder *encoder,
282                          BlockLayoutMap *blockInfoOut)
283 {
284     // Matrix packing is always recorded in individual fields, so they'll set the row major layout
285     // flag to true if needed.
286     GetUniformBlockInfo(uniforms, prefix, encoder, false, blockInfoOut);
287 }
288 
289 
290 }  // namespace sh
291