// // Copyright 2013 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // blocklayout.cpp: // Implementation for block layout classes and methods. // #include "compiler/translator/blocklayoutHLSL.h" #include "common/mathutil.h" #include "common/utilities.h" namespace sh { HLSLBlockEncoder::HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy, bool transposeMatrices) : mEncoderStrategy(strategy), mTransposeMatrices(transposeMatrices) {} void HLSLBlockEncoder::enterAggregateType(const ShaderVariable &structVar) { align(kComponentsPerRegister); } void HLSLBlockEncoder::exitAggregateType(const ShaderVariable &structVar) {} void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn, const std::vector &arraySizes, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) { GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn); // We assume we are only dealing with 4 byte components (no doubles or half-words currently) ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == kBytesPerComponent); int matrixStride = 0; int arrayStride = 0; // if variables are not to be packed, or we're about to // pack a matrix or array, skip to the start of the next // register if (!isPacked() || gl::IsMatrixType(type) || !arraySizes.empty()) { align(kComponentsPerRegister); } if (gl::IsMatrixType(type)) { matrixStride = kComponentsPerRegister; if (!arraySizes.empty()) { const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); arrayStride = kComponentsPerRegister * numRegisters; } } else if (!arraySizes.empty()) { arrayStride = kComponentsPerRegister; } else if (isPacked()) { int numComponents = gl::VariableComponentCount(type); if ((numComponents + (mCurrentOffset % kComponentsPerRegister)) > kComponentsPerRegister) { align(kComponentsPerRegister); } } *matrixStrideOut = matrixStride; *arrayStrideOut = arrayStride; } void HLSLBlockEncoder::advanceOffset(GLenum typeIn, const std::vector &arraySizes, bool isRowMajorMatrix, int arrayStride, int matrixStride) { GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn); if (!arraySizes.empty()) { unsigned int arraySize = gl::ArraySizeProduct(arraySizes); if (arraySize > 0) { mCurrentOffset += arrayStride * (arraySize - 1); } } if (gl::IsMatrixType(type)) { ASSERT(matrixStride == kComponentsPerRegister); const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix); mCurrentOffset += kComponentsPerRegister * (numRegisters - 1); mCurrentOffset += numComponents; } else if (isPacked()) { mCurrentOffset += gl::VariableComponentCount(type); } else { mCurrentOffset += kComponentsPerRegister; } } void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters) { mCurrentOffset += (numRegisters * kComponentsPerRegister); } HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor( ShShaderOutput outputType) { switch (outputType) { case SH_HLSL_3_0_OUTPUT: return ENCODE_LOOSE; case SH_HLSL_4_1_OUTPUT: case SH_HLSL_4_0_FL9_3_OUTPUT: return ENCODE_PACKED; default: UNREACHABLE(); return ENCODE_PACKED; } } template void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder) { if (variable.isStruct()) { for (size_t arrayElement = 0; arrayElement < variable.getArraySizeProduct(); arrayElement++) { encoder->enterAggregateType(variable); for (const ShaderVariable &field : variable.fields) { HLSLVariableRegisterCount(field, encoder); } encoder->exitAggregateType(variable); } } else { // We operate only on varyings and uniforms, which do not have matrix layout qualifiers encoder->encodeType(variable.type, variable.arraySizes, false); } } unsigned int HLSLVariableRegisterCount(const ShaderVariable &variable, ShShaderOutput outputType) { HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType), true); HLSLVariableRegisterCount(variable, &encoder); const size_t registerBytes = (encoder.kBytesPerComponent * encoder.kComponentsPerRegister); return static_cast( rx::roundUp(encoder.getCurrentOffset(), registerBytes) / registerBytes); } } // namespace sh