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