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