Home | History | Annotate | Download | only in translator
      1 //
      2 // Copyright (c) 2002-2012 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 
      7 #include <algorithm>
      8 
      9 #include "angle_gl.h"
     10 
     11 #include "compiler/translator/VariablePacker.h"
     12 #include "common/utilities.h"
     13 
     14 int VariablePacker::GetNumComponentsPerRow(sh::GLenum type)
     15 {
     16     switch (type)
     17     {
     18       case GL_FLOAT_MAT4:
     19       case GL_FLOAT_MAT2:
     20       case GL_FLOAT_MAT2x4:
     21       case GL_FLOAT_MAT3x4:
     22       case GL_FLOAT_MAT4x2:
     23       case GL_FLOAT_MAT4x3:
     24       case GL_FLOAT_VEC4:
     25       case GL_INT_VEC4:
     26       case GL_BOOL_VEC4:
     27       case GL_UNSIGNED_INT_VEC4:
     28         return 4;
     29       case GL_FLOAT_MAT3:
     30       case GL_FLOAT_MAT2x3:
     31       case GL_FLOAT_MAT3x2:
     32       case GL_FLOAT_VEC3:
     33       case GL_INT_VEC3:
     34       case GL_BOOL_VEC3:
     35       case GL_UNSIGNED_INT_VEC3:
     36         return 3;
     37       case GL_FLOAT_VEC2:
     38       case GL_INT_VEC2:
     39       case GL_BOOL_VEC2:
     40       case GL_UNSIGNED_INT_VEC2:
     41         return 2;
     42       default:
     43         ASSERT(gl::VariableComponentCount(type) == 1);
     44         return 1;
     45     }
     46 }
     47 
     48 int VariablePacker::GetNumRows(sh::GLenum type)
     49 {
     50     switch (type)
     51     {
     52       case GL_FLOAT_MAT4:
     53       case GL_FLOAT_MAT2x4:
     54       case GL_FLOAT_MAT3x4:
     55       case GL_FLOAT_MAT4x3:
     56       case GL_FLOAT_MAT4x2:
     57         return 4;
     58       case GL_FLOAT_MAT3:
     59       case GL_FLOAT_MAT2x3:
     60       case GL_FLOAT_MAT3x2:
     61         return 3;
     62       case GL_FLOAT_MAT2:
     63         return 2;
     64       default:
     65         ASSERT(gl::VariableRowCount(type) == 1);
     66         return 1;
     67     }
     68 }
     69 
     70 struct TVariableInfoComparer
     71 {
     72     bool operator()(const sh::ShaderVariable &lhs, const sh::ShaderVariable &rhs) const
     73     {
     74         int lhsSortOrder = gl::VariableSortOrder(lhs.type);
     75         int rhsSortOrder = gl::VariableSortOrder(rhs.type);
     76         if (lhsSortOrder != rhsSortOrder) {
     77             return lhsSortOrder < rhsSortOrder;
     78         }
     79         // Sort by largest first.
     80         return lhs.arraySize > rhs.arraySize;
     81     }
     82 };
     83 
     84 unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow)
     85 {
     86     return ((kColumnMask << (kNumColumns - numComponentsPerRow)) &
     87                     kColumnMask) >> column;
     88 }
     89 
     90 void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow)
     91 {
     92     unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow);
     93     for (int r = 0; r < numRows; ++r) {
     94         int row = topRow + r;
     95         ASSERT((rows_[row] & columnFlags) == 0);
     96         rows_[row] |= columnFlags;
     97     }
     98 }
     99 
    100 bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* destSize)
    101 {
    102     ASSERT(destRow);
    103 
    104     for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask;
    105          ++topNonFullRow_) {
    106     }
    107 
    108     for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask;
    109          --bottomNonFullRow_) {
    110     }
    111 
    112     if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) {
    113         return false;
    114     }
    115 
    116     unsigned columnFlags = makeColumnFlags(column, 1);
    117     int topGoodRow = 0;
    118     int smallestGoodTop = -1;
    119     int smallestGoodSize = maxRows_ + 1;
    120     int bottomRow = bottomNonFullRow_ + 1;
    121     bool found = false;
    122     for (int row = topNonFullRow_; row <= bottomRow; ++row) {
    123         bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false;
    124         if (rowEmpty) {
    125             if (!found) {
    126                 topGoodRow = row;
    127                 found = true;
    128             }
    129         } else {
    130             if (found) {
    131                 int size = row - topGoodRow;
    132                 if (size >= numRows && size < smallestGoodSize) {
    133                     smallestGoodSize = size;
    134                     smallestGoodTop = topGoodRow;
    135                 }
    136             }
    137             found = false;
    138         }
    139     }
    140     if (smallestGoodTop < 0) {
    141         return false;
    142     }
    143 
    144     *destRow = smallestGoodTop;
    145     if (destSize) {
    146         *destSize = smallestGoodSize;
    147     }
    148     return true;
    149 }
    150 
    151 template <typename VarT>
    152 bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int maxVectors,
    153                                                        const std::vector<VarT> &in_variables)
    154 {
    155     ASSERT(maxVectors > 0);
    156     maxRows_ = maxVectors;
    157     topNonFullRow_ = 0;
    158     bottomNonFullRow_ = maxRows_ - 1;
    159     std::vector<VarT> variables(in_variables);
    160 
    161     // Check whether each variable fits in the available vectors.
    162     for (size_t i = 0; i < variables.size(); i++) {
    163         const sh::ShaderVariable &variable = variables[i];
    164         if (variable.elementCount() > maxVectors / GetNumRows(variable.type)) {
    165             return false;
    166         }
    167     }
    168 
    169     // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific
    170     // order by type, then by size of array, largest first.
    171     std::sort(variables.begin(), variables.end(), TVariableInfoComparer());
    172     rows_.clear();
    173     rows_.resize(maxVectors, 0);
    174 
    175     // Packs the 4 column variables.
    176     size_t ii = 0;
    177     for (; ii < variables.size(); ++ii) {
    178         const sh::ShaderVariable &variable = variables[ii];
    179         if (GetNumComponentsPerRow(variable.type) != 4) {
    180             break;
    181         }
    182         topNonFullRow_ += GetNumRows(variable.type) * variable.elementCount();
    183     }
    184 
    185     if (topNonFullRow_ > maxRows_) {
    186         return false;
    187     }
    188 
    189     // Packs the 3 column variables.
    190     int num3ColumnRows = 0;
    191     for (; ii < variables.size(); ++ii) {
    192         const sh::ShaderVariable &variable = variables[ii];
    193         if (GetNumComponentsPerRow(variable.type) != 3) {
    194             break;
    195         }
    196         num3ColumnRows += GetNumRows(variable.type) * variable.elementCount();
    197     }
    198 
    199     if (topNonFullRow_ + num3ColumnRows > maxRows_) {
    200         return false;
    201     }
    202 
    203     fillColumns(topNonFullRow_, num3ColumnRows, 0, 3);
    204 
    205     // Packs the 2 column variables.
    206     int top2ColumnRow = topNonFullRow_ + num3ColumnRows;
    207     int twoColumnRowsAvailable = maxRows_ - top2ColumnRow;
    208     int rowsAvailableInColumns01 = twoColumnRowsAvailable;
    209     int rowsAvailableInColumns23 = twoColumnRowsAvailable;
    210     for (; ii < variables.size(); ++ii) {
    211         const sh::ShaderVariable &variable = variables[ii];
    212         if (GetNumComponentsPerRow(variable.type) != 2) {
    213             break;
    214         }
    215         int numRows = GetNumRows(variable.type) * variable.elementCount();
    216         if (numRows <= rowsAvailableInColumns01) {
    217             rowsAvailableInColumns01 -= numRows;
    218         } else if (numRows <= rowsAvailableInColumns23) {
    219             rowsAvailableInColumns23 -= numRows;
    220         } else {
    221             return false;
    222         }
    223     }
    224 
    225     int numRowsUsedInColumns01 =
    226         twoColumnRowsAvailable - rowsAvailableInColumns01;
    227     int numRowsUsedInColumns23 =
    228         twoColumnRowsAvailable - rowsAvailableInColumns23;
    229     fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2);
    230     fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23,
    231                 2, 2);
    232 
    233     // Packs the 1 column variables.
    234     for (; ii < variables.size(); ++ii) {
    235         const sh::ShaderVariable &variable = variables[ii];
    236         ASSERT(1 == GetNumComponentsPerRow(variable.type));
    237         int numRows = GetNumRows(variable.type) * variable.elementCount();
    238         int smallestColumn = -1;
    239         int smallestSize = maxRows_ + 1;
    240         int topRow = -1;
    241         for (int column = 0; column < kNumColumns; ++column) {
    242             int row = 0;
    243             int size = 0;
    244             if (searchColumn(column, numRows, &row, &size)) {
    245                 if (size < smallestSize) {
    246                     smallestSize = size;
    247                     smallestColumn = column;
    248                     topRow = row;
    249                 }
    250             }
    251         }
    252 
    253         if (smallestColumn < 0) {
    254             return false;
    255         }
    256 
    257         fillColumns(topRow, numRows, smallestColumn, 1);
    258     }
    259 
    260     ASSERT(variables.size() == ii);
    261 
    262     return true;
    263 }
    264 
    265 // Instantiate all possible variable packings
    266 template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::ShaderVariable> &);
    267 template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::Attribute> &);
    268 template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::Uniform> &);
    269 template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::Varying> &);
    270