blob: faaf0115fc427e7c3130e68d58da20537b4a2e19 [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//
Geoff Lang17732822013-08-29 13:46:49 -04006#include "compiler/translator/VariablePacker.h"
Jamie Madill183bde52014-07-02 15:31:19 -04007#include "angle_gl.h"
Jamie Madillaa72d782014-07-02 15:31:19 -04008#include "common/utilities.h"
gman@chromium.org8d804792012-10-17 21:33:48 +00009
10#include <algorithm>
gman@chromium.org8d804792012-10-17 21:33:48 +000011
Jamie Madill183bde52014-07-02 15:31:19 -040012int VariablePacker::GetNumComponentsPerRow(sh::GLenum type)
gman@chromium.org8d804792012-10-17 21:33:48 +000013{
Jamie Madillaa72d782014-07-02 15:31:19 -040014 switch (type)
15 {
16 case GL_FLOAT_MAT4:
17 case GL_FLOAT_MAT2:
18 case GL_FLOAT_MAT2x4:
19 case GL_FLOAT_MAT3x4:
20 case GL_FLOAT_MAT4x2:
21 case GL_FLOAT_MAT4x3:
22 case GL_FLOAT_VEC4:
23 case GL_INT_VEC4:
24 case GL_BOOL_VEC4:
25 case GL_UNSIGNED_INT_VEC4:
26 return 4;
27 case GL_FLOAT_MAT3:
28 case GL_FLOAT_MAT2x3:
29 case GL_FLOAT_MAT3x2:
30 case GL_FLOAT_VEC3:
31 case GL_INT_VEC3:
32 case GL_BOOL_VEC3:
33 case GL_UNSIGNED_INT_VEC3:
34 return 3;
35 case GL_FLOAT_VEC2:
36 case GL_INT_VEC2:
37 case GL_BOOL_VEC2:
38 case GL_UNSIGNED_INT_VEC2:
39 return 2;
40 default:
41 ASSERT(gl::VariableComponentCount(type) == 1);
42 return 1;
gman@chromium.org8d804792012-10-17 21:33:48 +000043 }
44}
45
Jamie Madill183bde52014-07-02 15:31:19 -040046int VariablePacker::GetNumRows(sh::GLenum type)
gman@chromium.org8d804792012-10-17 21:33:48 +000047{
Jamie Madillaa72d782014-07-02 15:31:19 -040048 switch (type)
49 {
50 case GL_FLOAT_MAT4:
51 case GL_FLOAT_MAT2x4:
52 case GL_FLOAT_MAT3x4:
53 case GL_FLOAT_MAT4x3:
54 case GL_FLOAT_MAT4x2:
55 return 4;
56 case GL_FLOAT_MAT3:
57 case GL_FLOAT_MAT2x3:
58 case GL_FLOAT_MAT3x2:
59 return 3;
60 case GL_FLOAT_MAT2:
61 return 2;
62 default:
63 ASSERT(gl::VariableRowCount(type) == 1);
64 return 1;
gman@chromium.org8d804792012-10-17 21:33:48 +000065 }
66}
67
Jamie Madill865d1452014-07-02 15:31:20 -040068struct TVariableInfoComparer
69{
Jamie Madilla718c1e2014-07-02 15:31:22 -040070 bool operator()(const sh::ShaderVariable &lhs, const sh::ShaderVariable &rhs) const
gman@chromium.org8d804792012-10-17 21:33:48 +000071 {
Jamie Madill865d1452014-07-02 15:31:20 -040072 int lhsSortOrder = gl::VariableSortOrder(lhs.type);
73 int rhsSortOrder = gl::VariableSortOrder(rhs.type);
gman@chromium.org8d804792012-10-17 21:33:48 +000074 if (lhsSortOrder != rhsSortOrder) {
75 return lhsSortOrder < rhsSortOrder;
76 }
77 // Sort by largest first.
Jamie Madilla718c1e2014-07-02 15:31:22 -040078 return lhs.arraySize > rhs.arraySize;
gman@chromium.org8d804792012-10-17 21:33:48 +000079 }
80};
81
82unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow)
83{
84 return ((kColumnMask << (kNumColumns - numComponentsPerRow)) &
85 kColumnMask) >> column;
86}
87
88void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow)
89{
90 unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow);
91 for (int r = 0; r < numRows; ++r) {
92 int row = topRow + r;
93 ASSERT((rows_[row] & columnFlags) == 0);
94 rows_[row] |= columnFlags;
95 }
96}
97
98bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* destSize)
99{
100 ASSERT(destRow);
101
102 for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask;
103 ++topNonFullRow_) {
104 }
105
106 for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask;
107 --bottomNonFullRow_) {
108 }
109
110 if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) {
111 return false;
112 }
113
114 unsigned columnFlags = makeColumnFlags(column, 1);
115 int topGoodRow = 0;
116 int smallestGoodTop = -1;
117 int smallestGoodSize = maxRows_ + 1;
118 int bottomRow = bottomNonFullRow_ + 1;
119 bool found = false;
120 for (int row = topNonFullRow_; row <= bottomRow; ++row) {
121 bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false;
122 if (rowEmpty) {
123 if (!found) {
124 topGoodRow = row;
125 found = true;
126 }
127 } else {
128 if (found) {
129 int size = row - topGoodRow;
130 if (size >= numRows && size < smallestGoodSize) {
131 smallestGoodSize = size;
132 smallestGoodTop = topGoodRow;
133 }
134 }
135 found = false;
136 }
137 }
138 if (smallestGoodTop < 0) {
139 return false;
140 }
141
142 *destRow = smallestGoodTop;
143 if (destSize) {
144 *destSize = smallestGoodSize;
145 }
146 return true;
147}
148
Jamie Madilla718c1e2014-07-02 15:31:22 -0400149template <typename VarT>
150bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int maxVectors,
151 const std::vector<VarT> &in_variables)
gman@chromium.org8d804792012-10-17 21:33:48 +0000152{
153 ASSERT(maxVectors > 0);
154 maxRows_ = maxVectors;
155 topNonFullRow_ = 0;
156 bottomNonFullRow_ = maxRows_ - 1;
Jamie Madilla718c1e2014-07-02 15:31:22 -0400157 std::vector<VarT> variables(in_variables);
gman@chromium.org8d804792012-10-17 21:33:48 +0000158
Nicolas Capens1d1c1152014-02-26 11:00:28 -0500159 // Check whether each variable fits in the available vectors.
160 for (size_t i = 0; i < variables.size(); i++) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400161 const sh::ShaderVariable &variable = variables[i];
162 if (variable.elementCount() > maxVectors / GetNumRows(variable.type)) {
Nicolas Capens1d1c1152014-02-26 11:00:28 -0500163 return false;
164 }
165 }
166
gman@chromium.org8d804792012-10-17 21:33:48 +0000167 // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific
168 // order by type, then by size of array, largest first.
169 std::sort(variables.begin(), variables.end(), TVariableInfoComparer());
170 rows_.clear();
171 rows_.resize(maxVectors, 0);
172
173 // Packs the 4 column variables.
174 size_t ii = 0;
175 for (; ii < variables.size(); ++ii) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400176 const sh::ShaderVariable &variable = variables[ii];
gman@chromium.org8d804792012-10-17 21:33:48 +0000177 if (GetNumComponentsPerRow(variable.type) != 4) {
178 break;
179 }
Jamie Madilla718c1e2014-07-02 15:31:22 -0400180 topNonFullRow_ += GetNumRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000181 }
182
183 if (topNonFullRow_ > maxRows_) {
184 return false;
185 }
186
187 // Packs the 3 column variables.
188 int num3ColumnRows = 0;
189 for (; ii < variables.size(); ++ii) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400190 const sh::ShaderVariable &variable = variables[ii];
gman@chromium.org8d804792012-10-17 21:33:48 +0000191 if (GetNumComponentsPerRow(variable.type) != 3) {
192 break;
193 }
Jamie Madilla718c1e2014-07-02 15:31:22 -0400194 num3ColumnRows += GetNumRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000195 }
196
197 if (topNonFullRow_ + num3ColumnRows > maxRows_) {
198 return false;
199 }
200
201 fillColumns(topNonFullRow_, num3ColumnRows, 0, 3);
202
203 // Packs the 2 column variables.
204 int top2ColumnRow = topNonFullRow_ + num3ColumnRows;
205 int twoColumnRowsAvailable = maxRows_ - top2ColumnRow;
206 int rowsAvailableInColumns01 = twoColumnRowsAvailable;
207 int rowsAvailableInColumns23 = twoColumnRowsAvailable;
208 for (; ii < variables.size(); ++ii) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400209 const sh::ShaderVariable &variable = variables[ii];
gman@chromium.org8d804792012-10-17 21:33:48 +0000210 if (GetNumComponentsPerRow(variable.type) != 2) {
211 break;
212 }
Jamie Madilla718c1e2014-07-02 15:31:22 -0400213 int numRows = GetNumRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000214 if (numRows <= rowsAvailableInColumns01) {
215 rowsAvailableInColumns01 -= numRows;
216 } else if (numRows <= rowsAvailableInColumns23) {
217 rowsAvailableInColumns23 -= numRows;
218 } else {
219 return false;
220 }
221 }
222
223 int numRowsUsedInColumns01 =
224 twoColumnRowsAvailable - rowsAvailableInColumns01;
225 int numRowsUsedInColumns23 =
226 twoColumnRowsAvailable - rowsAvailableInColumns23;
227 fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2);
228 fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23,
229 2, 2);
230
231 // Packs the 1 column variables.
232 for (; ii < variables.size(); ++ii) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400233 const sh::ShaderVariable &variable = variables[ii];
gman@chromium.org8d804792012-10-17 21:33:48 +0000234 ASSERT(1 == GetNumComponentsPerRow(variable.type));
Jamie Madilla718c1e2014-07-02 15:31:22 -0400235 int numRows = GetNumRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000236 int smallestColumn = -1;
237 int smallestSize = maxRows_ + 1;
238 int topRow = -1;
239 for (int column = 0; column < kNumColumns; ++column) {
240 int row = 0;
241 int size = 0;
242 if (searchColumn(column, numRows, &row, &size)) {
243 if (size < smallestSize) {
244 smallestSize = size;
245 smallestColumn = column;
246 topRow = row;
247 }
248 }
249 }
250
251 if (smallestColumn < 0) {
252 return false;
253 }
254
255 fillColumns(topRow, numRows, smallestColumn, 1);
256 }
257
258 ASSERT(variables.size() == ii);
259
260 return true;
261}
262
Jamie Madilla718c1e2014-07-02 15:31:22 -0400263// Instantiate all possible variable packings
264template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::ShaderVariable> &);
265template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::Attribute> &);
266template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::Uniform> &);
267template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::Varying> &);