blob: 45f516f3a4612b8822fc88c197ac9c45db2c64ec [file] [log] [blame]
Jamie Madill834e8b72014-04-11 13:33:58 -04001//
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 "common/blocklayout.h"
11#include "common/shadervars.h"
12#include "common/mathutil.h"
13#include "common/utilities.h"
14
15namespace gl
16{
17
18BlockLayoutEncoder::BlockLayoutEncoder(std::vector<BlockMemberInfo> *blockInfoOut)
19 : mCurrentOffset(0),
20 mBlockInfoOut(blockInfoOut)
21{
22}
23
24void BlockLayoutEncoder::encodeInterfaceBlockFields(const std::vector<InterfaceBlockField> &fields)
25{
26 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
27 {
28 const InterfaceBlockField &variable = fields[fieldIndex];
29
30 if (variable.fields.size() > 0)
31 {
32 const unsigned int elementCount = std::max(1u, variable.arraySize);
33
34 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
35 {
36 enterAggregateType();
37 encodeInterfaceBlockFields(variable.fields);
38 exitAggregateType();
39 }
40 }
41 else
42 {
43 encodeInterfaceBlockField(variable);
44 }
45 }
46}
47
48void BlockLayoutEncoder::encodeInterfaceBlockField(const InterfaceBlockField &field)
49{
50 int arrayStride;
51 int matrixStride;
52
53 ASSERT(field.fields.empty());
54 getBlockLayoutInfo(field.type, field.arraySize, field.isRowMajorMatrix, &arrayStride, &matrixStride);
55
56 const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, field.isRowMajorMatrix);
57
58 if (mBlockInfoOut)
59 {
60 mBlockInfoOut->push_back(memberInfo);
61 }
62
63 advanceOffset(field.type, field.arraySize, field.isRowMajorMatrix, arrayStride, matrixStride);
64}
65
66void BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix)
67{
68 int arrayStride;
69 int matrixStride;
70
71 getBlockLayoutInfo(type, arraySize, isRowMajorMatrix, &arrayStride, &matrixStride);
72
73 const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, isRowMajorMatrix);
74
75 if (mBlockInfoOut)
76 {
77 mBlockInfoOut->push_back(memberInfo);
78 }
79
80 advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride);
81}
82
83void BlockLayoutEncoder::nextRegister()
84{
85 mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, ComponentsPerRegister);
86}
87
88Std140BlockEncoder::Std140BlockEncoder(std::vector<BlockMemberInfo> *blockInfoOut)
89 : BlockLayoutEncoder(blockInfoOut)
90{
91}
92
93void Std140BlockEncoder::enterAggregateType()
94{
95 nextRegister();
96}
97
98void Std140BlockEncoder::exitAggregateType()
99{
100 nextRegister();
101}
102
103void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
104{
105 // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
106 ASSERT(gl::UniformComponentSize(gl::UniformComponentType(type)) == BytesPerComponent);
107
108 size_t baseAlignment = 0;
109 int matrixStride = 0;
110 int arrayStride = 0;
111
112 if (gl::IsMatrixType(type))
113 {
114 baseAlignment = ComponentsPerRegister;
115 matrixStride = ComponentsPerRegister;
116
117 if (arraySize > 0)
118 {
119 const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
120 arrayStride = ComponentsPerRegister * numRegisters;
121 }
122 }
123 else if (arraySize > 0)
124 {
125 baseAlignment = ComponentsPerRegister;
126 arrayStride = ComponentsPerRegister;
127 }
128 else
129 {
130 const int numComponents = gl::UniformComponentCount(type);
131 baseAlignment = (numComponents == 3 ? 4u : static_cast<size_t>(numComponents));
132 }
133
134 mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment);
135
136 *matrixStrideOut = matrixStride;
137 *arrayStrideOut = arrayStride;
138}
139
140void Std140BlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
141{
142 if (arraySize > 0)
143 {
144 mCurrentOffset += arrayStride * arraySize;
145 }
146 else if (gl::IsMatrixType(type))
147 {
148 ASSERT(matrixStride == ComponentsPerRegister);
149 const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
150 mCurrentOffset += ComponentsPerRegister * numRegisters;
151 }
152 else
153 {
154 mCurrentOffset += gl::UniformComponentCount(type);
155 }
156}
157
158HLSLBlockEncoder::HLSLBlockEncoder(std::vector<BlockMemberInfo> *blockInfoOut)
159 : BlockLayoutEncoder(blockInfoOut)
160{
161}
162
163void HLSLBlockEncoder::enterAggregateType()
164{
165 nextRegister();
166}
167
168void HLSLBlockEncoder::exitAggregateType()
169{
170}
171
172void HLSLBlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
173{
174 // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
175 ASSERT(gl::UniformComponentSize(gl::UniformComponentType(type)) == BytesPerComponent);
176
177 int matrixStride = 0;
178 int arrayStride = 0;
179
180 if (gl::IsMatrixType(type))
181 {
182 nextRegister();
183 matrixStride = ComponentsPerRegister;
184
185 if (arraySize > 0)
186 {
187 const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
188 arrayStride = ComponentsPerRegister * numRegisters;
189 }
190 }
191 else if (arraySize > 0)
192 {
193 nextRegister();
194 arrayStride = ComponentsPerRegister;
195 }
196 else
197 {
198 int numComponents = gl::UniformComponentCount(type);
199 if ((numComponents + (mCurrentOffset % ComponentsPerRegister)) > ComponentsPerRegister)
200 {
201 nextRegister();
202 }
203 }
204
205 *matrixStrideOut = matrixStride;
206 *arrayStrideOut = arrayStride;
207}
208
209void HLSLBlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
210{
211 if (arraySize > 0)
212 {
213 mCurrentOffset += arrayStride * (arraySize - 1);
214 }
215
216 if (gl::IsMatrixType(type))
217 {
218 ASSERT(matrixStride == ComponentsPerRegister);
219 const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
220 const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix);
221 mCurrentOffset += ComponentsPerRegister * (numRegisters - 1);
222 mCurrentOffset += numComponents;
223 }
224 else
225 {
226 mCurrentOffset += gl::UniformComponentCount(type);
227 }
228}
229
230void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, gl::Uniform *variable, HLSLBlockEncoder *encoder, const std::vector<gl::BlockMemberInfo> &blockInfo)
231{
232 // because this method computes offsets (element indexes) instead of any total sizes,
233 // we can ignore the array size of the variable
234
235 if (variable->isStruct())
236 {
237 encoder->enterAggregateType();
238
239 for (size_t fieldIndex = 0; fieldIndex < variable->fields.size(); fieldIndex++)
240 {
241 HLSLVariableGetRegisterInfo(baseRegisterIndex, &variable->fields[fieldIndex], encoder, blockInfo);
242 }
243
244 encoder->exitAggregateType();
245 }
246 else
247 {
248 encoder->encodeType(variable->type, variable->arraySize, false);
249
250 const size_t registerBytes = (encoder->BytesPerComponent * encoder->ComponentsPerRegister);
251 variable->registerIndex = baseRegisterIndex + (blockInfo.back().offset / registerBytes);
252 variable->elementIndex = (blockInfo.back().offset % registerBytes) / sizeof(float);
253 }
254}
255
256void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, gl::Uniform *variable)
257{
258 std::vector<BlockMemberInfo> blockInfo;
259 HLSLBlockEncoder encoder(&blockInfo);
260 HLSLVariableGetRegisterInfo(baseRegisterIndex, variable, &encoder, blockInfo);
261}
262
263template <class ShaderVarType>
264void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder)
265{
266 if (variable.isStruct())
267 {
268 for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++)
269 {
270 encoder->enterAggregateType();
271
272 for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++)
273 {
274 HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder);
275 }
276
277 encoder->exitAggregateType();
278 }
279 }
280 else
281 {
282 // We operate only on varyings and uniforms, which do not have matrix layout qualifiers
283 encoder->encodeType(variable.type, variable.arraySize, false);
284 }
285}
286
287unsigned int HLSLVariableRegisterCount(const Varying &variable)
288{
289 HLSLBlockEncoder encoder(NULL);
290 HLSLVariableRegisterCount(variable, &encoder);
291
292 const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
293 return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
294}
295
296unsigned int HLSLVariableRegisterCount(const Uniform &variable)
297{
298 HLSLBlockEncoder encoder(NULL);
299 HLSLVariableRegisterCount(variable, &encoder);
300
301 const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
302 return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
303}
304
305}