blob: a0c9289d7906bcfa7177f5a43c64764ae293c917 [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
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400158HLSLBlockEncoder::HLSLBlockEncoder(std::vector<BlockMemberInfo> *blockInfoOut, HLSLBlockEncoderStrategy strategy)
159 : BlockLayoutEncoder(blockInfoOut),
160 mEncoderStrategy(strategy)
Jamie Madill834e8b72014-04-11 13:33:58 -0400161{
162}
163
164void HLSLBlockEncoder::enterAggregateType()
165{
166 nextRegister();
167}
168
169void HLSLBlockEncoder::exitAggregateType()
170{
171}
172
173void HLSLBlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
174{
175 // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
176 ASSERT(gl::UniformComponentSize(gl::UniformComponentType(type)) == BytesPerComponent);
177
178 int matrixStride = 0;
179 int arrayStride = 0;
180
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400181 // if variables are not to be packed, or we're about to
182 // pack a matrix or array, skip to the start of the next
183 // register
184 if (!isPacked() ||
185 gl::IsMatrixType(type) ||
186 arraySize > 0)
Jamie Madill834e8b72014-04-11 13:33:58 -0400187 {
188 nextRegister();
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400189 }
190
191 if (gl::IsMatrixType(type))
192 {
Jamie Madill834e8b72014-04-11 13:33:58 -0400193 matrixStride = ComponentsPerRegister;
194
195 if (arraySize > 0)
196 {
197 const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
198 arrayStride = ComponentsPerRegister * numRegisters;
199 }
200 }
201 else if (arraySize > 0)
202 {
Jamie Madill834e8b72014-04-11 13:33:58 -0400203 arrayStride = ComponentsPerRegister;
204 }
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400205 else if (isPacked())
Jamie Madill834e8b72014-04-11 13:33:58 -0400206 {
207 int numComponents = gl::UniformComponentCount(type);
208 if ((numComponents + (mCurrentOffset % ComponentsPerRegister)) > ComponentsPerRegister)
209 {
210 nextRegister();
211 }
212 }
213
214 *matrixStrideOut = matrixStride;
215 *arrayStrideOut = arrayStride;
216}
217
218void HLSLBlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
219{
220 if (arraySize > 0)
221 {
222 mCurrentOffset += arrayStride * (arraySize - 1);
223 }
224
225 if (gl::IsMatrixType(type))
226 {
227 ASSERT(matrixStride == ComponentsPerRegister);
228 const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
229 const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix);
230 mCurrentOffset += ComponentsPerRegister * (numRegisters - 1);
231 mCurrentOffset += numComponents;
232 }
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400233 else if (isPacked())
Jamie Madill834e8b72014-04-11 13:33:58 -0400234 {
235 mCurrentOffset += gl::UniformComponentCount(type);
236 }
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400237 else
238 {
239 mCurrentOffset += ComponentsPerRegister;
240 }
Jamie Madill834e8b72014-04-11 13:33:58 -0400241}
242
Jamie Madillc600c8c2014-05-16 11:22:21 -0400243void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters)
244{
245 mCurrentOffset += (numRegisters * ComponentsPerRegister);
246}
247
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400248void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, gl::Uniform *variable, HLSLBlockEncoder *encoder,
249 const std::vector<gl::BlockMemberInfo> &blockInfo, ShShaderOutput outputType)
Jamie Madill834e8b72014-04-11 13:33:58 -0400250{
251 // because this method computes offsets (element indexes) instead of any total sizes,
252 // we can ignore the array size of the variable
253
254 if (variable->isStruct())
255 {
256 encoder->enterAggregateType();
257
Jamie Madillc600c8c2014-05-16 11:22:21 -0400258 variable->registerIndex = baseRegisterIndex;
259
Jamie Madill834e8b72014-04-11 13:33:58 -0400260 for (size_t fieldIndex = 0; fieldIndex < variable->fields.size(); fieldIndex++)
261 {
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400262 HLSLVariableGetRegisterInfo(baseRegisterIndex, &variable->fields[fieldIndex], encoder, blockInfo, outputType);
Jamie Madill834e8b72014-04-11 13:33:58 -0400263 }
264
Jamie Madillc600c8c2014-05-16 11:22:21 -0400265 // Since the above loop only encodes one element of an array, ensure we don't lose track of the
266 // current register offset
267 if (variable->isArray())
268 {
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400269 unsigned int structRegisterCount = (HLSLVariableRegisterCount(*variable, outputType) / variable->arraySize);
Jamie Madillc600c8c2014-05-16 11:22:21 -0400270 encoder->skipRegisters(structRegisterCount * (variable->arraySize - 1));
271 }
272
Jamie Madill834e8b72014-04-11 13:33:58 -0400273 encoder->exitAggregateType();
274 }
275 else
276 {
277 encoder->encodeType(variable->type, variable->arraySize, false);
278
279 const size_t registerBytes = (encoder->BytesPerComponent * encoder->ComponentsPerRegister);
280 variable->registerIndex = baseRegisterIndex + (blockInfo.back().offset / registerBytes);
281 variable->elementIndex = (blockInfo.back().offset % registerBytes) / sizeof(float);
282 }
283}
284
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400285void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, gl::Uniform *variable, ShShaderOutput outputType)
Jamie Madill834e8b72014-04-11 13:33:58 -0400286{
287 std::vector<BlockMemberInfo> blockInfo;
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400288 HLSLBlockEncoder encoder(&blockInfo,
289 outputType == SH_HLSL9_OUTPUT ? HLSLBlockEncoder::ENCODE_LOOSE
290 : HLSLBlockEncoder::ENCODE_PACKED);
291 HLSLVariableGetRegisterInfo(baseRegisterIndex, variable, &encoder, blockInfo, outputType);
Jamie Madill834e8b72014-04-11 13:33:58 -0400292}
293
294template <class ShaderVarType>
295void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder)
296{
297 if (variable.isStruct())
298 {
299 for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++)
300 {
301 encoder->enterAggregateType();
302
303 for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++)
304 {
305 HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder);
306 }
307
308 encoder->exitAggregateType();
309 }
310 }
311 else
312 {
313 // We operate only on varyings and uniforms, which do not have matrix layout qualifiers
314 encoder->encodeType(variable.type, variable.arraySize, false);
315 }
316}
317
318unsigned int HLSLVariableRegisterCount(const Varying &variable)
319{
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400320 HLSLBlockEncoder encoder(NULL, HLSLBlockEncoder::ENCODE_PACKED);
Jamie Madill834e8b72014-04-11 13:33:58 -0400321 HLSLVariableRegisterCount(variable, &encoder);
322
323 const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
324 return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
325}
326
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400327unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType)
Jamie Madill834e8b72014-04-11 13:33:58 -0400328{
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400329 HLSLBlockEncoder encoder(NULL,
330 outputType == SH_HLSL9_OUTPUT ? HLSLBlockEncoder::ENCODE_LOOSE
331 : HLSLBlockEncoder::ENCODE_PACKED);
332
Jamie Madill834e8b72014-04-11 13:33:58 -0400333 HLSLVariableRegisterCount(variable, &encoder);
334
335 const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
336 return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
337}
338
339}