blob: 0bdfa1e15156b79e2a89c0949f1b005a690ddb8b [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
Jamie Madillbf9cce22014-07-18 10:33:09 -0400164HLSLBlockEncoder::HLSLBlockEncoder(ShShaderOutput outputType)
165 : BlockLayoutEncoder(NULL),
166 mEncoderStrategy(GetStrategyFor(outputType))
167{
168}
169
Jamie Madill834e8b72014-04-11 13:33:58 -0400170void HLSLBlockEncoder::enterAggregateType()
171{
172 nextRegister();
173}
174
175void HLSLBlockEncoder::exitAggregateType()
176{
177}
178
179void HLSLBlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
180{
181 // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
Jamie Madillf2575982014-06-25 16:04:54 -0400182 ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent);
Jamie Madill834e8b72014-04-11 13:33:58 -0400183
184 int matrixStride = 0;
185 int arrayStride = 0;
186
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400187 // if variables are not to be packed, or we're about to
188 // pack a matrix or array, skip to the start of the next
189 // register
190 if (!isPacked() ||
191 gl::IsMatrixType(type) ||
192 arraySize > 0)
Jamie Madill834e8b72014-04-11 13:33:58 -0400193 {
194 nextRegister();
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400195 }
196
197 if (gl::IsMatrixType(type))
198 {
Jamie Madill834e8b72014-04-11 13:33:58 -0400199 matrixStride = ComponentsPerRegister;
200
201 if (arraySize > 0)
202 {
203 const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
204 arrayStride = ComponentsPerRegister * numRegisters;
205 }
206 }
207 else if (arraySize > 0)
208 {
Jamie Madill834e8b72014-04-11 13:33:58 -0400209 arrayStride = ComponentsPerRegister;
210 }
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400211 else if (isPacked())
Jamie Madill834e8b72014-04-11 13:33:58 -0400212 {
Jamie Madillf2575982014-06-25 16:04:54 -0400213 int numComponents = gl::VariableComponentCount(type);
Jamie Madill834e8b72014-04-11 13:33:58 -0400214 if ((numComponents + (mCurrentOffset % ComponentsPerRegister)) > ComponentsPerRegister)
215 {
216 nextRegister();
217 }
218 }
219
220 *matrixStrideOut = matrixStride;
221 *arrayStrideOut = arrayStride;
222}
223
224void HLSLBlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
225{
226 if (arraySize > 0)
227 {
228 mCurrentOffset += arrayStride * (arraySize - 1);
229 }
230
231 if (gl::IsMatrixType(type))
232 {
233 ASSERT(matrixStride == ComponentsPerRegister);
234 const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
235 const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix);
236 mCurrentOffset += ComponentsPerRegister * (numRegisters - 1);
237 mCurrentOffset += numComponents;
238 }
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400239 else if (isPacked())
Jamie Madill834e8b72014-04-11 13:33:58 -0400240 {
Jamie Madillf2575982014-06-25 16:04:54 -0400241 mCurrentOffset += gl::VariableComponentCount(type);
Jamie Madill834e8b72014-04-11 13:33:58 -0400242 }
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400243 else
244 {
245 mCurrentOffset += ComponentsPerRegister;
246 }
Jamie Madill834e8b72014-04-11 13:33:58 -0400247}
248
Jamie Madillc600c8c2014-05-16 11:22:21 -0400249void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters)
250{
251 mCurrentOffset += (numRegisters * ComponentsPerRegister);
252}
253
Jamie Madillbf9cce22014-07-18 10:33:09 -0400254HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor(ShShaderOutput outputType)
255{
256 switch (outputType)
257 {
258 case SH_HLSL9_OUTPUT: return ENCODE_LOOSE;
259 case SH_HLSL11_OUTPUT: return ENCODE_PACKED;
260 default: UNREACHABLE(); return ENCODE_PACKED;
261 }
262}
263
Jamie Madillfc43d272014-07-11 17:02:02 -0400264size_t HLSLInterfaceBlockDataSize(const sh::InterfaceBlock &interfaceBlock)
265{
266 switch (interfaceBlock.layout)
267 {
268 case BLOCKLAYOUT_SHARED:
269 case BLOCKLAYOUT_PACKED:
270 {
271 HLSLBlockEncoder hlslEncoder(NULL, HLSLBlockEncoder::ENCODE_PACKED);
272 hlslEncoder.encodeInterfaceBlockFields(interfaceBlock.fields);
273 return hlslEncoder.getBlockSize();
274 }
275 break;
276
277 case BLOCKLAYOUT_STANDARD:
278 {
279 Std140BlockEncoder stdEncoder(NULL);
280 stdEncoder.encodeInterfaceBlockFields(interfaceBlock.fields);
281 return stdEncoder.getBlockSize();
282 }
283 break;
284
285 default:
286 UNREACHABLE();
287 return 0;
288 }
289}
290
Jamie Madillf2575982014-06-25 16:04:54 -0400291void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, Uniform *variable, HLSLBlockEncoder *encoder,
292 const std::vector<BlockMemberInfo> &blockInfo, ShShaderOutput outputType)
Jamie Madill834e8b72014-04-11 13:33:58 -0400293{
294 // because this method computes offsets (element indexes) instead of any total sizes,
295 // we can ignore the array size of the variable
296
297 if (variable->isStruct())
298 {
299 encoder->enterAggregateType();
300
Jamie Madillc600c8c2014-05-16 11:22:21 -0400301 variable->registerIndex = baseRegisterIndex;
302
Jamie Madill834e8b72014-04-11 13:33:58 -0400303 for (size_t fieldIndex = 0; fieldIndex < variable->fields.size(); fieldIndex++)
304 {
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400305 HLSLVariableGetRegisterInfo(baseRegisterIndex, &variable->fields[fieldIndex], encoder, blockInfo, outputType);
Jamie Madill834e8b72014-04-11 13:33:58 -0400306 }
307
Jamie Madillc600c8c2014-05-16 11:22:21 -0400308 // Since the above loop only encodes one element of an array, ensure we don't lose track of the
309 // current register offset
310 if (variable->isArray())
311 {
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400312 unsigned int structRegisterCount = (HLSLVariableRegisterCount(*variable, outputType) / variable->arraySize);
Jamie Madillc600c8c2014-05-16 11:22:21 -0400313 encoder->skipRegisters(structRegisterCount * (variable->arraySize - 1));
314 }
315
Jamie Madill834e8b72014-04-11 13:33:58 -0400316 encoder->exitAggregateType();
317 }
318 else
319 {
320 encoder->encodeType(variable->type, variable->arraySize, false);
321
322 const size_t registerBytes = (encoder->BytesPerComponent * encoder->ComponentsPerRegister);
323 variable->registerIndex = baseRegisterIndex + (blockInfo.back().offset / registerBytes);
324 variable->elementIndex = (blockInfo.back().offset % registerBytes) / sizeof(float);
325 }
326}
327
Jamie Madillf2575982014-06-25 16:04:54 -0400328void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, Uniform *variable, ShShaderOutput outputType)
Jamie Madill834e8b72014-04-11 13:33:58 -0400329{
330 std::vector<BlockMemberInfo> blockInfo;
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400331 HLSLBlockEncoder encoder(&blockInfo,
332 outputType == SH_HLSL9_OUTPUT ? HLSLBlockEncoder::ENCODE_LOOSE
333 : HLSLBlockEncoder::ENCODE_PACKED);
334 HLSLVariableGetRegisterInfo(baseRegisterIndex, variable, &encoder, blockInfo, outputType);
Jamie Madill834e8b72014-04-11 13:33:58 -0400335}
336
337template <class ShaderVarType>
338void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder)
339{
340 if (variable.isStruct())
341 {
342 for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++)
343 {
344 encoder->enterAggregateType();
345
346 for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++)
347 {
348 HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder);
349 }
350
351 encoder->exitAggregateType();
352 }
353 }
354 else
355 {
356 // We operate only on varyings and uniforms, which do not have matrix layout qualifiers
357 encoder->encodeType(variable.type, variable.arraySize, false);
358 }
359}
360
361unsigned int HLSLVariableRegisterCount(const Varying &variable)
362{
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400363 HLSLBlockEncoder encoder(NULL, HLSLBlockEncoder::ENCODE_PACKED);
Jamie Madill834e8b72014-04-11 13:33:58 -0400364 HLSLVariableRegisterCount(variable, &encoder);
365
366 const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
367 return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
368}
369
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400370unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType)
Jamie Madill834e8b72014-04-11 13:33:58 -0400371{
Jamie Madillbf9cce22014-07-18 10:33:09 -0400372 HLSLBlockEncoder encoder(outputType);
Jamie Madill834e8b72014-04-11 13:33:58 -0400373 HLSLVariableRegisterCount(variable, &encoder);
374
375 const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
376 return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
377}
378
379}