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 14 namespace sh 15 { 16 17 BlockLayoutEncoder::BlockLayoutEncoder() 18 : mCurrentOffset(0) 19 { 20 } 21 22 BlockMemberInfo 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 36 void BlockLayoutEncoder::nextRegister() 37 { 38 mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, ComponentsPerRegister); 39 } 40 41 Std140BlockEncoder::Std140BlockEncoder() 42 { 43 } 44 45 void Std140BlockEncoder::enterAggregateType() 46 { 47 nextRegister(); 48 } 49 50 void Std140BlockEncoder::exitAggregateType() 51 { 52 nextRegister(); 53 } 54 55 void 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 92 void 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 110 HLSLBlockEncoder::HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy) 111 : mEncoderStrategy(strategy) 112 { 113 } 114 115 void HLSLBlockEncoder::enterAggregateType() 116 { 117 nextRegister(); 118 } 119 120 void HLSLBlockEncoder::exitAggregateType() 121 { 122 } 123 124 void 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 169 void 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 194 void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters) 195 { 196 mCurrentOffset += (numRegisters * ComponentsPerRegister); 197 } 198 199 HLSLBlockEncoder::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 209 template <class ShaderVarType> 210 void 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 233 unsigned 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 242 unsigned 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