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/mathutil.h"
     12 #include "common/utilities.h"
     13 
     14 namespace sh
     15 {
     16 
     17 BlockLayoutEncoder::BlockLayoutEncoder()
     18     : mCurrentOffset(0)
     19 {
     20 }
     21 
     22 BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix)
     23 {
     24     int arrayStride;
     25     int matrixStride;
     26 
     27     getBlockLayoutInfo(type, arraySize, isRowMajorMatrix, &arrayStride, &matrixStride);
     28 
     29     const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, isRowMajorMatrix);
     30 
     31     advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride);
     32 
     33     return memberInfo;
     34 }
     35 
     36 void BlockLayoutEncoder::nextRegister()
     37 {
     38     mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, ComponentsPerRegister);
     39 }
     40 
     41 Std140BlockEncoder::Std140BlockEncoder()
     42 {
     43 }
     44 
     45 void Std140BlockEncoder::enterAggregateType()
     46 {
     47     nextRegister();
     48 }
     49 
     50 void Std140BlockEncoder::exitAggregateType()
     51 {
     52     nextRegister();
     53 }
     54 
     55 void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
     56 {
     57     // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
     58     ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent);
     59 
     60     size_t baseAlignment = 0;
     61     int matrixStride = 0;
     62     int arrayStride = 0;
     63 
     64     if (gl::IsMatrixType(type))
     65     {
     66         baseAlignment = ComponentsPerRegister;
     67         matrixStride = ComponentsPerRegister;
     68 
     69         if (arraySize > 0)
     70         {
     71             const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
     72             arrayStride = ComponentsPerRegister * numRegisters;
     73         }
     74     }
     75     else if (arraySize > 0)
     76     {
     77         baseAlignment = ComponentsPerRegister;
     78         arrayStride = ComponentsPerRegister;
     79     }
     80     else
     81     {
     82         const int numComponents = gl::VariableComponentCount(type);
     83         baseAlignment = (numComponents == 3 ? 4u : static_cast<size_t>(numComponents));
     84     }
     85 
     86     mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment);
     87 
     88     *matrixStrideOut = matrixStride;
     89     *arrayStrideOut = arrayStride;
     90 }
     91 
     92 void Std140BlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
     93 {
     94     if (arraySize > 0)
     95     {
     96         mCurrentOffset += arrayStride * arraySize;
     97     }
     98     else if (gl::IsMatrixType(type))
     99     {
    100         ASSERT(matrixStride == ComponentsPerRegister);
    101         const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
    102         mCurrentOffset += ComponentsPerRegister * numRegisters;
    103     }
    104     else
    105     {
    106         mCurrentOffset += gl::VariableComponentCount(type);
    107     }
    108 }
    109 
    110 HLSLBlockEncoder::HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy)
    111     : mEncoderStrategy(strategy)
    112 {
    113 }
    114 
    115 void HLSLBlockEncoder::enterAggregateType()
    116 {
    117     nextRegister();
    118 }
    119 
    120 void HLSLBlockEncoder::exitAggregateType()
    121 {
    122 }
    123 
    124 void HLSLBlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
    125 {
    126     // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
    127     ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent);
    128 
    129     int matrixStride = 0;
    130     int arrayStride = 0;
    131 
    132     // if variables are not to be packed, or we're about to
    133     // pack a matrix or array, skip to the start of the next
    134     // register
    135     if (!isPacked() ||
    136         gl::IsMatrixType(type) ||
    137         arraySize > 0)
    138     {
    139         nextRegister();
    140     }
    141 
    142     if (gl::IsMatrixType(type))
    143     {
    144         matrixStride = ComponentsPerRegister;
    145 
    146         if (arraySize > 0)
    147         {
    148             const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
    149             arrayStride = ComponentsPerRegister * numRegisters;
    150         }
    151     }
    152     else if (arraySize > 0)
    153     {
    154         arrayStride = ComponentsPerRegister;
    155     }
    156     else if (isPacked())
    157     {
    158         int numComponents = gl::VariableComponentCount(type);
    159         if ((numComponents + (mCurrentOffset % ComponentsPerRegister)) > ComponentsPerRegister)
    160         {
    161             nextRegister();
    162         }
    163     }
    164 
    165     *matrixStrideOut = matrixStride;
    166     *arrayStrideOut = arrayStride;
    167 }
    168 
    169 void HLSLBlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
    170 {
    171     if (arraySize > 0)
    172     {
    173         mCurrentOffset += arrayStride * (arraySize - 1);
    174     }
    175 
    176     if (gl::IsMatrixType(type))
    177     {
    178         ASSERT(matrixStride == ComponentsPerRegister);
    179         const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
    180         const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix);
    181         mCurrentOffset += ComponentsPerRegister * (numRegisters - 1);
    182         mCurrentOffset += numComponents;
    183     }
    184     else if (isPacked())
    185     {
    186         mCurrentOffset += gl::VariableComponentCount(type);
    187     }
    188     else
    189     {
    190         mCurrentOffset += ComponentsPerRegister;
    191     }
    192 }
    193 
    194 void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters)
    195 {
    196     mCurrentOffset += (numRegisters * ComponentsPerRegister);
    197 }
    198 
    199 HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor(ShShaderOutput outputType)
    200 {
    201     switch (outputType)
    202     {
    203       case SH_HLSL9_OUTPUT: return ENCODE_LOOSE;
    204       case SH_HLSL11_OUTPUT: return ENCODE_PACKED;
    205       default: UNREACHABLE(); return ENCODE_PACKED;
    206     }
    207 }
    208 
    209 template <class ShaderVarType>
    210 void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder)
    211 {
    212     if (variable.isStruct())
    213     {
    214         for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++)
    215         {
    216             encoder->enterAggregateType();
    217 
    218             for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++)
    219             {
    220                 HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder);
    221             }
    222 
    223             encoder->exitAggregateType();
    224         }
    225     }
    226     else
    227     {
    228         // We operate only on varyings and uniforms, which do not have matrix layout qualifiers
    229         encoder->encodeType(variable.type, variable.arraySize, false);
    230     }
    231 }
    232 
    233 unsigned int HLSLVariableRegisterCount(const Varying &variable)
    234 {
    235     HLSLBlockEncoder encoder(HLSLBlockEncoder::ENCODE_PACKED);
    236     HLSLVariableRegisterCount(variable, &encoder);
    237 
    238     const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
    239     return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
    240 }
    241 
    242 unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType)
    243 {
    244     HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType));
    245     HLSLVariableRegisterCount(variable, &encoder);
    246 
    247     const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
    248     return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
    249 }
    250 
    251 }
    252