Home | History | Annotate | Download | only in common
      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