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 #include "compiler/translator/VariablePacker.h" 7 8 #include <algorithm> 9 #include "compiler/translator/ShHandle.h" 10 11 namespace { 12 int GetSortOrder(ShDataType type) 13 { 14 switch (type) { 15 case SH_FLOAT_MAT4: 16 case SH_FLOAT_MAT2x4: 17 case SH_FLOAT_MAT3x4: 18 case SH_FLOAT_MAT4x2: 19 case SH_FLOAT_MAT4x3: 20 return 0; 21 case SH_FLOAT_MAT2: 22 return 1; 23 case SH_FLOAT_VEC4: 24 case SH_INT_VEC4: 25 case SH_BOOL_VEC4: 26 return 2; 27 case SH_FLOAT_MAT3: 28 case SH_FLOAT_MAT2x3: 29 case SH_FLOAT_MAT3x2: 30 return 3; 31 case SH_FLOAT_VEC3: 32 case SH_INT_VEC3: 33 case SH_BOOL_VEC3: 34 return 4; 35 case SH_FLOAT_VEC2: 36 case SH_INT_VEC2: 37 case SH_BOOL_VEC2: 38 return 5; 39 case SH_FLOAT: 40 case SH_INT: 41 case SH_BOOL: 42 case SH_SAMPLER_2D: 43 case SH_SAMPLER_CUBE: 44 case SH_SAMPLER_EXTERNAL_OES: 45 case SH_SAMPLER_2D_RECT_ARB: 46 return 6; 47 default: 48 ASSERT(false); 49 return 7; 50 } 51 } 52 } // namespace 53 54 int VariablePacker::GetNumComponentsPerRow(ShDataType type) 55 { 56 switch (type) { 57 case SH_FLOAT_MAT4: 58 case SH_FLOAT_MAT2: 59 case SH_FLOAT_MAT2x4: 60 case SH_FLOAT_MAT3x4: 61 case SH_FLOAT_MAT4x2: 62 case SH_FLOAT_MAT4x3: 63 case SH_FLOAT_VEC4: 64 case SH_INT_VEC4: 65 case SH_BOOL_VEC4: 66 return 4; 67 case SH_FLOAT_MAT3: 68 case SH_FLOAT_MAT2x3: 69 case SH_FLOAT_MAT3x2: 70 case SH_FLOAT_VEC3: 71 case SH_INT_VEC3: 72 case SH_BOOL_VEC3: 73 return 3; 74 case SH_FLOAT_VEC2: 75 case SH_INT_VEC2: 76 case SH_BOOL_VEC2: 77 return 2; 78 case SH_FLOAT: 79 case SH_INT: 80 case SH_BOOL: 81 case SH_SAMPLER_2D: 82 case SH_SAMPLER_CUBE: 83 case SH_SAMPLER_EXTERNAL_OES: 84 case SH_SAMPLER_2D_RECT_ARB: 85 return 1; 86 default: 87 ASSERT(false); 88 return 5; 89 } 90 } 91 92 int VariablePacker::GetNumRows(ShDataType type) 93 { 94 switch (type) { 95 case SH_FLOAT_MAT4: 96 case SH_FLOAT_MAT2x4: 97 case SH_FLOAT_MAT3x4: 98 case SH_FLOAT_MAT4x3: 99 case SH_FLOAT_MAT4x2: 100 return 4; 101 case SH_FLOAT_MAT3: 102 case SH_FLOAT_MAT2x3: 103 case SH_FLOAT_MAT3x2: 104 return 3; 105 case SH_FLOAT_MAT2: 106 return 2; 107 case SH_FLOAT_VEC4: 108 case SH_INT_VEC4: 109 case SH_BOOL_VEC4: 110 case SH_FLOAT_VEC3: 111 case SH_INT_VEC3: 112 case SH_BOOL_VEC3: 113 case SH_FLOAT_VEC2: 114 case SH_INT_VEC2: 115 case SH_BOOL_VEC2: 116 case SH_FLOAT: 117 case SH_INT: 118 case SH_BOOL: 119 case SH_SAMPLER_2D: 120 case SH_SAMPLER_CUBE: 121 case SH_SAMPLER_EXTERNAL_OES: 122 case SH_SAMPLER_2D_RECT_ARB: 123 return 1; 124 default: 125 ASSERT(false); 126 return 100000; 127 } 128 } 129 130 struct TVariableInfoComparer { 131 bool operator()(const TVariableInfo& lhs, const TVariableInfo& rhs) const 132 { 133 int lhsSortOrder = GetSortOrder(lhs.type); 134 int rhsSortOrder = GetSortOrder(rhs.type); 135 if (lhsSortOrder != rhsSortOrder) { 136 return lhsSortOrder < rhsSortOrder; 137 } 138 // Sort by largest first. 139 return lhs.size > rhs.size; 140 } 141 }; 142 143 unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow) 144 { 145 return ((kColumnMask << (kNumColumns - numComponentsPerRow)) & 146 kColumnMask) >> column; 147 } 148 149 void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow) 150 { 151 unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow); 152 for (int r = 0; r < numRows; ++r) { 153 int row = topRow + r; 154 ASSERT((rows_[row] & columnFlags) == 0); 155 rows_[row] |= columnFlags; 156 } 157 } 158 159 bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* destSize) 160 { 161 ASSERT(destRow); 162 163 for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask; 164 ++topNonFullRow_) { 165 } 166 167 for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask; 168 --bottomNonFullRow_) { 169 } 170 171 if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) { 172 return false; 173 } 174 175 unsigned columnFlags = makeColumnFlags(column, 1); 176 int topGoodRow = 0; 177 int smallestGoodTop = -1; 178 int smallestGoodSize = maxRows_ + 1; 179 int bottomRow = bottomNonFullRow_ + 1; 180 bool found = false; 181 for (int row = topNonFullRow_; row <= bottomRow; ++row) { 182 bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false; 183 if (rowEmpty) { 184 if (!found) { 185 topGoodRow = row; 186 found = true; 187 } 188 } else { 189 if (found) { 190 int size = row - topGoodRow; 191 if (size >= numRows && size < smallestGoodSize) { 192 smallestGoodSize = size; 193 smallestGoodTop = topGoodRow; 194 } 195 } 196 found = false; 197 } 198 } 199 if (smallestGoodTop < 0) { 200 return false; 201 } 202 203 *destRow = smallestGoodTop; 204 if (destSize) { 205 *destSize = smallestGoodSize; 206 } 207 return true; 208 } 209 210 bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVariableInfoList& in_variables) 211 { 212 ASSERT(maxVectors > 0); 213 maxRows_ = maxVectors; 214 topNonFullRow_ = 0; 215 bottomNonFullRow_ = maxRows_ - 1; 216 TVariableInfoList variables(in_variables); 217 218 // Check whether each variable fits in the available vectors. 219 for (size_t i = 0; i < variables.size(); i++) { 220 const TVariableInfo& variable = variables[i]; 221 if (variable.size > maxVectors / GetNumRows(variable.type)) { 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 const TVariableInfo& variable = variables[ii]; 236 if (GetNumComponentsPerRow(variable.type) != 4) { 237 break; 238 } 239 topNonFullRow_ += GetNumRows(variable.type) * variable.size; 240 } 241 242 if (topNonFullRow_ > maxRows_) { 243 return false; 244 } 245 246 // Packs the 3 column variables. 247 int num3ColumnRows = 0; 248 for (; ii < variables.size(); ++ii) { 249 const TVariableInfo& variable = variables[ii]; 250 if (GetNumComponentsPerRow(variable.type) != 3) { 251 break; 252 } 253 num3ColumnRows += GetNumRows(variable.type) * variable.size; 254 } 255 256 if (topNonFullRow_ + num3ColumnRows > maxRows_) { 257 return false; 258 } 259 260 fillColumns(topNonFullRow_, num3ColumnRows, 0, 3); 261 262 // Packs the 2 column variables. 263 int top2ColumnRow = topNonFullRow_ + num3ColumnRows; 264 int twoColumnRowsAvailable = maxRows_ - top2ColumnRow; 265 int rowsAvailableInColumns01 = twoColumnRowsAvailable; 266 int rowsAvailableInColumns23 = twoColumnRowsAvailable; 267 for (; ii < variables.size(); ++ii) { 268 const TVariableInfo& variable = variables[ii]; 269 if (GetNumComponentsPerRow(variable.type) != 2) { 270 break; 271 } 272 int numRows = GetNumRows(variable.type) * variable.size; 273 if (numRows <= rowsAvailableInColumns01) { 274 rowsAvailableInColumns01 -= numRows; 275 } else if (numRows <= rowsAvailableInColumns23) { 276 rowsAvailableInColumns23 -= numRows; 277 } else { 278 return false; 279 } 280 } 281 282 int numRowsUsedInColumns01 = 283 twoColumnRowsAvailable - rowsAvailableInColumns01; 284 int numRowsUsedInColumns23 = 285 twoColumnRowsAvailable - rowsAvailableInColumns23; 286 fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2); 287 fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23, 288 2, 2); 289 290 // Packs the 1 column variables. 291 for (; ii < variables.size(); ++ii) { 292 const TVariableInfo& variable = variables[ii]; 293 ASSERT(1 == GetNumComponentsPerRow(variable.type)); 294 int numRows = GetNumRows(variable.type) * variable.size; 295 int smallestColumn = -1; 296 int smallestSize = maxRows_ + 1; 297 int topRow = -1; 298 for (int column = 0; column < kNumColumns; ++column) { 299 int row = 0; 300 int size = 0; 301 if (searchColumn(column, numRows, &row, &size)) { 302 if (size < smallestSize) { 303 smallestSize = size; 304 smallestColumn = column; 305 topRow = row; 306 } 307 } 308 } 309 310 if (smallestColumn < 0) { 311 return false; 312 } 313 314 fillColumns(topRow, numRows, smallestColumn, 1); 315 } 316 317 ASSERT(variables.size() == ii); 318 319 return true; 320 } 321 322 323 324