blob: 9bf14cb6d3cdf7e9584ef05dfc4f1c016e25e1f1 [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
Jamie Madillf2575982014-06-25 16:04:54 -040015namespace sh
Jamie Madill834e8b72014-04-11 13:33:58 -040016{
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)
Jamie Madillf2575982014-06-25 16:04:54 -0400106 ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent);
Jamie Madill834e8b72014-04-11 13:33:58 -0400107
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 {
Jamie Madillf2575982014-06-25 16:04:54 -0400130 const int numComponents = gl::VariableComponentCount(type);
Jamie Madill834e8b72014-04-11 13:33:58 -0400131 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 {
Jamie Madillf2575982014-06-25 16:04:54 -0400154 mCurrentOffset += gl::VariableComponentCount(type);
Jamie Madill834e8b72014-04-11 13:33:58 -0400155 }
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)
Jamie Madillf2575982014-06-25 16:04:54 -0400176 ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent);
Jamie Madill834e8b72014-04-11 13:33:58 -0400177
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 {
Jamie Madillf2575982014-06-25 16:04:54 -0400207 int numComponents = gl::VariableComponentCount(type);
Jamie Madill834e8b72014-04-11 13:33:58 -0400208 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 {
Jamie Madillf2575982014-06-25 16:04:54 -0400235 mCurrentOffset += gl::VariableComponentCount(type);
Jamie Madill834e8b72014-04-11 13:33:58 -0400236 }
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
Jamie Madillfc43d272014-07-11 17:02:02 -0400248size_t HLSLInterfaceBlockDataSize(const sh::InterfaceBlock &interfaceBlock)
249{
250 switch (interfaceBlock.layout)
251 {
252 case BLOCKLAYOUT_SHARED:
253 case BLOCKLAYOUT_PACKED:
254 {
255 HLSLBlockEncoder hlslEncoder(NULL, HLSLBlockEncoder::ENCODE_PACKED);
256 hlslEncoder.encodeInterfaceBlockFields(interfaceBlock.fields);
257 return hlslEncoder.getBlockSize();
258 }
259 break;
260
261 case BLOCKLAYOUT_STANDARD:
262 {
263 Std140BlockEncoder stdEncoder(NULL);
264 stdEncoder.encodeInterfaceBlockFields(interfaceBlock.fields);
265 return stdEncoder.getBlockSize();
266 }
267 break;
268
269 default:
270 UNREACHABLE();
271 return 0;
272 }
273}
274
Jamie Madillf2575982014-06-25 16:04:54 -0400275void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, Uniform *variable, HLSLBlockEncoder *encoder,
276 const std::vector<BlockMemberInfo> &blockInfo, ShShaderOutput outputType)
Jamie Madill834e8b72014-04-11 13:33:58 -0400277{
278 // because this method computes offsets (element indexes) instead of any total sizes,
279 // we can ignore the array size of the variable
280
281 if (variable->isStruct())
282 {
283 encoder->enterAggregateType();
284
Jamie Madillc600c8c2014-05-16 11:22:21 -0400285 variable->registerIndex = baseRegisterIndex;
286
Jamie Madill834e8b72014-04-11 13:33:58 -0400287 for (size_t fieldIndex = 0; fieldIndex < variable->fields.size(); fieldIndex++)
288 {
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400289 HLSLVariableGetRegisterInfo(baseRegisterIndex, &variable->fields[fieldIndex], encoder, blockInfo, outputType);
Jamie Madill834e8b72014-04-11 13:33:58 -0400290 }
291
Jamie Madillc600c8c2014-05-16 11:22:21 -0400292 // Since the above loop only encodes one element of an array, ensure we don't lose track of the
293 // current register offset
294 if (variable->isArray())
295 {
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400296 unsigned int structRegisterCount = (HLSLVariableRegisterCount(*variable, outputType) / variable->arraySize);
Jamie Madillc600c8c2014-05-16 11:22:21 -0400297 encoder->skipRegisters(structRegisterCount * (variable->arraySize - 1));
298 }
299
Jamie Madill834e8b72014-04-11 13:33:58 -0400300 encoder->exitAggregateType();
301 }
302 else
303 {
304 encoder->encodeType(variable->type, variable->arraySize, false);
305
306 const size_t registerBytes = (encoder->BytesPerComponent * encoder->ComponentsPerRegister);
307 variable->registerIndex = baseRegisterIndex + (blockInfo.back().offset / registerBytes);
308 variable->elementIndex = (blockInfo.back().offset % registerBytes) / sizeof(float);
309 }
310}
311
Jamie Madillf2575982014-06-25 16:04:54 -0400312void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, Uniform *variable, ShShaderOutput outputType)
Jamie Madill834e8b72014-04-11 13:33:58 -0400313{
314 std::vector<BlockMemberInfo> blockInfo;
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400315 HLSLBlockEncoder encoder(&blockInfo,
316 outputType == SH_HLSL9_OUTPUT ? HLSLBlockEncoder::ENCODE_LOOSE
317 : HLSLBlockEncoder::ENCODE_PACKED);
318 HLSLVariableGetRegisterInfo(baseRegisterIndex, variable, &encoder, blockInfo, outputType);
Jamie Madill834e8b72014-04-11 13:33:58 -0400319}
320
321template <class ShaderVarType>
322void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder)
323{
324 if (variable.isStruct())
325 {
326 for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++)
327 {
328 encoder->enterAggregateType();
329
330 for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++)
331 {
332 HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder);
333 }
334
335 encoder->exitAggregateType();
336 }
337 }
338 else
339 {
340 // We operate only on varyings and uniforms, which do not have matrix layout qualifiers
341 encoder->encodeType(variable.type, variable.arraySize, false);
342 }
343}
344
345unsigned int HLSLVariableRegisterCount(const Varying &variable)
346{
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400347 HLSLBlockEncoder encoder(NULL, HLSLBlockEncoder::ENCODE_PACKED);
Jamie Madill834e8b72014-04-11 13:33:58 -0400348 HLSLVariableRegisterCount(variable, &encoder);
349
350 const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
351 return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
352}
353
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400354unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType)
Jamie Madill834e8b72014-04-11 13:33:58 -0400355{
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400356 HLSLBlockEncoder encoder(NULL,
357 outputType == SH_HLSL9_OUTPUT ? HLSLBlockEncoder::ENCODE_LOOSE
358 : HLSLBlockEncoder::ENCODE_PACKED);
359
Jamie Madill834e8b72014-04-11 13:33:58 -0400360 HLSLVariableRegisterCount(variable, &encoder);
361
362 const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
363 return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
364}
365
366}