1 //
2 // Copyright 2013 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 "compiler/translator/blocklayoutHLSL.h"
11 
12 #include "common/mathutil.h"
13 #include "common/utilities.h"
14 
15 namespace sh
16 {
17 
HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy,bool transposeMatrices)18 HLSLBlockEncoder::HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy, bool transposeMatrices)
19     : mEncoderStrategy(strategy), mTransposeMatrices(transposeMatrices)
20 {}
21 
enterAggregateType(const ShaderVariable & structVar)22 void HLSLBlockEncoder::enterAggregateType(const ShaderVariable &structVar)
23 {
24     align(kComponentsPerRegister);
25 }
26 
exitAggregateType(const ShaderVariable & structVar)27 void HLSLBlockEncoder::exitAggregateType(const ShaderVariable &structVar) {}
28 
getBlockLayoutInfo(GLenum typeIn,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int * arrayStrideOut,int * matrixStrideOut)29 void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn,
30                                           const std::vector<unsigned int> &arraySizes,
31                                           bool isRowMajorMatrix,
32                                           int *arrayStrideOut,
33                                           int *matrixStrideOut)
34 {
35     GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn);
36 
37     // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
38     ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == kBytesPerComponent);
39 
40     int matrixStride = 0;
41     int arrayStride  = 0;
42 
43     // if variables are not to be packed, or we're about to
44     // pack a matrix or array, skip to the start of the next
45     // register
46     if (!isPacked() || gl::IsMatrixType(type) || !arraySizes.empty())
47     {
48         align(kComponentsPerRegister);
49     }
50 
51     if (gl::IsMatrixType(type))
52     {
53         matrixStride = kComponentsPerRegister;
54 
55         if (!arraySizes.empty())
56         {
57             const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
58             arrayStride            = kComponentsPerRegister * numRegisters;
59         }
60     }
61     else if (!arraySizes.empty())
62     {
63         arrayStride = kComponentsPerRegister;
64     }
65     else if (isPacked())
66     {
67         int numComponents = gl::VariableComponentCount(type);
68         if ((numComponents + (mCurrentOffset % kComponentsPerRegister)) > kComponentsPerRegister)
69         {
70             align(kComponentsPerRegister);
71         }
72     }
73 
74     *matrixStrideOut = matrixStride;
75     *arrayStrideOut  = arrayStride;
76 }
77 
advanceOffset(GLenum typeIn,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int arrayStride,int matrixStride)78 void HLSLBlockEncoder::advanceOffset(GLenum typeIn,
79                                      const std::vector<unsigned int> &arraySizes,
80                                      bool isRowMajorMatrix,
81                                      int arrayStride,
82                                      int matrixStride)
83 {
84     GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn);
85 
86     if (!arraySizes.empty())
87     {
88         unsigned int arraySize = gl::ArraySizeProduct(arraySizes);
89         if (arraySize > 0)
90         {
91             mCurrentOffset += arrayStride * (arraySize - 1);
92         }
93     }
94 
95     if (gl::IsMatrixType(type))
96     {
97         ASSERT(matrixStride == kComponentsPerRegister);
98         const int numRegisters  = gl::MatrixRegisterCount(type, isRowMajorMatrix);
99         const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix);
100         mCurrentOffset += kComponentsPerRegister * (numRegisters - 1);
101         mCurrentOffset += numComponents;
102     }
103     else if (isPacked())
104     {
105         mCurrentOffset += gl::VariableComponentCount(type);
106     }
107     else
108     {
109         mCurrentOffset += kComponentsPerRegister;
110     }
111 }
112 
skipRegisters(unsigned int numRegisters)113 void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters)
114 {
115     mCurrentOffset += (numRegisters * kComponentsPerRegister);
116 }
117 
GetStrategyFor(ShShaderOutput outputType)118 HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor(
119     ShShaderOutput outputType)
120 {
121     switch (outputType)
122     {
123         case SH_HLSL_3_0_OUTPUT:
124             return ENCODE_LOOSE;
125         case SH_HLSL_4_1_OUTPUT:
126         case SH_HLSL_4_0_FL9_3_OUTPUT:
127             return ENCODE_PACKED;
128         default:
129             UNREACHABLE();
130             return ENCODE_PACKED;
131     }
132 }
133 
134 template <class ShaderVarType>
HLSLVariableRegisterCount(const ShaderVarType & variable,HLSLBlockEncoder * encoder)135 void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder)
136 {
137     if (variable.isStruct())
138     {
139         for (size_t arrayElement = 0; arrayElement < variable.getArraySizeProduct(); arrayElement++)
140         {
141             encoder->enterAggregateType(variable);
142 
143             for (const ShaderVariable &field : variable.fields)
144             {
145                 HLSLVariableRegisterCount(field, encoder);
146             }
147 
148             encoder->exitAggregateType(variable);
149         }
150     }
151     else
152     {
153         // We operate only on varyings and uniforms, which do not have matrix layout qualifiers
154         encoder->encodeType(variable.type, variable.arraySizes, false);
155     }
156 }
157 
HLSLVariableRegisterCount(const ShaderVariable & variable,ShShaderOutput outputType)158 unsigned int HLSLVariableRegisterCount(const ShaderVariable &variable, ShShaderOutput outputType)
159 {
160     HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType), true);
161     HLSLVariableRegisterCount(variable, &encoder);
162 
163     const size_t registerBytes = (encoder.kBytesPerComponent * encoder.kComponentsPerRegister);
164     return static_cast<unsigned int>(
165         rx::roundUp<size_t>(encoder.getCurrentOffset(), registerBytes) / registerBytes);
166 }
167 }  // namespace sh
168