xref: /aosp_15_r20/external/angle/src/compiler/translator/VariablePacker.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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