blob: a981c8ae0b33e592fc6596619228a35543f73375 [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//
gman@chromium.org8d804792012-10-17 21:33:48 +00006
7#include <algorithm>
gman@chromium.org8d804792012-10-17 21:33:48 +00008
Jamie Madille294bb82014-07-17 14:16:26 -04009#include "angle_gl.h"
10
11#include "compiler/translator/VariablePacker.h"
12#include "common/utilities.h"
13
Jamie Madill183bde52014-07-02 15:31:19 -040014int VariablePacker::GetNumComponentsPerRow(sh::GLenum type)
gman@chromium.org8d804792012-10-17 21:33:48 +000015{
Jamie Madillaa72d782014-07-02 15:31:19 -040016 switch (type)
17 {
18 case GL_FLOAT_MAT4:
19 case GL_FLOAT_MAT2:
20 case GL_FLOAT_MAT2x4:
21 case GL_FLOAT_MAT3x4:
22 case GL_FLOAT_MAT4x2:
23 case GL_FLOAT_MAT4x3:
24 case GL_FLOAT_VEC4:
25 case GL_INT_VEC4:
26 case GL_BOOL_VEC4:
27 case GL_UNSIGNED_INT_VEC4:
28 return 4;
29 case GL_FLOAT_MAT3:
30 case GL_FLOAT_MAT2x3:
31 case GL_FLOAT_MAT3x2:
32 case GL_FLOAT_VEC3:
33 case GL_INT_VEC3:
34 case GL_BOOL_VEC3:
35 case GL_UNSIGNED_INT_VEC3:
36 return 3;
37 case GL_FLOAT_VEC2:
38 case GL_INT_VEC2:
39 case GL_BOOL_VEC2:
40 case GL_UNSIGNED_INT_VEC2:
41 return 2;
42 default:
43 ASSERT(gl::VariableComponentCount(type) == 1);
44 return 1;
gman@chromium.org8d804792012-10-17 21:33:48 +000045 }
46}
47
Jamie Madill183bde52014-07-02 15:31:19 -040048int VariablePacker::GetNumRows(sh::GLenum type)
gman@chromium.org8d804792012-10-17 21:33:48 +000049{
Jamie Madillaa72d782014-07-02 15:31:19 -040050 switch (type)
51 {
52 case GL_FLOAT_MAT4:
53 case GL_FLOAT_MAT2x4:
54 case GL_FLOAT_MAT3x4:
55 case GL_FLOAT_MAT4x3:
56 case GL_FLOAT_MAT4x2:
57 return 4;
58 case GL_FLOAT_MAT3:
59 case GL_FLOAT_MAT2x3:
60 case GL_FLOAT_MAT3x2:
61 return 3;
62 case GL_FLOAT_MAT2:
63 return 2;
64 default:
65 ASSERT(gl::VariableRowCount(type) == 1);
66 return 1;
gman@chromium.org8d804792012-10-17 21:33:48 +000067 }
68}
69
Jamie Madill865d1452014-07-02 15:31:20 -040070struct TVariableInfoComparer
71{
Jamie Madilla718c1e2014-07-02 15:31:22 -040072 bool operator()(const sh::ShaderVariable &lhs, const sh::ShaderVariable &rhs) const
gman@chromium.org8d804792012-10-17 21:33:48 +000073 {
Jamie Madill865d1452014-07-02 15:31:20 -040074 int lhsSortOrder = gl::VariableSortOrder(lhs.type);
75 int rhsSortOrder = gl::VariableSortOrder(rhs.type);
gman@chromium.org8d804792012-10-17 21:33:48 +000076 if (lhsSortOrder != rhsSortOrder) {
77 return lhsSortOrder < rhsSortOrder;
78 }
79 // Sort by largest first.
Jamie Madilla718c1e2014-07-02 15:31:22 -040080 return lhs.arraySize > rhs.arraySize;
gman@chromium.org8d804792012-10-17 21:33:48 +000081 }
82};
83
84unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow)
85{
86 return ((kColumnMask << (kNumColumns - numComponentsPerRow)) &
87 kColumnMask) >> column;
88}
89
90void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow)
91{
92 unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow);
93 for (int r = 0; r < numRows; ++r) {
94 int row = topRow + r;
95 ASSERT((rows_[row] & columnFlags) == 0);
96 rows_[row] |= columnFlags;
97 }
98}
99
100bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* destSize)
101{
102 ASSERT(destRow);
103
104 for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask;
105 ++topNonFullRow_) {
106 }
107
108 for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask;
109 --bottomNonFullRow_) {
110 }
111
112 if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) {
113 return false;
114 }
115
116 unsigned columnFlags = makeColumnFlags(column, 1);
117 int topGoodRow = 0;
118 int smallestGoodTop = -1;
119 int smallestGoodSize = maxRows_ + 1;
120 int bottomRow = bottomNonFullRow_ + 1;
121 bool found = false;
122 for (int row = topNonFullRow_; row <= bottomRow; ++row) {
123 bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false;
124 if (rowEmpty) {
125 if (!found) {
126 topGoodRow = row;
127 found = true;
128 }
129 } else {
130 if (found) {
131 int size = row - topGoodRow;
132 if (size >= numRows && size < smallestGoodSize) {
133 smallestGoodSize = size;
134 smallestGoodTop = topGoodRow;
135 }
136 }
137 found = false;
138 }
139 }
140 if (smallestGoodTop < 0) {
141 return false;
142 }
143
144 *destRow = smallestGoodTop;
145 if (destSize) {
146 *destSize = smallestGoodSize;
147 }
148 return true;
149}
150
Corentin Walleze58e1412016-07-18 16:40:46 -0400151bool VariablePacker::CheckVariablesWithinPackingLimits(
152 unsigned int maxVectors,
153 const std::vector<sh::ShaderVariable> &in_variables)
gman@chromium.org8d804792012-10-17 21:33:48 +0000154{
155 ASSERT(maxVectors > 0);
156 maxRows_ = maxVectors;
157 topNonFullRow_ = 0;
158 bottomNonFullRow_ = maxRows_ - 1;
Corentin Walleze58e1412016-07-18 16:40:46 -0400159 std::vector<sh::ShaderVariable> variables;
160
161 for (const auto &variable : in_variables)
162 {
163 ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse,
164 &variables);
165 }
gman@chromium.org8d804792012-10-17 21:33:48 +0000166
Nicolas Capens1d1c1152014-02-26 11:00:28 -0500167 // Check whether each variable fits in the available vectors.
168 for (size_t i = 0; i < variables.size(); i++) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400169 const sh::ShaderVariable &variable = variables[i];
170 if (variable.elementCount() > maxVectors / GetNumRows(variable.type)) {
Nicolas Capens1d1c1152014-02-26 11:00:28 -0500171 return false;
172 }
173 }
174
gman@chromium.org8d804792012-10-17 21:33:48 +0000175 // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific
176 // order by type, then by size of array, largest first.
177 std::sort(variables.begin(), variables.end(), TVariableInfoComparer());
178 rows_.clear();
179 rows_.resize(maxVectors, 0);
180
181 // Packs the 4 column variables.
182 size_t ii = 0;
183 for (; ii < variables.size(); ++ii) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400184 const sh::ShaderVariable &variable = variables[ii];
gman@chromium.org8d804792012-10-17 21:33:48 +0000185 if (GetNumComponentsPerRow(variable.type) != 4) {
186 break;
187 }
Jamie Madilla718c1e2014-07-02 15:31:22 -0400188 topNonFullRow_ += GetNumRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000189 }
190
191 if (topNonFullRow_ > maxRows_) {
192 return false;
193 }
194
195 // Packs the 3 column variables.
196 int num3ColumnRows = 0;
197 for (; ii < variables.size(); ++ii) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400198 const sh::ShaderVariable &variable = variables[ii];
gman@chromium.org8d804792012-10-17 21:33:48 +0000199 if (GetNumComponentsPerRow(variable.type) != 3) {
200 break;
201 }
Jamie Madilla718c1e2014-07-02 15:31:22 -0400202 num3ColumnRows += GetNumRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000203 }
204
205 if (topNonFullRow_ + num3ColumnRows > maxRows_) {
206 return false;
207 }
208
209 fillColumns(topNonFullRow_, num3ColumnRows, 0, 3);
210
211 // Packs the 2 column variables.
212 int top2ColumnRow = topNonFullRow_ + num3ColumnRows;
213 int twoColumnRowsAvailable = maxRows_ - top2ColumnRow;
214 int rowsAvailableInColumns01 = twoColumnRowsAvailable;
215 int rowsAvailableInColumns23 = twoColumnRowsAvailable;
216 for (; ii < variables.size(); ++ii) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400217 const sh::ShaderVariable &variable = variables[ii];
gman@chromium.org8d804792012-10-17 21:33:48 +0000218 if (GetNumComponentsPerRow(variable.type) != 2) {
219 break;
220 }
Jamie Madilla718c1e2014-07-02 15:31:22 -0400221 int numRows = GetNumRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000222 if (numRows <= rowsAvailableInColumns01) {
223 rowsAvailableInColumns01 -= numRows;
224 } else if (numRows <= rowsAvailableInColumns23) {
225 rowsAvailableInColumns23 -= numRows;
226 } else {
227 return false;
228 }
229 }
230
231 int numRowsUsedInColumns01 =
232 twoColumnRowsAvailable - rowsAvailableInColumns01;
233 int numRowsUsedInColumns23 =
234 twoColumnRowsAvailable - rowsAvailableInColumns23;
235 fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2);
236 fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23,
237 2, 2);
238
239 // Packs the 1 column variables.
240 for (; ii < variables.size(); ++ii) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400241 const sh::ShaderVariable &variable = variables[ii];
gman@chromium.org8d804792012-10-17 21:33:48 +0000242 ASSERT(1 == GetNumComponentsPerRow(variable.type));
Jamie Madilla718c1e2014-07-02 15:31:22 -0400243 int numRows = GetNumRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000244 int smallestColumn = -1;
245 int smallestSize = maxRows_ + 1;
246 int topRow = -1;
247 for (int column = 0; column < kNumColumns; ++column) {
248 int row = 0;
249 int size = 0;
250 if (searchColumn(column, numRows, &row, &size)) {
251 if (size < smallestSize) {
252 smallestSize = size;
253 smallestColumn = column;
254 topRow = row;
255 }
256 }
257 }
258
259 if (smallestColumn < 0) {
260 return false;
261 }
262
263 fillColumns(topRow, numRows, smallestColumn, 1);
264 }
265
266 ASSERT(variables.size() == ii);
267
268 return true;
269}