blob: 1fa668b2143417473fa01cbe413e62234c2c434a [file] [log] [blame]
gman@chromium.org8d804792012-10-17 21:33:48 +00001//
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//
Olli Etuahod7487b12017-08-09 15:45:13 +03006// 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.
gman@chromium.org8d804792012-10-17 21:33:48 +00008
9#include <algorithm>
gman@chromium.org8d804792012-10-17 21:33:48 +000010
Jamie Madille294bb82014-07-17 14:16:26 -040011#include "angle_gl.h"
12
13#include "compiler/translator/VariablePacker.h"
14#include "common/utilities.h"
15
Olli Etuahod7487b12017-08-09 15:45:13 +030016namespace sh
gman@chromium.org8d804792012-10-17 21:33:48 +000017{
Olli Etuahod7487b12017-08-09 15:45:13 +030018
19namespace
20{
21
22void ExpandVariable(const ShaderVariable &variable,
23 const std::string &name,
24 const std::string &mappedName,
25 bool markStaticUse,
26 std::vector<ShaderVariable> *expanded);
27
28void ExpandUserDefinedVariable(const ShaderVariable &variable,
29 const std::string &name,
30 const std::string &mappedName,
31 bool markStaticUse,
32 std::vector<ShaderVariable> *expanded)
33{
34 ASSERT(variable.isStruct());
35
36 const std::vector<ShaderVariable> &fields = variable.fields;
37
38 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
Jamie Madillaa72d782014-07-02 15:31:19 -040039 {
Olli Etuahod7487b12017-08-09 15:45:13 +030040 const ShaderVariable &field = fields[fieldIndex];
41 ExpandVariable(field, name + "." + field.name, mappedName + "." + field.mappedName,
42 markStaticUse, expanded);
gman@chromium.org8d804792012-10-17 21:33:48 +000043 }
44}
45
Olli Etuahod7487b12017-08-09 15:45:13 +030046void ExpandVariable(const ShaderVariable &variable,
47 const std::string &name,
48 const std::string &mappedName,
49 bool markStaticUse,
50 std::vector<ShaderVariable> *expanded)
gman@chromium.org8d804792012-10-17 21:33:48 +000051{
Olli Etuahod7487b12017-08-09 15:45:13 +030052 if (variable.isStruct())
Jamie Madillaa72d782014-07-02 15:31:19 -040053 {
Olli Etuahod7487b12017-08-09 15:45:13 +030054 if (variable.isArray())
55 {
56 for (unsigned int elementIndex = 0; elementIndex < variable.elementCount();
57 elementIndex++)
58 {
59 std::string lname = name + ::ArrayString(elementIndex);
60 std::string lmappedName = mappedName + ::ArrayString(elementIndex);
61 ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded);
62 }
63 }
64 else
65 {
66 ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded);
67 }
68 }
69 else
70 {
71 ShaderVariable expandedVar = variable;
72
73 expandedVar.name = name;
74 expandedVar.mappedName = mappedName;
75
76 // Mark all expanded fields as used if the parent is used
77 if (markStaticUse)
78 {
79 expandedVar.staticUse = true;
80 }
81
82 if (expandedVar.isArray())
83 {
84 expandedVar.name += "[0]";
85 expandedVar.mappedName += "[0]";
86 }
87
88 expanded->push_back(expandedVar);
gman@chromium.org8d804792012-10-17 21:33:48 +000089 }
90}
91
Olli Etuahod7487b12017-08-09 15:45:13 +030092class VariablePacker
93{
94 public:
95 bool checkExpandedVariablesWithinPackingLimits(unsigned int maxVectors,
96 std::vector<sh::ShaderVariable> *variables);
97
98 private:
99 static const int kNumColumns = 4;
100 static const unsigned kColumnMask = (1 << kNumColumns) - 1;
101
102 unsigned makeColumnFlags(int column, int numComponentsPerRow);
103 void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow);
104 bool searchColumn(int column, int numRows, int *destRow, int *destSize);
105
106 int topNonFullRow_;
107 int bottomNonFullRow_;
108 int maxRows_;
109 std::vector<unsigned> rows_;
110};
111
Jamie Madill865d1452014-07-02 15:31:20 -0400112struct TVariableInfoComparer
113{
Jamie Madilla718c1e2014-07-02 15:31:22 -0400114 bool operator()(const sh::ShaderVariable &lhs, const sh::ShaderVariable &rhs) const
gman@chromium.org8d804792012-10-17 21:33:48 +0000115 {
Jamie Madill865d1452014-07-02 15:31:20 -0400116 int lhsSortOrder = gl::VariableSortOrder(lhs.type);
117 int rhsSortOrder = gl::VariableSortOrder(rhs.type);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500118 if (lhsSortOrder != rhsSortOrder)
119 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000120 return lhsSortOrder < rhsSortOrder;
121 }
122 // Sort by largest first.
Jamie Madilla718c1e2014-07-02 15:31:22 -0400123 return lhs.arraySize > rhs.arraySize;
gman@chromium.org8d804792012-10-17 21:33:48 +0000124 }
125};
126
127unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow)
128{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500129 return ((kColumnMask << (kNumColumns - numComponentsPerRow)) & kColumnMask) >> column;
gman@chromium.org8d804792012-10-17 21:33:48 +0000130}
131
132void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow)
133{
134 unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500135 for (int r = 0; r < numRows; ++r)
136 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000137 int row = topRow + r;
138 ASSERT((rows_[row] & columnFlags) == 0);
139 rows_[row] |= columnFlags;
140 }
141}
142
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500143bool VariablePacker::searchColumn(int column, int numRows, int *destRow, int *destSize)
gman@chromium.org8d804792012-10-17 21:33:48 +0000144{
145 ASSERT(destRow);
146
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500147 for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask; ++topNonFullRow_)
148 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000149 }
150
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500151 for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask; --bottomNonFullRow_)
152 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000153 }
154
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500155 if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows)
156 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000157 return false;
158 }
159
160 unsigned columnFlags = makeColumnFlags(column, 1);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500161 int topGoodRow = 0;
162 int smallestGoodTop = -1;
gman@chromium.org8d804792012-10-17 21:33:48 +0000163 int smallestGoodSize = maxRows_ + 1;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500164 int bottomRow = bottomNonFullRow_ + 1;
165 bool found = false;
166 for (int row = topNonFullRow_; row <= bottomRow; ++row)
167 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000168 bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500169 if (rowEmpty)
170 {
171 if (!found)
172 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000173 topGoodRow = row;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500174 found = true;
gman@chromium.org8d804792012-10-17 21:33:48 +0000175 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500176 }
177 else
178 {
179 if (found)
180 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000181 int size = row - topGoodRow;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500182 if (size >= numRows && size < smallestGoodSize)
183 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000184 smallestGoodSize = size;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500185 smallestGoodTop = topGoodRow;
gman@chromium.org8d804792012-10-17 21:33:48 +0000186 }
187 }
188 found = false;
189 }
190 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500191 if (smallestGoodTop < 0)
192 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000193 return false;
194 }
195
196 *destRow = smallestGoodTop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500197 if (destSize)
198 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000199 *destSize = smallestGoodSize;
200 }
201 return true;
202}
203
Olli Etuahod7487b12017-08-09 15:45:13 +0300204bool VariablePacker::checkExpandedVariablesWithinPackingLimits(
Corentin Walleze58e1412016-07-18 16:40:46 -0400205 unsigned int maxVectors,
Olli Etuahod7487b12017-08-09 15:45:13 +0300206 std::vector<sh::ShaderVariable> *variables)
gman@chromium.org8d804792012-10-17 21:33:48 +0000207{
208 ASSERT(maxVectors > 0);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500209 maxRows_ = maxVectors;
210 topNonFullRow_ = 0;
gman@chromium.org8d804792012-10-17 21:33:48 +0000211 bottomNonFullRow_ = maxRows_ - 1;
gman@chromium.org8d804792012-10-17 21:33:48 +0000212
Nicolas Capens1d1c1152014-02-26 11:00:28 -0500213 // Check whether each variable fits in the available vectors.
Olli Etuahod7487b12017-08-09 15:45:13 +0300214 for (const sh::ShaderVariable &variable : *variables)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500215 {
Olli Etuahod7487b12017-08-09 15:45:13 +0300216 // Structs should have been expanded before reaching here.
217 ASSERT(!variable.isStruct());
218 if (variable.elementCount() > maxVectors / GetVariablePackingRows(variable.type))
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500219 {
Nicolas Capens1d1c1152014-02-26 11:00:28 -0500220 return false;
221 }
222 }
223
gman@chromium.org8d804792012-10-17 21:33:48 +0000224 // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific
225 // order by type, then by size of array, largest first.
Olli Etuahod7487b12017-08-09 15:45:13 +0300226 std::sort(variables->begin(), variables->end(), TVariableInfoComparer());
gman@chromium.org8d804792012-10-17 21:33:48 +0000227 rows_.clear();
228 rows_.resize(maxVectors, 0);
229
230 // Packs the 4 column variables.
231 size_t ii = 0;
Olli Etuahod7487b12017-08-09 15:45:13 +0300232 for (; ii < variables->size(); ++ii)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500233 {
Olli Etuahod7487b12017-08-09 15:45:13 +0300234 const sh::ShaderVariable &variable = (*variables)[ii];
235 if (GetVariablePackingComponentsPerRow(variable.type) != 4)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500236 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000237 break;
238 }
Olli Etuahod7487b12017-08-09 15:45:13 +0300239 topNonFullRow_ += GetVariablePackingRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000240 }
241
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500242 if (topNonFullRow_ > maxRows_)
243 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000244 return false;
245 }
246
247 // Packs the 3 column variables.
248 int num3ColumnRows = 0;
Olli Etuahod7487b12017-08-09 15:45:13 +0300249 for (; ii < variables->size(); ++ii)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500250 {
Olli Etuahod7487b12017-08-09 15:45:13 +0300251 const sh::ShaderVariable &variable = (*variables)[ii];
252 if (GetVariablePackingComponentsPerRow(variable.type) != 3)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500253 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000254 break;
255 }
Olli Etuahod7487b12017-08-09 15:45:13 +0300256 num3ColumnRows += GetVariablePackingRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000257 }
258
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500259 if (topNonFullRow_ + num3ColumnRows > maxRows_)
260 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000261 return false;
262 }
263
264 fillColumns(topNonFullRow_, num3ColumnRows, 0, 3);
265
266 // Packs the 2 column variables.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500267 int top2ColumnRow = topNonFullRow_ + num3ColumnRows;
268 int twoColumnRowsAvailable = maxRows_ - top2ColumnRow;
gman@chromium.org8d804792012-10-17 21:33:48 +0000269 int rowsAvailableInColumns01 = twoColumnRowsAvailable;
270 int rowsAvailableInColumns23 = twoColumnRowsAvailable;
Olli Etuahod7487b12017-08-09 15:45:13 +0300271 for (; ii < variables->size(); ++ii)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500272 {
Olli Etuahod7487b12017-08-09 15:45:13 +0300273 const sh::ShaderVariable &variable = (*variables)[ii];
274 if (GetVariablePackingComponentsPerRow(variable.type) != 2)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500275 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000276 break;
277 }
Olli Etuahod7487b12017-08-09 15:45:13 +0300278 int numRows = GetVariablePackingRows(variable.type) * variable.elementCount();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500279 if (numRows <= rowsAvailableInColumns01)
280 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000281 rowsAvailableInColumns01 -= numRows;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500282 }
283 else if (numRows <= rowsAvailableInColumns23)
284 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000285 rowsAvailableInColumns23 -= numRows;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500286 }
287 else
288 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000289 return false;
290 }
291 }
292
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500293 int numRowsUsedInColumns01 = twoColumnRowsAvailable - rowsAvailableInColumns01;
294 int numRowsUsedInColumns23 = twoColumnRowsAvailable - rowsAvailableInColumns23;
gman@chromium.org8d804792012-10-17 21:33:48 +0000295 fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500296 fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23, 2, 2);
gman@chromium.org8d804792012-10-17 21:33:48 +0000297
298 // Packs the 1 column variables.
Olli Etuahod7487b12017-08-09 15:45:13 +0300299 for (; ii < variables->size(); ++ii)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500300 {
Olli Etuahod7487b12017-08-09 15:45:13 +0300301 const sh::ShaderVariable &variable = (*variables)[ii];
302 ASSERT(1 == GetVariablePackingComponentsPerRow(variable.type));
303 int numRows = GetVariablePackingRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000304 int smallestColumn = -1;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500305 int smallestSize = maxRows_ + 1;
306 int topRow = -1;
307 for (int column = 0; column < kNumColumns; ++column)
308 {
309 int row = 0;
gman@chromium.org8d804792012-10-17 21:33:48 +0000310 int size = 0;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500311 if (searchColumn(column, numRows, &row, &size))
312 {
313 if (size < smallestSize)
314 {
315 smallestSize = size;
gman@chromium.org8d804792012-10-17 21:33:48 +0000316 smallestColumn = column;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500317 topRow = row;
gman@chromium.org8d804792012-10-17 21:33:48 +0000318 }
319 }
320 }
321
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500322 if (smallestColumn < 0)
323 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000324 return false;
325 }
326
327 fillColumns(topRow, numRows, smallestColumn, 1);
328 }
329
Olli Etuahod7487b12017-08-09 15:45:13 +0300330 ASSERT(variables->size() == ii);
gman@chromium.org8d804792012-10-17 21:33:48 +0000331
332 return true;
333}
Olli Etuahod7487b12017-08-09 15:45:13 +0300334
335} // anonymous namespace
336
337int GetVariablePackingComponentsPerRow(sh::GLenum type)
338{
339 switch (type)
340 {
341 case GL_FLOAT_MAT4:
342 case GL_FLOAT_MAT2:
343 case GL_FLOAT_MAT2x4:
344 case GL_FLOAT_MAT3x4:
345 case GL_FLOAT_MAT4x2:
346 case GL_FLOAT_MAT4x3:
347 case GL_FLOAT_VEC4:
348 case GL_INT_VEC4:
349 case GL_BOOL_VEC4:
350 case GL_UNSIGNED_INT_VEC4:
351 return 4;
352 case GL_FLOAT_MAT3:
353 case GL_FLOAT_MAT2x3:
354 case GL_FLOAT_MAT3x2:
355 case GL_FLOAT_VEC3:
356 case GL_INT_VEC3:
357 case GL_BOOL_VEC3:
358 case GL_UNSIGNED_INT_VEC3:
359 return 3;
360 case GL_FLOAT_VEC2:
361 case GL_INT_VEC2:
362 case GL_BOOL_VEC2:
363 case GL_UNSIGNED_INT_VEC2:
364 return 2;
365 default:
366 ASSERT(gl::VariableComponentCount(type) == 1);
367 return 1;
368 }
369}
370
371int GetVariablePackingRows(sh::GLenum type)
372{
373 switch (type)
374 {
375 case GL_FLOAT_MAT4:
376 case GL_FLOAT_MAT2x4:
377 case GL_FLOAT_MAT3x4:
378 case GL_FLOAT_MAT4x3:
379 case GL_FLOAT_MAT4x2:
380 return 4;
381 case GL_FLOAT_MAT3:
382 case GL_FLOAT_MAT2x3:
383 case GL_FLOAT_MAT3x2:
384 return 3;
385 case GL_FLOAT_MAT2:
386 return 2;
387 default:
388 ASSERT(gl::VariableRowCount(type) == 1);
389 return 1;
390 }
391}
392
393template <typename T>
394bool CheckVariablesInPackingLimits(unsigned int maxVectors, const std::vector<T> &variables)
395{
396 VariablePacker packer;
397 std::vector<sh::ShaderVariable> expandedVariables;
398 for (const ShaderVariable &variable : variables)
399 {
400 ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse,
401 &expandedVariables);
402 }
403 return packer.checkExpandedVariablesWithinPackingLimits(maxVectors, &expandedVariables);
404}
405
406template bool CheckVariablesInPackingLimits<ShaderVariable>(
407 unsigned int maxVectors,
408 const std::vector<ShaderVariable> &variables);
409template bool CheckVariablesInPackingLimits<Uniform>(unsigned int maxVectors,
410 const std::vector<Uniform> &variables);
411
412} // namespace sh