blob: 2aa776fba131408c9d0a9f204d2320a950a7d8a2 [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"
Jamie Madill834e8b72014-04-11 13:33:58 -040011#include "common/mathutil.h"
12#include "common/utilities.h"
13
Jamie Madillf2575982014-06-25 16:04:54 -040014namespace sh
Jamie Madill834e8b72014-04-11 13:33:58 -040015{
16
Jamie Madille04a5b72014-07-18 10:33:12 -040017BlockLayoutEncoder::BlockLayoutEncoder()
Jamie Madill42bcf322014-08-25 16:20:46 -040018 : mCurrentOffset(0),
19 mInRowMajorField(false)
Jamie Madill834e8b72014-04-11 13:33:58 -040020{
21}
22
Jamie Madill42bcf322014-08-25 16:20:46 -040023template <typename VarT>
24void BlockLayoutEncoder::encodeVariables(const std::vector<VarT> &fields)
Jamie Madill834e8b72014-04-11 13:33:58 -040025{
26 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
27 {
Jamie Madill42bcf322014-08-25 16:20:46 -040028 const VarT &variable = fields[fieldIndex];
Jamie Madill834e8b72014-04-11 13:33:58 -040029
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();
Jamie Madill42bcf322014-08-25 16:20:46 -040037 encodeVariables(variable.fields);
Jamie Madill834e8b72014-04-11 13:33:58 -040038 exitAggregateType();
39 }
40 }
41 else
42 {
Jamie Madill42bcf322014-08-25 16:20:46 -040043 encodeVariable(variable);
Jamie Madill834e8b72014-04-11 13:33:58 -040044 }
45 }
46}
47
Jamie Madill42bcf322014-08-25 16:20:46 -040048// Only defined for interface block fields, and shader variable base
49template void BlockLayoutEncoder::encodeVariables(const std::vector<ShaderVariable> &);
50template void BlockLayoutEncoder::encodeVariables(const std::vector<InterfaceBlockField> &);
51
52BlockMemberInfo BlockLayoutEncoder::encodeVariable(const InterfaceBlockField &field)
53{
54 mInRowMajorField = field.isRowMajorMatrix;
55 return encodeVariable(static_cast<ShaderVariable>(field));
56}
57
58BlockMemberInfo BlockLayoutEncoder::encodeVariable(const sh::ShaderVariable &field)
Jamie Madill834e8b72014-04-11 13:33:58 -040059{
60 int arrayStride;
61 int matrixStride;
62
63 ASSERT(field.fields.empty());
Jamie Madill42bcf322014-08-25 16:20:46 -040064 getBlockLayoutInfo(field.type, field.arraySize, mInRowMajorField, &arrayStride, &matrixStride);
Jamie Madill834e8b72014-04-11 13:33:58 -040065
Jamie Madill42bcf322014-08-25 16:20:46 -040066 const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, mInRowMajorField);
Jamie Madill834e8b72014-04-11 13:33:58 -040067
Jamie Madill42bcf322014-08-25 16:20:46 -040068 advanceOffset(field.type, field.arraySize, mInRowMajorField, arrayStride, matrixStride);
Jamie Madille04a5b72014-07-18 10:33:12 -040069
70 return memberInfo;
Jamie Madill834e8b72014-04-11 13:33:58 -040071}
72
73void BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix)
74{
75 int arrayStride;
76 int matrixStride;
77
78 getBlockLayoutInfo(type, arraySize, isRowMajorMatrix, &arrayStride, &matrixStride);
79
80 const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, isRowMajorMatrix);
81
Jamie Madill834e8b72014-04-11 13:33:58 -040082 advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride);
83}
84
85void BlockLayoutEncoder::nextRegister()
86{
87 mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, ComponentsPerRegister);
88}
89
Jamie Madille04a5b72014-07-18 10:33:12 -040090Std140BlockEncoder::Std140BlockEncoder()
Jamie Madill834e8b72014-04-11 13:33:58 -040091{
92}
93
94void Std140BlockEncoder::enterAggregateType()
95{
96 nextRegister();
97}
98
99void Std140BlockEncoder::exitAggregateType()
100{
101 nextRegister();
102}
103
104void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
105{
106 // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
Jamie Madillf2575982014-06-25 16:04:54 -0400107 ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent);
Jamie Madill834e8b72014-04-11 13:33:58 -0400108
109 size_t baseAlignment = 0;
110 int matrixStride = 0;
111 int arrayStride = 0;
112
113 if (gl::IsMatrixType(type))
114 {
115 baseAlignment = ComponentsPerRegister;
116 matrixStride = ComponentsPerRegister;
117
118 if (arraySize > 0)
119 {
120 const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
121 arrayStride = ComponentsPerRegister * numRegisters;
122 }
123 }
124 else if (arraySize > 0)
125 {
126 baseAlignment = ComponentsPerRegister;
127 arrayStride = ComponentsPerRegister;
128 }
129 else
130 {
Jamie Madillf2575982014-06-25 16:04:54 -0400131 const int numComponents = gl::VariableComponentCount(type);
Jamie Madill834e8b72014-04-11 13:33:58 -0400132 baseAlignment = (numComponents == 3 ? 4u : static_cast<size_t>(numComponents));
133 }
134
135 mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment);
136
137 *matrixStrideOut = matrixStride;
138 *arrayStrideOut = arrayStride;
139}
140
141void Std140BlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
142{
143 if (arraySize > 0)
144 {
145 mCurrentOffset += arrayStride * arraySize;
146 }
147 else if (gl::IsMatrixType(type))
148 {
149 ASSERT(matrixStride == ComponentsPerRegister);
150 const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
151 mCurrentOffset += ComponentsPerRegister * numRegisters;
152 }
153 else
154 {
Jamie Madillf2575982014-06-25 16:04:54 -0400155 mCurrentOffset += gl::VariableComponentCount(type);
Jamie Madill834e8b72014-04-11 13:33:58 -0400156 }
157}
158
Jamie Madille04a5b72014-07-18 10:33:12 -0400159HLSLBlockEncoder::HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy)
160 : mEncoderStrategy(strategy)
Jamie Madillbf9cce22014-07-18 10:33:09 -0400161{
162}
163
Jamie Madill834e8b72014-04-11 13:33:58 -0400164void 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 Madillbf9cce22014-07-18 10:33:09 -0400248HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor(ShShaderOutput outputType)
249{
250 switch (outputType)
251 {
252 case SH_HLSL9_OUTPUT: return ENCODE_LOOSE;
253 case SH_HLSL11_OUTPUT: return ENCODE_PACKED;
254 default: UNREACHABLE(); return ENCODE_PACKED;
255 }
256}
257
Jamie Madill834e8b72014-04-11 13:33:58 -0400258template <class ShaderVarType>
259void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder)
260{
261 if (variable.isStruct())
262 {
263 for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++)
264 {
265 encoder->enterAggregateType();
266
267 for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++)
268 {
269 HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder);
270 }
271
272 encoder->exitAggregateType();
273 }
274 }
275 else
276 {
277 // We operate only on varyings and uniforms, which do not have matrix layout qualifiers
278 encoder->encodeType(variable.type, variable.arraySize, false);
279 }
280}
281
282unsigned int HLSLVariableRegisterCount(const Varying &variable)
283{
Jamie Madille04a5b72014-07-18 10:33:12 -0400284 HLSLBlockEncoder encoder(HLSLBlockEncoder::ENCODE_PACKED);
Jamie Madill834e8b72014-04-11 13:33:58 -0400285 HLSLVariableRegisterCount(variable, &encoder);
286
287 const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
288 return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
289}
290
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400291unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType)
Jamie Madill834e8b72014-04-11 13:33:58 -0400292{
Jamie Madille04a5b72014-07-18 10:33:12 -0400293 HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType));
Jamie Madill834e8b72014-04-11 13:33:58 -0400294 HLSLVariableRegisterCount(variable, &encoder);
295
296 const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
297 return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
298}
299
300}