| // |
| // Copyright (c) 2013-2014 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/blocklayout.h" |
| |
| #include "common/mathutil.h" |
| #include "common/utilities.h" |
| |
| namespace sh |
| { |
| |
| namespace |
| { |
| bool IsRowMajorLayout(const InterfaceBlockField &var) |
| { |
| return var.isRowMajorLayout; |
| } |
| |
| bool IsRowMajorLayout(const ShaderVariable &var) |
| { |
| return false; |
| } |
| |
| template <typename VarT> |
| void GetUniformBlockInfo(const std::vector<VarT> &fields, |
| const std::string &prefix, |
| sh::BlockLayoutEncoder *encoder, |
| bool inRowMajorLayout, |
| BlockLayoutMap *blockInfoOut); |
| |
| template <typename VarT> |
| void GetUniformBlockStructMemberInfo(const std::vector<VarT> &fields, |
| const std::string &fieldName, |
| sh::BlockLayoutEncoder *encoder, |
| bool inRowMajorLayout, |
| BlockLayoutMap *blockInfoOut) |
| { |
| encoder->enterAggregateType(); |
| GetUniformBlockInfo(fields, fieldName, encoder, inRowMajorLayout, blockInfoOut); |
| encoder->exitAggregateType(); |
| } |
| |
| template <typename VarT> |
| void GetUniformBlockStructArrayMemberInfo(const VarT &field, |
| unsigned int arrayNestingIndex, |
| const std::string &arrayName, |
| sh::BlockLayoutEncoder *encoder, |
| bool inRowMajorLayout, |
| BlockLayoutMap *blockInfoOut) |
| { |
| // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the |
| // innermost. |
| const unsigned int currentArraySize = field.getNestedArraySize(arrayNestingIndex); |
| for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement) |
| { |
| const std::string elementName = arrayName + ArrayString(arrayElement); |
| if (arrayNestingIndex + 1u < field.arraySizes.size()) |
| { |
| GetUniformBlockStructArrayMemberInfo(field, arrayNestingIndex + 1u, elementName, |
| encoder, inRowMajorLayout, blockInfoOut); |
| } |
| else |
| { |
| GetUniformBlockStructMemberInfo(field.fields, elementName, encoder, inRowMajorLayout, |
| blockInfoOut); |
| } |
| } |
| } |
| |
| template <typename VarT> |
| void GetUniformBlockArrayOfArraysMemberInfo(const VarT &field, |
| unsigned int arrayNestingIndex, |
| const std::string &arrayName, |
| sh::BlockLayoutEncoder *encoder, |
| bool isRowMajorMatrix, |
| BlockLayoutMap *blockInfoOut) |
| { |
| const unsigned int currentArraySize = field.getNestedArraySize(arrayNestingIndex); |
| for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement) |
| { |
| const std::string elementName = arrayName + ArrayString(arrayElement); |
| if (arrayNestingIndex + 2u < field.arraySizes.size()) |
| { |
| GetUniformBlockArrayOfArraysMemberInfo(field, arrayNestingIndex + 1u, elementName, |
| encoder, isRowMajorMatrix, blockInfoOut); |
| } |
| else |
| { |
| std::vector<unsigned int> innermostArraySize( |
| 1u, field.getNestedArraySize(arrayNestingIndex + 1u)); |
| (*blockInfoOut)[elementName] = |
| encoder->encodeType(field.type, innermostArraySize, isRowMajorMatrix); |
| } |
| } |
| } |
| |
| template <typename VarT> |
| void GetUniformBlockInfo(const std::vector<VarT> &fields, |
| const std::string &prefix, |
| sh::BlockLayoutEncoder *encoder, |
| bool inRowMajorLayout, |
| BlockLayoutMap *blockInfoOut) |
| { |
| for (const VarT &field : fields) |
| { |
| // Skip samplers. On Vulkan we use this for the default uniform block, so samplers may be |
| // included. |
| if (gl::IsSamplerType(field.type)) |
| { |
| continue; |
| } |
| |
| const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name); |
| |
| bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field)); |
| |
| if (field.isStruct()) |
| { |
| if (field.isArray()) |
| { |
| GetUniformBlockStructArrayMemberInfo(field, 0u, fieldName, encoder, rowMajorLayout, |
| blockInfoOut); |
| } |
| else |
| { |
| GetUniformBlockStructMemberInfo(field.fields, fieldName, encoder, rowMajorLayout, |
| blockInfoOut); |
| } |
| } |
| else if (field.isArrayOfArrays()) |
| { |
| GetUniformBlockArrayOfArraysMemberInfo(field, 0u, fieldName, encoder, |
| rowMajorLayout && gl::IsMatrixType(field.type), |
| blockInfoOut); |
| } |
| else |
| { |
| (*blockInfoOut)[fieldName] = encoder->encodeType( |
| field.type, field.arraySizes, rowMajorLayout && gl::IsMatrixType(field.type)); |
| } |
| } |
| } |
| |
| } // anonymous namespace |
| |
| BlockLayoutEncoder::BlockLayoutEncoder() : mCurrentOffset(0) |
| { |
| } |
| |
| BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, |
| const std::vector<unsigned int> &arraySizes, |
| bool isRowMajorMatrix) |
| { |
| int arrayStride; |
| int matrixStride; |
| |
| getBlockLayoutInfo(type, arraySizes, isRowMajorMatrix, &arrayStride, &matrixStride); |
| |
| const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * BytesPerComponent), |
| static_cast<int>(arrayStride * BytesPerComponent), |
| static_cast<int>(matrixStride * BytesPerComponent), |
| isRowMajorMatrix); |
| |
| advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride, matrixStride); |
| |
| return memberInfo; |
| } |
| |
| // static |
| size_t BlockLayoutEncoder::getBlockRegister(const BlockMemberInfo &info) |
| { |
| return (info.offset / BytesPerComponent) / ComponentsPerRegister; |
| } |
| |
| // static |
| size_t BlockLayoutEncoder::getBlockRegisterElement(const BlockMemberInfo &info) |
| { |
| return (info.offset / BytesPerComponent) % ComponentsPerRegister; |
| } |
| |
| void BlockLayoutEncoder::nextRegister() |
| { |
| mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, ComponentsPerRegister); |
| } |
| |
| Std140BlockEncoder::Std140BlockEncoder() |
| { |
| } |
| |
| void Std140BlockEncoder::enterAggregateType() |
| { |
| nextRegister(); |
| } |
| |
| void Std140BlockEncoder::exitAggregateType() |
| { |
| nextRegister(); |
| } |
| |
| void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, |
| const std::vector<unsigned int> &arraySizes, |
| bool isRowMajorMatrix, |
| int *arrayStrideOut, |
| int *matrixStrideOut) |
| { |
| // We assume we are only dealing with 4 byte components (no doubles or half-words currently) |
| ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent); |
| |
| size_t baseAlignment = 0; |
| int matrixStride = 0; |
| int arrayStride = 0; |
| |
| if (gl::IsMatrixType(type)) |
| { |
| baseAlignment = ComponentsPerRegister; |
| matrixStride = ComponentsPerRegister; |
| |
| if (!arraySizes.empty()) |
| { |
| const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); |
| arrayStride = ComponentsPerRegister * numRegisters; |
| } |
| } |
| else if (!arraySizes.empty()) |
| { |
| baseAlignment = ComponentsPerRegister; |
| arrayStride = ComponentsPerRegister; |
| } |
| else |
| { |
| const int numComponents = gl::VariableComponentCount(type); |
| baseAlignment = (numComponents == 3 ? 4u : static_cast<size_t>(numComponents)); |
| } |
| |
| mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment); |
| |
| *matrixStrideOut = matrixStride; |
| *arrayStrideOut = arrayStride; |
| } |
| |
| void Std140BlockEncoder::advanceOffset(GLenum type, |
| const std::vector<unsigned int> &arraySizes, |
| bool isRowMajorMatrix, |
| int arrayStride, |
| int matrixStride) |
| { |
| if (!arraySizes.empty()) |
| { |
| mCurrentOffset += arrayStride * gl::ArraySizeProduct(arraySizes); |
| } |
| else if (gl::IsMatrixType(type)) |
| { |
| ASSERT(matrixStride == ComponentsPerRegister); |
| const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); |
| mCurrentOffset += ComponentsPerRegister * numRegisters; |
| } |
| else |
| { |
| mCurrentOffset += gl::VariableComponentCount(type); |
| } |
| } |
| |
| void GetUniformBlockInfo(const std::vector<InterfaceBlockField> &fields, |
| const std::string &prefix, |
| sh::BlockLayoutEncoder *encoder, |
| BlockLayoutMap *blockInfoOut) |
| { |
| // Matrix packing is always recorded in individual fields, so they'll set the row major layout |
| // flag to true if needed. |
| GetUniformBlockInfo(fields, prefix, encoder, false, blockInfoOut); |
| } |
| |
| void GetUniformBlockInfo(const std::vector<Uniform> &uniforms, |
| const std::string &prefix, |
| sh::BlockLayoutEncoder *encoder, |
| BlockLayoutMap *blockInfoOut) |
| { |
| // Matrix packing is always recorded in individual fields, so they'll set the row major layout |
| // flag to true if needed. |
| GetUniformBlockInfo(uniforms, prefix, encoder, false, blockInfoOut); |
| } |
| |
| |
| } // namespace sh |