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/shadervars.h" 12 #include "common/mathutil.h" 13 #include "common/utilities.h" 14 15 namespace gl 16 { 17 18 BlockLayoutEncoder::BlockLayoutEncoder(std::vector<BlockMemberInfo> *blockInfoOut) 19 : mCurrentOffset(0), 20 mBlockInfoOut(blockInfoOut) 21 { 22 } 23 24 void 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 48 void 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 66 void 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 83 void BlockLayoutEncoder::nextRegister() 84 { 85 mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, ComponentsPerRegister); 86 } 87 88 Std140BlockEncoder::Std140BlockEncoder(std::vector<BlockMemberInfo> *blockInfoOut) 89 : BlockLayoutEncoder(blockInfoOut) 90 { 91 } 92 93 void Std140BlockEncoder::enterAggregateType() 94 { 95 nextRegister(); 96 } 97 98 void Std140BlockEncoder::exitAggregateType() 99 { 100 nextRegister(); 101 } 102 103 void 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) 106 ASSERT(gl::UniformComponentSize(gl::UniformComponentType(type)) == BytesPerComponent); 107 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 { 130 const int numComponents = gl::UniformComponentCount(type); 131 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 140 void 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 { 154 mCurrentOffset += gl::UniformComponentCount(type); 155 } 156 } 157 158 HLSLBlockEncoder::HLSLBlockEncoder(std::vector<BlockMemberInfo> *blockInfoOut, HLSLBlockEncoderStrategy strategy) 159 : BlockLayoutEncoder(blockInfoOut), 160 mEncoderStrategy(strategy) 161 { 162 } 163 164 void HLSLBlockEncoder::enterAggregateType() 165 { 166 nextRegister(); 167 } 168 169 void HLSLBlockEncoder::exitAggregateType() 170 { 171 } 172 173 void 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) 176 ASSERT(gl::UniformComponentSize(gl::UniformComponentType(type)) == BytesPerComponent); 177 178 int matrixStride = 0; 179 int arrayStride = 0; 180 181 // 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) 187 { 188 nextRegister(); 189 } 190 191 if (gl::IsMatrixType(type)) 192 { 193 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 { 203 arrayStride = ComponentsPerRegister; 204 } 205 else if (isPacked()) 206 { 207 int numComponents = gl::UniformComponentCount(type); 208 if ((numComponents + (mCurrentOffset % ComponentsPerRegister)) > ComponentsPerRegister) 209 { 210 nextRegister(); 211 } 212 } 213 214 *matrixStrideOut = matrixStride; 215 *arrayStrideOut = arrayStride; 216 } 217 218 void 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 } 233 else if (isPacked()) 234 { 235 mCurrentOffset += gl::UniformComponentCount(type); 236 } 237 else 238 { 239 mCurrentOffset += ComponentsPerRegister; 240 } 241 } 242 243 void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters) 244 { 245 mCurrentOffset += (numRegisters * ComponentsPerRegister); 246 } 247 248 void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, gl::Uniform *variable, HLSLBlockEncoder *encoder, 249 const std::vector<gl::BlockMemberInfo> &blockInfo, ShShaderOutput outputType) 250 { 251 // because this method computes offsets (element indexes) instead of any total sizes, 252 // we can ignore the array size of the variable 253 254 if (variable->isStruct()) 255 { 256 encoder->enterAggregateType(); 257 258 variable->registerIndex = baseRegisterIndex; 259 260 for (size_t fieldIndex = 0; fieldIndex < variable->fields.size(); fieldIndex++) 261 { 262 HLSLVariableGetRegisterInfo(baseRegisterIndex, &variable->fields[fieldIndex], encoder, blockInfo, outputType); 263 } 264 265 // Since the above loop only encodes one element of an array, ensure we don't lose track of the 266 // current register offset 267 if (variable->isArray()) 268 { 269 unsigned int structRegisterCount = (HLSLVariableRegisterCount(*variable, outputType) / variable->arraySize); 270 encoder->skipRegisters(structRegisterCount * (variable->arraySize - 1)); 271 } 272 273 encoder->exitAggregateType(); 274 } 275 else 276 { 277 encoder->encodeType(variable->type, variable->arraySize, false); 278 279 const size_t registerBytes = (encoder->BytesPerComponent * encoder->ComponentsPerRegister); 280 variable->registerIndex = baseRegisterIndex + (blockInfo.back().offset / registerBytes); 281 variable->elementIndex = (blockInfo.back().offset % registerBytes) / sizeof(float); 282 } 283 } 284 285 void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, gl::Uniform *variable, ShShaderOutput outputType) 286 { 287 std::vector<BlockMemberInfo> blockInfo; 288 HLSLBlockEncoder encoder(&blockInfo, 289 outputType == SH_HLSL9_OUTPUT ? HLSLBlockEncoder::ENCODE_LOOSE 290 : HLSLBlockEncoder::ENCODE_PACKED); 291 HLSLVariableGetRegisterInfo(baseRegisterIndex, variable, &encoder, blockInfo, outputType); 292 } 293 294 template <class ShaderVarType> 295 void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder) 296 { 297 if (variable.isStruct()) 298 { 299 for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++) 300 { 301 encoder->enterAggregateType(); 302 303 for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++) 304 { 305 HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder); 306 } 307 308 encoder->exitAggregateType(); 309 } 310 } 311 else 312 { 313 // We operate only on varyings and uniforms, which do not have matrix layout qualifiers 314 encoder->encodeType(variable.type, variable.arraySize, false); 315 } 316 } 317 318 unsigned int HLSLVariableRegisterCount(const Varying &variable) 319 { 320 HLSLBlockEncoder encoder(NULL, HLSLBlockEncoder::ENCODE_PACKED); 321 HLSLVariableRegisterCount(variable, &encoder); 322 323 const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister); 324 return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes); 325 } 326 327 unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType) 328 { 329 HLSLBlockEncoder encoder(NULL, 330 outputType == SH_HLSL9_OUTPUT ? HLSLBlockEncoder::ENCODE_LOOSE 331 : HLSLBlockEncoder::ENCODE_PACKED); 332 333 HLSLVariableRegisterCount(variable, &encoder); 334 335 const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister); 336 return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes); 337 } 338 339 } 340