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