VariablePacker.cpp (12126B)
1 // 2 // Copyright 2002 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 // Check whether variables fit within packing limits according to the packing rules from the GLSL ES 7 // 1.00.17 spec, Appendix A, section 7. 8 9 #include <algorithm> 10 11 #include "angle_gl.h" 12 13 #include "common/utilities.h" 14 #include "compiler/translator/VariablePacker.h" 15 16 namespace sh 17 { 18 19 namespace 20 { 21 22 // Expand the variable so that struct variables are split into their individual fields. 23 // Will not set the mappedName or staticUse fields on the expanded variables. 24 void ExpandVariable(const ShaderVariable &variable, 25 const std::string &name, 26 std::vector<ShaderVariable> *expanded); 27 28 void ExpandStructVariable(const ShaderVariable &variable, 29 const std::string &name, 30 std::vector<ShaderVariable> *expanded) 31 { 32 ASSERT(variable.isStruct()); 33 34 const std::vector<ShaderVariable> &fields = variable.fields; 35 36 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) 37 { 38 const ShaderVariable &field = fields[fieldIndex]; 39 ExpandVariable(field, name + "." + field.name, expanded); 40 } 41 } 42 43 void ExpandStructArrayVariable(const ShaderVariable &variable, 44 unsigned int arrayNestingIndex, 45 const std::string &name, 46 std::vector<ShaderVariable> *expanded) 47 { 48 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the 49 // innermost. 50 const unsigned int currentArraySize = variable.getNestedArraySize(arrayNestingIndex); 51 for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement) 52 { 53 const std::string elementName = name + ArrayString(arrayElement); 54 if (arrayNestingIndex + 1u < variable.arraySizes.size()) 55 { 56 ExpandStructArrayVariable(variable, arrayNestingIndex + 1u, elementName, expanded); 57 } 58 else 59 { 60 ExpandStructVariable(variable, elementName, expanded); 61 } 62 } 63 } 64 65 void ExpandVariable(const ShaderVariable &variable, 66 const std::string &name, 67 std::vector<ShaderVariable> *expanded) 68 { 69 if (variable.isStruct()) 70 { 71 if (variable.isArray()) 72 { 73 ExpandStructArrayVariable(variable, 0u, name, expanded); 74 } 75 else 76 { 77 ExpandStructVariable(variable, name, expanded); 78 } 79 } 80 else 81 { 82 ShaderVariable expandedVar = variable; 83 expandedVar.name = name; 84 85 expanded->push_back(expandedVar); 86 } 87 } 88 89 int GetVariablePackingRows(const ShaderVariable &variable) 90 { 91 return GetTypePackingRows(variable.type) * variable.getArraySizeProduct(); 92 } 93 94 class VariablePacker 95 { 96 public: 97 bool checkExpandedVariablesWithinPackingLimits(unsigned int maxVectors, 98 std::vector<sh::ShaderVariable> *variables); 99 100 private: 101 static const int kNumColumns = 4; 102 static const unsigned kColumnMask = (1 << kNumColumns) - 1; 103 104 unsigned makeColumnFlags(int column, int numComponentsPerRow); 105 void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow); 106 bool searchColumn(int column, int numRows, int *destRow, int *destSize); 107 108 int topNonFullRow_; 109 int bottomNonFullRow_; 110 int maxRows_; 111 std::vector<unsigned> rows_; 112 }; 113 114 struct TVariableInfoComparer 115 { 116 bool operator()(const sh::ShaderVariable &lhs, const sh::ShaderVariable &rhs) const 117 { 118 int lhsSortOrder = gl::VariableSortOrder(lhs.type); 119 int rhsSortOrder = gl::VariableSortOrder(rhs.type); 120 if (lhsSortOrder != rhsSortOrder) 121 { 122 return lhsSortOrder < rhsSortOrder; 123 } 124 // Sort by largest first. 125 return lhs.getArraySizeProduct() > rhs.getArraySizeProduct(); 126 } 127 }; 128 129 unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow) 130 { 131 return ((kColumnMask << (kNumColumns - numComponentsPerRow)) & kColumnMask) >> column; 132 } 133 134 void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow) 135 { 136 unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow); 137 for (int r = 0; r < numRows; ++r) 138 { 139 int row = topRow + r; 140 ASSERT((rows_[row] & columnFlags) == 0); 141 rows_[row] |= columnFlags; 142 } 143 } 144 145 bool VariablePacker::searchColumn(int column, int numRows, int *destRow, int *destSize) 146 { 147 ASSERT(destRow); 148 149 for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask; ++topNonFullRow_) 150 { 151 } 152 153 for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask; --bottomNonFullRow_) 154 { 155 } 156 157 if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) 158 { 159 return false; 160 } 161 162 unsigned columnFlags = makeColumnFlags(column, 1); 163 int topGoodRow = 0; 164 int smallestGoodTop = -1; 165 int smallestGoodSize = maxRows_ + 1; 166 int bottomRow = bottomNonFullRow_ + 1; 167 bool found = false; 168 for (int row = topNonFullRow_; row <= bottomRow; ++row) 169 { 170 bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false; 171 if (rowEmpty) 172 { 173 if (!found) 174 { 175 topGoodRow = row; 176 found = true; 177 } 178 } 179 else 180 { 181 if (found) 182 { 183 int size = row - topGoodRow; 184 if (size >= numRows && size < smallestGoodSize) 185 { 186 smallestGoodSize = size; 187 smallestGoodTop = topGoodRow; 188 } 189 } 190 found = false; 191 } 192 } 193 if (smallestGoodTop < 0) 194 { 195 return false; 196 } 197 198 *destRow = smallestGoodTop; 199 if (destSize) 200 { 201 *destSize = smallestGoodSize; 202 } 203 return true; 204 } 205 206 bool VariablePacker::checkExpandedVariablesWithinPackingLimits( 207 unsigned int maxVectors, 208 std::vector<sh::ShaderVariable> *variables) 209 { 210 ASSERT(maxVectors > 0); 211 maxRows_ = maxVectors; 212 topNonFullRow_ = 0; 213 bottomNonFullRow_ = maxRows_ - 1; 214 215 // Check whether each variable fits in the available vectors. 216 for (const sh::ShaderVariable &variable : *variables) 217 { 218 // Structs should have been expanded before reaching here. 219 ASSERT(!variable.isStruct()); 220 if (variable.getArraySizeProduct() > maxVectors / GetTypePackingRows(variable.type)) 221 { 222 return false; 223 } 224 } 225 226 // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific 227 // order by type, then by size of array, largest first. 228 std::sort(variables->begin(), variables->end(), TVariableInfoComparer()); 229 rows_.clear(); 230 rows_.resize(maxVectors, 0); 231 232 // Packs the 4 column variables. 233 size_t ii = 0; 234 for (; ii < variables->size(); ++ii) 235 { 236 const sh::ShaderVariable &variable = (*variables)[ii]; 237 if (GetTypePackingComponentsPerRow(variable.type) != 4) 238 { 239 break; 240 } 241 topNonFullRow_ += GetVariablePackingRows(variable); 242 if (topNonFullRow_ > maxRows_) 243 { 244 return false; 245 } 246 } 247 248 // Packs the 3 column variables. 249 int num3ColumnRows = 0; 250 for (; ii < variables->size(); ++ii) 251 { 252 const sh::ShaderVariable &variable = (*variables)[ii]; 253 if (GetTypePackingComponentsPerRow(variable.type) != 3) 254 { 255 break; 256 } 257 258 num3ColumnRows += GetVariablePackingRows(variable); 259 if (topNonFullRow_ + num3ColumnRows > maxRows_) 260 { 261 return false; 262 } 263 } 264 265 fillColumns(topNonFullRow_, num3ColumnRows, 0, 3); 266 267 // Packs the 2 column variables. 268 int top2ColumnRow = topNonFullRow_ + num3ColumnRows; 269 int twoColumnRowsAvailable = maxRows_ - top2ColumnRow; 270 int rowsAvailableInColumns01 = twoColumnRowsAvailable; 271 int rowsAvailableInColumns23 = twoColumnRowsAvailable; 272 for (; ii < variables->size(); ++ii) 273 { 274 const sh::ShaderVariable &variable = (*variables)[ii]; 275 if (GetTypePackingComponentsPerRow(variable.type) != 2) 276 { 277 break; 278 } 279 int numRows = GetVariablePackingRows(variable); 280 if (numRows <= rowsAvailableInColumns01) 281 { 282 rowsAvailableInColumns01 -= numRows; 283 } 284 else if (numRows <= rowsAvailableInColumns23) 285 { 286 rowsAvailableInColumns23 -= numRows; 287 } 288 else 289 { 290 return false; 291 } 292 } 293 294 int numRowsUsedInColumns01 = twoColumnRowsAvailable - rowsAvailableInColumns01; 295 int numRowsUsedInColumns23 = twoColumnRowsAvailable - rowsAvailableInColumns23; 296 fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2); 297 fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23, 2, 2); 298 299 // Packs the 1 column variables. 300 for (; ii < variables->size(); ++ii) 301 { 302 const sh::ShaderVariable &variable = (*variables)[ii]; 303 ASSERT(1 == GetTypePackingComponentsPerRow(variable.type)); 304 int numRows = GetVariablePackingRows(variable); 305 int smallestColumn = -1; 306 int smallestSize = maxRows_ + 1; 307 int topRow = -1; 308 for (int column = 0; column < kNumColumns; ++column) 309 { 310 int row = 0; 311 int size = 0; 312 if (searchColumn(column, numRows, &row, &size)) 313 { 314 if (size < smallestSize) 315 { 316 smallestSize = size; 317 smallestColumn = column; 318 topRow = row; 319 } 320 } 321 } 322 323 if (smallestColumn < 0) 324 { 325 return false; 326 } 327 328 fillColumns(topRow, numRows, smallestColumn, 1); 329 } 330 331 ASSERT(variables->size() == ii); 332 333 return true; 334 } 335 336 } // anonymous namespace 337 338 int GetTypePackingComponentsPerRow(sh::GLenum type) 339 { 340 switch (type) 341 { 342 case GL_FLOAT_MAT4: 343 case GL_FLOAT_MAT2: 344 case GL_FLOAT_MAT2x4: 345 case GL_FLOAT_MAT3x4: 346 case GL_FLOAT_MAT4x2: 347 case GL_FLOAT_MAT4x3: 348 case GL_FLOAT_VEC4: 349 case GL_INT_VEC4: 350 case GL_BOOL_VEC4: 351 case GL_UNSIGNED_INT_VEC4: 352 return 4; 353 case GL_FLOAT_MAT3: 354 case GL_FLOAT_MAT2x3: 355 case GL_FLOAT_MAT3x2: 356 case GL_FLOAT_VEC3: 357 case GL_INT_VEC3: 358 case GL_BOOL_VEC3: 359 case GL_UNSIGNED_INT_VEC3: 360 return 3; 361 case GL_FLOAT_VEC2: 362 case GL_INT_VEC2: 363 case GL_BOOL_VEC2: 364 case GL_UNSIGNED_INT_VEC2: 365 return 2; 366 default: 367 ASSERT(gl::VariableComponentCount(type) == 1); 368 return 1; 369 } 370 } 371 372 int GetTypePackingRows(sh::GLenum type) 373 { 374 switch (type) 375 { 376 case GL_FLOAT_MAT4: 377 case GL_FLOAT_MAT2x4: 378 case GL_FLOAT_MAT3x4: 379 case GL_FLOAT_MAT4x3: 380 case GL_FLOAT_MAT4x2: 381 return 4; 382 case GL_FLOAT_MAT3: 383 case GL_FLOAT_MAT2x3: 384 case GL_FLOAT_MAT3x2: 385 return 3; 386 case GL_FLOAT_MAT2: 387 return 2; 388 default: 389 ASSERT(gl::VariableRowCount(type) == 1); 390 return 1; 391 } 392 } 393 394 bool CheckVariablesInPackingLimits(unsigned int maxVectors, 395 const std::vector<ShaderVariable> &variables) 396 { 397 VariablePacker packer; 398 std::vector<sh::ShaderVariable> expandedVariables; 399 for (const ShaderVariable &variable : variables) 400 { 401 ExpandVariable(variable, variable.name, &expandedVariables); 402 } 403 return packer.checkExpandedVariablesWithinPackingLimits(maxVectors, &expandedVariables); 404 } 405 406 bool CheckVariablesInPackingLimits(unsigned int maxVectors, 407 const std::vector<ShaderVariable> &variables); 408 409 } // namespace sh