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