blob: e69052162a6937e5d9cb1931275104126dfe0251 [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
Jamie Madilla718c1e2014-07-02 15:31:22 -0400151template <typename VarT>
152bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int maxVectors,
153 const std::vector<VarT> &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;
Jamie Madilla718c1e2014-07-02 15:31:22 -0400159 std::vector<VarT> variables(in_variables);
gman@chromium.org8d804792012-10-17 21:33:48 +0000160
Nicolas Capens1d1c1152014-02-26 11:00:28 -0500161 // Check whether each variable fits in the available vectors.
162 for (size_t i = 0; i < variables.size(); i++) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400163 const sh::ShaderVariable &variable = variables[i];
164 if (variable.elementCount() > maxVectors / GetNumRows(variable.type)) {
Nicolas Capens1d1c1152014-02-26 11:00:28 -0500165 return false;
166 }
167 }
168
gman@chromium.org8d804792012-10-17 21:33:48 +0000169 // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific
170 // order by type, then by size of array, largest first.
171 std::sort(variables.begin(), variables.end(), TVariableInfoComparer());
172 rows_.clear();
173 rows_.resize(maxVectors, 0);
174
175 // Packs the 4 column variables.
176 size_t ii = 0;
177 for (; ii < variables.size(); ++ii) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400178 const sh::ShaderVariable &variable = variables[ii];
gman@chromium.org8d804792012-10-17 21:33:48 +0000179 if (GetNumComponentsPerRow(variable.type) != 4) {
180 break;
181 }
Jamie Madilla718c1e2014-07-02 15:31:22 -0400182 topNonFullRow_ += GetNumRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000183 }
184
185 if (topNonFullRow_ > maxRows_) {
186 return false;
187 }
188
189 // Packs the 3 column variables.
190 int num3ColumnRows = 0;
191 for (; ii < variables.size(); ++ii) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400192 const sh::ShaderVariable &variable = variables[ii];
gman@chromium.org8d804792012-10-17 21:33:48 +0000193 if (GetNumComponentsPerRow(variable.type) != 3) {
194 break;
195 }
Jamie Madilla718c1e2014-07-02 15:31:22 -0400196 num3ColumnRows += GetNumRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000197 }
198
199 if (topNonFullRow_ + num3ColumnRows > maxRows_) {
200 return false;
201 }
202
203 fillColumns(topNonFullRow_, num3ColumnRows, 0, 3);
204
205 // Packs the 2 column variables.
206 int top2ColumnRow = topNonFullRow_ + num3ColumnRows;
207 int twoColumnRowsAvailable = maxRows_ - top2ColumnRow;
208 int rowsAvailableInColumns01 = twoColumnRowsAvailable;
209 int rowsAvailableInColumns23 = twoColumnRowsAvailable;
210 for (; ii < variables.size(); ++ii) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400211 const sh::ShaderVariable &variable = variables[ii];
gman@chromium.org8d804792012-10-17 21:33:48 +0000212 if (GetNumComponentsPerRow(variable.type) != 2) {
213 break;
214 }
Jamie Madilla718c1e2014-07-02 15:31:22 -0400215 int numRows = GetNumRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000216 if (numRows <= rowsAvailableInColumns01) {
217 rowsAvailableInColumns01 -= numRows;
218 } else if (numRows <= rowsAvailableInColumns23) {
219 rowsAvailableInColumns23 -= numRows;
220 } else {
221 return false;
222 }
223 }
224
225 int numRowsUsedInColumns01 =
226 twoColumnRowsAvailable - rowsAvailableInColumns01;
227 int numRowsUsedInColumns23 =
228 twoColumnRowsAvailable - rowsAvailableInColumns23;
229 fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2);
230 fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23,
231 2, 2);
232
233 // Packs the 1 column variables.
234 for (; ii < variables.size(); ++ii) {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400235 const sh::ShaderVariable &variable = variables[ii];
gman@chromium.org8d804792012-10-17 21:33:48 +0000236 ASSERT(1 == GetNumComponentsPerRow(variable.type));
Jamie Madilla718c1e2014-07-02 15:31:22 -0400237 int numRows = GetNumRows(variable.type) * variable.elementCount();
gman@chromium.org8d804792012-10-17 21:33:48 +0000238 int smallestColumn = -1;
239 int smallestSize = maxRows_ + 1;
240 int topRow = -1;
241 for (int column = 0; column < kNumColumns; ++column) {
242 int row = 0;
243 int size = 0;
244 if (searchColumn(column, numRows, &row, &size)) {
245 if (size < smallestSize) {
246 smallestSize = size;
247 smallestColumn = column;
248 topRow = row;
249 }
250 }
251 }
252
253 if (smallestColumn < 0) {
254 return false;
255 }
256
257 fillColumns(topRow, numRows, smallestColumn, 1);
258 }
259
260 ASSERT(variables.size() == ii);
261
262 return true;
263}
264
Jamie Madilla718c1e2014-07-02 15:31:22 -0400265// Instantiate all possible variable packings
266template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::ShaderVariable> &);
267template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::Attribute> &);
268template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::Uniform> &);
269template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::Varying> &);