1//
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/mathutil.h"
12#include "common/utilities.h"
13
14namespace sh
15{
16
17BlockLayoutEncoder::BlockLayoutEncoder()
18    : mCurrentOffset(0)
19{
20}
21
22BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix)
23{
24    int arrayStride;
25    int matrixStride;
26
27    getBlockLayoutInfo(type, arraySize, isRowMajorMatrix, &arrayStride, &matrixStride);
28
29    const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, isRowMajorMatrix);
30
31    advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride);
32
33    return memberInfo;
34}
35
36void BlockLayoutEncoder::nextRegister()
37{
38    mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, ComponentsPerRegister);
39}
40
41Std140BlockEncoder::Std140BlockEncoder()
42{
43}
44
45void Std140BlockEncoder::enterAggregateType()
46{
47    nextRegister();
48}
49
50void Std140BlockEncoder::exitAggregateType()
51{
52    nextRegister();
53}
54
55void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
56{
57    // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
58    ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent);
59
60    size_t baseAlignment = 0;
61    int matrixStride = 0;
62    int arrayStride = 0;
63
64    if (gl::IsMatrixType(type))
65    {
66        baseAlignment = ComponentsPerRegister;
67        matrixStride = ComponentsPerRegister;
68
69        if (arraySize > 0)
70        {
71            const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
72            arrayStride = ComponentsPerRegister * numRegisters;
73        }
74    }
75    else if (arraySize > 0)
76    {
77        baseAlignment = ComponentsPerRegister;
78        arrayStride = ComponentsPerRegister;
79    }
80    else
81    {
82        const int numComponents = gl::VariableComponentCount(type);
83        baseAlignment = (numComponents == 3 ? 4u : static_cast<size_t>(numComponents));
84    }
85
86    mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment);
87
88    *matrixStrideOut = matrixStride;
89    *arrayStrideOut = arrayStride;
90}
91
92void Std140BlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
93{
94    if (arraySize > 0)
95    {
96        mCurrentOffset += arrayStride * arraySize;
97    }
98    else if (gl::IsMatrixType(type))
99    {
100        ASSERT(matrixStride == ComponentsPerRegister);
101        const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
102        mCurrentOffset += ComponentsPerRegister * numRegisters;
103    }
104    else
105    {
106        mCurrentOffset += gl::VariableComponentCount(type);
107    }
108}
109
110HLSLBlockEncoder::HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy)
111    : mEncoderStrategy(strategy)
112{
113}
114
115void HLSLBlockEncoder::enterAggregateType()
116{
117    nextRegister();
118}
119
120void HLSLBlockEncoder::exitAggregateType()
121{
122}
123
124void HLSLBlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
125{
126    // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
127    ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent);
128
129    int matrixStride = 0;
130    int arrayStride = 0;
131
132    // if variables are not to be packed, or we're about to
133    // pack a matrix or array, skip to the start of the next
134    // register
135    if (!isPacked() ||
136        gl::IsMatrixType(type) ||
137        arraySize > 0)
138    {
139        nextRegister();
140    }
141
142    if (gl::IsMatrixType(type))
143    {
144        matrixStride = ComponentsPerRegister;
145
146        if (arraySize > 0)
147        {
148            const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
149            arrayStride = ComponentsPerRegister * numRegisters;
150        }
151    }
152    else if (arraySize > 0)
153    {
154        arrayStride = ComponentsPerRegister;
155    }
156    else if (isPacked())
157    {
158        int numComponents = gl::VariableComponentCount(type);
159        if ((numComponents + (mCurrentOffset % ComponentsPerRegister)) > ComponentsPerRegister)
160        {
161            nextRegister();
162        }
163    }
164
165    *matrixStrideOut = matrixStride;
166    *arrayStrideOut = arrayStride;
167}
168
169void HLSLBlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
170{
171    if (arraySize > 0)
172    {
173        mCurrentOffset += arrayStride * (arraySize - 1);
174    }
175
176    if (gl::IsMatrixType(type))
177    {
178        ASSERT(matrixStride == ComponentsPerRegister);
179        const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
180        const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix);
181        mCurrentOffset += ComponentsPerRegister * (numRegisters - 1);
182        mCurrentOffset += numComponents;
183    }
184    else if (isPacked())
185    {
186        mCurrentOffset += gl::VariableComponentCount(type);
187    }
188    else
189    {
190        mCurrentOffset += ComponentsPerRegister;
191    }
192}
193
194void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters)
195{
196    mCurrentOffset += (numRegisters * ComponentsPerRegister);
197}
198
199HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor(ShShaderOutput outputType)
200{
201    switch (outputType)
202    {
203      case SH_HLSL9_OUTPUT: return ENCODE_LOOSE;
204      case SH_HLSL11_OUTPUT: return ENCODE_PACKED;
205      default: UNREACHABLE(); return ENCODE_PACKED;
206    }
207}
208
209template <class ShaderVarType>
210void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder)
211{
212    if (variable.isStruct())
213    {
214        for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++)
215        {
216            encoder->enterAggregateType();
217
218            for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++)
219            {
220                HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder);
221            }
222
223            encoder->exitAggregateType();
224        }
225    }
226    else
227    {
228        // We operate only on varyings and uniforms, which do not have matrix layout qualifiers
229        encoder->encodeType(variable.type, variable.arraySize, false);
230    }
231}
232
233unsigned int HLSLVariableRegisterCount(const Varying &variable)
234{
235    HLSLBlockEncoder encoder(HLSLBlockEncoder::ENCODE_PACKED);
236    HLSLVariableRegisterCount(variable, &encoder);
237
238    const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
239    return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
240}
241
242unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType)
243{
244    HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType));
245    HLSLVariableRegisterCount(variable, &encoder);
246
247    const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
248    return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
249}
250
251}
252