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
ExpandStructVariable(const ShaderVariable & variable,const std::string & name,std::vector<ShaderVariable> * expanded)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
ExpandStructArrayVariable(const ShaderVariable & variable,unsigned int arrayNestingIndex,const std::string & name,std::vector<ShaderVariable> * expanded)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
ExpandVariable(const ShaderVariable & variable,const std::string & name,std::vector<ShaderVariable> * expanded)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
GetVariablePackingRows(const ShaderVariable & variable)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 {
operator ()sh::__anone7e802c40111::TVariableInfoComparer116 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
makeColumnFlags(int column,int numComponentsPerRow)129 unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow)
130 {
131 return ((kColumnMask << (kNumColumns - numComponentsPerRow)) & kColumnMask) >> column;
132 }
133
fillColumns(int topRow,int numRows,int column,int numComponentsPerRow)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
searchColumn(int column,int numRows,int * destRow,int * destSize)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
checkExpandedVariablesWithinPackingLimits(unsigned int maxVectors,std::vector<sh::ShaderVariable> * variables)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
GetTypePackingComponentsPerRow(sh::GLenum type)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
GetTypePackingRows(sh::GLenum type)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
CheckVariablesInPackingLimits(unsigned int maxVectors,const std::vector<ShaderVariable> & variables)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
410