Edit

kc3-lang/angle/src/common/blocklayout.cpp

Branch :

  • Show log

    Commit

  • Author : Vladimir Vukicevic
    Date : 2014-05-27 12:07:51
    Hash : 24d8d675
    Message : Fix register packing for structs in d3d9. Fixes WebGL test misc/shader-with-array-of-structs-uniform BUG=angle:656 Change-Id: If79a19db4d40bab9110422f7876de32e7f85e506 Reviewed-on: https://chromium-review.googlesource.com/200620 Tested-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Nicolas Capens <nicolascapens@chromium.org>

  • src/common/blocklayout.cpp
  • //
    // 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 "common/blocklayout.h"
    #include "common/shadervars.h"
    #include "common/mathutil.h"
    #include "common/utilities.h"
    
    namespace gl
    {
    
    BlockLayoutEncoder::BlockLayoutEncoder(std::vector<BlockMemberInfo> *blockInfoOut)
        : mCurrentOffset(0),
          mBlockInfoOut(blockInfoOut)
    {
    }
    
    void BlockLayoutEncoder::encodeInterfaceBlockFields(const std::vector<InterfaceBlockField> &fields)
    {
        for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
        {
            const InterfaceBlockField &variable = fields[fieldIndex];
    
            if (variable.fields.size() > 0)
            {
                const unsigned int elementCount = std::max(1u, variable.arraySize);
    
                for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
                {
                    enterAggregateType();
                    encodeInterfaceBlockFields(variable.fields);
                    exitAggregateType();
                }
            }
            else
            {
                encodeInterfaceBlockField(variable);
            }
        }
    }
    
    void BlockLayoutEncoder::encodeInterfaceBlockField(const InterfaceBlockField &field)
    {
        int arrayStride;
        int matrixStride;
    
        ASSERT(field.fields.empty());
        getBlockLayoutInfo(field.type, field.arraySize, field.isRowMajorMatrix, &arrayStride, &matrixStride);
    
        const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, field.isRowMajorMatrix);
    
        if (mBlockInfoOut)
        {
            mBlockInfoOut->push_back(memberInfo);
        }
    
        advanceOffset(field.type, field.arraySize, field.isRowMajorMatrix, arrayStride, matrixStride);
    }
    
    void BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix)
    {
        int arrayStride;
        int matrixStride;
    
        getBlockLayoutInfo(type, arraySize, isRowMajorMatrix, &arrayStride, &matrixStride);
    
        const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, isRowMajorMatrix);
    
        if (mBlockInfoOut)
        {
            mBlockInfoOut->push_back(memberInfo);
        }
    
        advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride);
    }
    
    void BlockLayoutEncoder::nextRegister()
    {
        mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, ComponentsPerRegister);
    }
    
    Std140BlockEncoder::Std140BlockEncoder(std::vector<BlockMemberInfo> *blockInfoOut)
        : BlockLayoutEncoder(blockInfoOut)
    {
    }
    
    void Std140BlockEncoder::enterAggregateType()
    {
        nextRegister();
    }
    
    void Std140BlockEncoder::exitAggregateType()
    {
        nextRegister();
    }
    
    void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
    {
        // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
        ASSERT(gl::UniformComponentSize(gl::UniformComponentType(type)) == BytesPerComponent);
    
        size_t baseAlignment = 0;
        int matrixStride = 0;
        int arrayStride = 0;
    
        if (gl::IsMatrixType(type))
        {
            baseAlignment = ComponentsPerRegister;
            matrixStride = ComponentsPerRegister;
    
            if (arraySize > 0)
            {
                const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
                arrayStride = ComponentsPerRegister * numRegisters;
            }
        }
        else if (arraySize > 0)
        {
            baseAlignment = ComponentsPerRegister;
            arrayStride = ComponentsPerRegister;
        }
        else
        {
            const int numComponents = gl::UniformComponentCount(type);
            baseAlignment = (numComponents == 3 ? 4u : static_cast<size_t>(numComponents));
        }
    
        mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment);
    
        *matrixStrideOut = matrixStride;
        *arrayStrideOut = arrayStride;
    }
    
    void Std140BlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
    {
        if (arraySize > 0)
        {
            mCurrentOffset += arrayStride * arraySize;
        }
        else if (gl::IsMatrixType(type))
        {
            ASSERT(matrixStride == ComponentsPerRegister);
            const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
            mCurrentOffset += ComponentsPerRegister * numRegisters;
        }
        else
        {
            mCurrentOffset += gl::UniformComponentCount(type);
        }
    }
    
    HLSLBlockEncoder::HLSLBlockEncoder(std::vector<BlockMemberInfo> *blockInfoOut, HLSLBlockEncoderStrategy strategy)
        : BlockLayoutEncoder(blockInfoOut),
          mEncoderStrategy(strategy)
    {
    }
    
    void HLSLBlockEncoder::enterAggregateType()
    {
        nextRegister();
    }
    
    void HLSLBlockEncoder::exitAggregateType()
    {
    }
    
    void HLSLBlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
    {
        // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
        ASSERT(gl::UniformComponentSize(gl::UniformComponentType(type)) == BytesPerComponent);
    
        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) ||
            arraySize > 0)
        {
            nextRegister();
        }
    
        if (gl::IsMatrixType(type))
        {
            matrixStride = ComponentsPerRegister;
    
            if (arraySize > 0)
            {
                const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
                arrayStride = ComponentsPerRegister * numRegisters;
            }
        }
        else if (arraySize > 0)
        {
            arrayStride = ComponentsPerRegister;
        }
        else if (isPacked())
        {
            int numComponents = gl::UniformComponentCount(type);
            if ((numComponents + (mCurrentOffset % ComponentsPerRegister)) > ComponentsPerRegister)
            {
                nextRegister();
            }
        }
    
        *matrixStrideOut = matrixStride;
        *arrayStrideOut = arrayStride;
    }
    
    void HLSLBlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
    {
        if (arraySize > 0)
        {
            mCurrentOffset += arrayStride * (arraySize - 1);
        }
    
        if (gl::IsMatrixType(type))
        {
            ASSERT(matrixStride == ComponentsPerRegister);
            const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
            const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix);
            mCurrentOffset += ComponentsPerRegister * (numRegisters - 1);
            mCurrentOffset += numComponents;
        }
        else if (isPacked())
        {
            mCurrentOffset += gl::UniformComponentCount(type);
        }
        else
        {
            mCurrentOffset += ComponentsPerRegister;
        }
    }
    
    void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters)
    {
        mCurrentOffset += (numRegisters * ComponentsPerRegister);
    }
    
    void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, gl::Uniform *variable, HLSLBlockEncoder *encoder,
                                     const std::vector<gl::BlockMemberInfo> &blockInfo, ShShaderOutput outputType)
    {
        // because this method computes offsets (element indexes) instead of any total sizes,
        // we can ignore the array size of the variable
    
        if (variable->isStruct())
        {
            encoder->enterAggregateType();
    
            variable->registerIndex = baseRegisterIndex;
    
            for (size_t fieldIndex = 0; fieldIndex < variable->fields.size(); fieldIndex++)
            {
                HLSLVariableGetRegisterInfo(baseRegisterIndex, &variable->fields[fieldIndex], encoder, blockInfo, outputType);
            }
    
            // Since the above loop only encodes one element of an array, ensure we don't lose track of the
            // current register offset
            if (variable->isArray())
            {
                unsigned int structRegisterCount = (HLSLVariableRegisterCount(*variable, outputType) / variable->arraySize);
                encoder->skipRegisters(structRegisterCount * (variable->arraySize - 1));
            }
    
            encoder->exitAggregateType();
        }
        else
        {
            encoder->encodeType(variable->type, variable->arraySize, false);
    
            const size_t registerBytes = (encoder->BytesPerComponent * encoder->ComponentsPerRegister);
            variable->registerIndex = baseRegisterIndex + (blockInfo.back().offset / registerBytes);
            variable->elementIndex = (blockInfo.back().offset % registerBytes) / sizeof(float);
        }
    }
    
    void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, gl::Uniform *variable, ShShaderOutput outputType)
    {
        std::vector<BlockMemberInfo> blockInfo;
        HLSLBlockEncoder encoder(&blockInfo,
                                 outputType == SH_HLSL9_OUTPUT ? HLSLBlockEncoder::ENCODE_LOOSE
                                                               : HLSLBlockEncoder::ENCODE_PACKED);
        HLSLVariableGetRegisterInfo(baseRegisterIndex, variable, &encoder, blockInfo, outputType);
    }
    
    template <class ShaderVarType>
    void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder)
    {
        if (variable.isStruct())
        {
            for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++)
            {
                encoder->enterAggregateType();
    
                for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++)
                {
                    HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder);
                }
    
                encoder->exitAggregateType();
            }
        }
        else
        {
            // We operate only on varyings and uniforms, which do not have matrix layout qualifiers
            encoder->encodeType(variable.type, variable.arraySize, false);
        }
    }
    
    unsigned int HLSLVariableRegisterCount(const Varying &variable)
    {
        HLSLBlockEncoder encoder(NULL, HLSLBlockEncoder::ENCODE_PACKED);
        HLSLVariableRegisterCount(variable, &encoder);
    
        const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
        return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
    }
    
    unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType)
    {
        HLSLBlockEncoder encoder(NULL,
                                 outputType == SH_HLSL9_OUTPUT ? HLSLBlockEncoder::ENCODE_LOOSE
                                                               : HLSLBlockEncoder::ENCODE_PACKED);
    
        HLSLVariableRegisterCount(variable, &encoder);
    
        const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
        return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
    }
    
    }