Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 1 | // |
| 2 | // Copyright (c) 2002-2014 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 | |
| 7 | #include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h" |
| 8 | #include "compiler/translator/compilerdebug.h" |
| 9 | |
| 10 | #include <algorithm> |
| 11 | |
Zhenyao Mo | daf5657 | 2014-08-06 16:18:30 -0700 | [diff] [blame] | 12 | #include "angle_gl.h" |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 13 | #include "common/angleutils.h" |
| 14 | |
| 15 | namespace |
| 16 | { |
| 17 | |
| 18 | bool ContainsMatrixNode(const TIntermSequence &sequence) |
| 19 | { |
| 20 | for (size_t ii = 0; ii < sequence.size(); ++ii) |
| 21 | { |
| 22 | TIntermTyped *node = sequence[ii]->getAsTyped(); |
| 23 | if (node && node->isMatrix()) |
| 24 | return true; |
| 25 | } |
| 26 | return false; |
| 27 | } |
| 28 | |
| 29 | bool ContainsVectorNode(const TIntermSequence &sequence) |
| 30 | { |
| 31 | for (size_t ii = 0; ii < sequence.size(); ++ii) |
| 32 | { |
| 33 | TIntermTyped *node = sequence[ii]->getAsTyped(); |
| 34 | if (node && node->isVector()) |
| 35 | return true; |
| 36 | } |
| 37 | return false; |
| 38 | } |
| 39 | |
| 40 | TIntermConstantUnion *ConstructIndexNode(int index) |
| 41 | { |
| 42 | ConstantUnion *u = new ConstantUnion[1]; |
| 43 | u[0].setIConst(index); |
| 44 | |
| 45 | TType type(EbtInt, EbpUndefined, EvqConst, 1); |
| 46 | TIntermConstantUnion *node = new TIntermConstantUnion(u, type); |
| 47 | return node; |
| 48 | } |
| 49 | |
| 50 | TIntermBinary *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index) |
| 51 | { |
| 52 | TIntermBinary *binary = new TIntermBinary(EOpIndexDirect); |
| 53 | binary->setLeft(symbolNode); |
| 54 | TIntermConstantUnion *indexNode = ConstructIndexNode(index); |
| 55 | binary->setRight(indexNode); |
| 56 | return binary; |
| 57 | } |
| 58 | |
| 59 | TIntermBinary *ConstructMatrixIndexBinaryNode( |
| 60 | TIntermSymbol *symbolNode, int colIndex, int rowIndex) |
| 61 | { |
| 62 | TIntermBinary *colVectorNode = |
| 63 | ConstructVectorIndexBinaryNode(symbolNode, colIndex); |
| 64 | |
| 65 | TIntermBinary *binary = new TIntermBinary(EOpIndexDirect); |
| 66 | binary->setLeft(colVectorNode); |
| 67 | TIntermConstantUnion *rowIndexNode = ConstructIndexNode(rowIndex); |
| 68 | binary->setRight(rowIndexNode); |
| 69 | return binary; |
| 70 | } |
| 71 | |
| 72 | } // namespace anonymous |
| 73 | |
| 74 | bool ScalarizeVecAndMatConstructorArgs::visitAggregate(Visit visit, TIntermAggregate *node) |
| 75 | { |
| 76 | if (visit == PreVisit) |
| 77 | { |
| 78 | switch (node->getOp()) |
| 79 | { |
| 80 | case EOpSequence: |
| 81 | mSequenceStack.push_back(TIntermSequence()); |
| 82 | { |
Zhenyao Mo | e40d1e9 | 2014-07-16 17:40:36 -0700 | [diff] [blame] | 83 | for (TIntermSequence::const_iterator iter = node->getSequence()->begin(); |
| 84 | iter != node->getSequence()->end(); ++iter) |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 85 | { |
| 86 | TIntermNode *child = *iter; |
| 87 | ASSERT(child != NULL); |
| 88 | child->traverse(this); |
| 89 | mSequenceStack.back().push_back(child); |
| 90 | } |
| 91 | } |
Zhenyao Mo | e40d1e9 | 2014-07-16 17:40:36 -0700 | [diff] [blame] | 92 | if (mSequenceStack.back().size() > node->getSequence()->size()) |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 93 | { |
Zhenyao Mo | e40d1e9 | 2014-07-16 17:40:36 -0700 | [diff] [blame] | 94 | node->getSequence()->clear(); |
| 95 | *(node->getSequence()) = mSequenceStack.back(); |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 96 | } |
| 97 | mSequenceStack.pop_back(); |
| 98 | return false; |
| 99 | case EOpConstructVec2: |
| 100 | case EOpConstructVec3: |
| 101 | case EOpConstructVec4: |
| 102 | case EOpConstructBVec2: |
| 103 | case EOpConstructBVec3: |
| 104 | case EOpConstructBVec4: |
| 105 | case EOpConstructIVec2: |
| 106 | case EOpConstructIVec3: |
| 107 | case EOpConstructIVec4: |
Zhenyao Mo | e40d1e9 | 2014-07-16 17:40:36 -0700 | [diff] [blame] | 108 | if (ContainsMatrixNode(*(node->getSequence()))) |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 109 | scalarizeArgs(node, false, true); |
| 110 | break; |
| 111 | case EOpConstructMat2: |
| 112 | case EOpConstructMat3: |
| 113 | case EOpConstructMat4: |
Zhenyao Mo | e40d1e9 | 2014-07-16 17:40:36 -0700 | [diff] [blame] | 114 | if (ContainsVectorNode(*(node->getSequence()))) |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 115 | scalarizeArgs(node, true, false); |
| 116 | break; |
| 117 | default: |
| 118 | break; |
| 119 | } |
| 120 | } |
| 121 | return true; |
| 122 | } |
| 123 | |
| 124 | void ScalarizeVecAndMatConstructorArgs::scalarizeArgs( |
| 125 | TIntermAggregate *aggregate, bool scalarizeVector, bool scalarizeMatrix) |
| 126 | { |
| 127 | ASSERT(aggregate); |
| 128 | int size = 0; |
| 129 | switch (aggregate->getOp()) |
| 130 | { |
| 131 | case EOpConstructVec2: |
| 132 | case EOpConstructBVec2: |
| 133 | case EOpConstructIVec2: |
| 134 | size = 2; |
| 135 | break; |
| 136 | case EOpConstructVec3: |
| 137 | case EOpConstructBVec3: |
| 138 | case EOpConstructIVec3: |
| 139 | size = 3; |
| 140 | break; |
| 141 | case EOpConstructVec4: |
| 142 | case EOpConstructBVec4: |
| 143 | case EOpConstructIVec4: |
| 144 | case EOpConstructMat2: |
| 145 | size = 4; |
| 146 | break; |
| 147 | case EOpConstructMat3: |
| 148 | size = 9; |
| 149 | break; |
| 150 | case EOpConstructMat4: |
| 151 | size = 16; |
| 152 | break; |
| 153 | default: |
| 154 | break; |
| 155 | } |
Zhenyao Mo | e40d1e9 | 2014-07-16 17:40:36 -0700 | [diff] [blame] | 156 | TIntermSequence *sequence = aggregate->getSequence(); |
| 157 | TIntermSequence original(*sequence); |
| 158 | sequence->clear(); |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 159 | for (size_t ii = 0; ii < original.size(); ++ii) |
| 160 | { |
| 161 | ASSERT(size > 0); |
| 162 | TIntermTyped *node = original[ii]->getAsTyped(); |
| 163 | ASSERT(node); |
| 164 | TString varName = createTempVariable(node); |
| 165 | if (node->isScalar()) |
| 166 | { |
| 167 | TIntermSymbol *symbolNode = |
| 168 | new TIntermSymbol(-1, varName, node->getType()); |
Zhenyao Mo | e40d1e9 | 2014-07-16 17:40:36 -0700 | [diff] [blame] | 169 | sequence->push_back(symbolNode); |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 170 | size--; |
| 171 | } |
| 172 | else if (node->isVector()) |
| 173 | { |
| 174 | if (scalarizeVector) |
| 175 | { |
| 176 | int repeat = std::min(size, node->getNominalSize()); |
| 177 | size -= repeat; |
| 178 | for (int index = 0; index < repeat; ++index) |
| 179 | { |
| 180 | TIntermSymbol *symbolNode = |
| 181 | new TIntermSymbol(-1, varName, node->getType()); |
| 182 | TIntermBinary *newNode = ConstructVectorIndexBinaryNode( |
| 183 | symbolNode, index); |
Zhenyao Mo | e40d1e9 | 2014-07-16 17:40:36 -0700 | [diff] [blame] | 184 | sequence->push_back(newNode); |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 185 | } |
| 186 | } |
| 187 | else |
| 188 | { |
| 189 | TIntermSymbol *symbolNode = |
| 190 | new TIntermSymbol(-1, varName, node->getType()); |
Zhenyao Mo | e40d1e9 | 2014-07-16 17:40:36 -0700 | [diff] [blame] | 191 | sequence->push_back(symbolNode); |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 192 | size -= node->getNominalSize(); |
| 193 | } |
| 194 | } |
| 195 | else |
| 196 | { |
| 197 | ASSERT(node->isMatrix()); |
| 198 | if (scalarizeMatrix) |
| 199 | { |
| 200 | int colIndex = 0, rowIndex = 0; |
| 201 | int repeat = std::min(size, node->getCols() * node->getRows()); |
| 202 | size -= repeat; |
| 203 | while (repeat > 0) |
| 204 | { |
| 205 | TIntermSymbol *symbolNode = |
| 206 | new TIntermSymbol(-1, varName, node->getType()); |
| 207 | TIntermBinary *newNode = ConstructMatrixIndexBinaryNode( |
| 208 | symbolNode, colIndex, rowIndex); |
Zhenyao Mo | e40d1e9 | 2014-07-16 17:40:36 -0700 | [diff] [blame] | 209 | sequence->push_back(newNode); |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 210 | rowIndex++; |
| 211 | if (rowIndex >= node->getRows()) |
| 212 | { |
| 213 | rowIndex = 0; |
| 214 | colIndex++; |
| 215 | } |
| 216 | repeat--; |
| 217 | } |
| 218 | } |
| 219 | else |
| 220 | { |
| 221 | TIntermSymbol *symbolNode = |
| 222 | new TIntermSymbol(-1, varName, node->getType()); |
Zhenyao Mo | e40d1e9 | 2014-07-16 17:40:36 -0700 | [diff] [blame] | 223 | sequence->push_back(symbolNode); |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 224 | size -= node->getCols() * node->getRows(); |
| 225 | } |
| 226 | } |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | TString ScalarizeVecAndMatConstructorArgs::createTempVariable(TIntermTyped *original) |
| 231 | { |
| 232 | TString tempVarName = "_webgl_tmp_"; |
| 233 | if (original->isScalar()) |
| 234 | { |
| 235 | tempVarName += "scalar_"; |
| 236 | } |
| 237 | else if (original->isVector()) |
| 238 | { |
| 239 | tempVarName += "vec_"; |
| 240 | } |
| 241 | else |
| 242 | { |
| 243 | ASSERT(original->isMatrix()); |
| 244 | tempVarName += "mat_"; |
| 245 | } |
| 246 | tempVarName += Str(mTempVarCount).c_str(); |
| 247 | mTempVarCount++; |
| 248 | |
| 249 | ASSERT(original); |
| 250 | TType type = original->getType(); |
| 251 | type.setQualifier(EvqTemporary); |
| 252 | |
Zhenyao Mo | daf5657 | 2014-08-06 16:18:30 -0700 | [diff] [blame] | 253 | if (mShaderType == GL_FRAGMENT_SHADER && |
| 254 | type.getBasicType() == EbtFloat && |
| 255 | type.getPrecision() == EbpUndefined) |
| 256 | { |
| 257 | // We use the highest available precision for the temporary variable |
| 258 | // to avoid computing the actual precision using the rules defined |
| 259 | // in GLSL ES 1.0 Section 4.5.2. |
| 260 | type.setPrecision(mFragmentPrecisionHigh ? EbpHigh : EbpMedium); |
| 261 | } |
| 262 | |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 263 | TIntermBinary *init = new TIntermBinary(EOpInitialize); |
| 264 | TIntermSymbol *symbolNode = new TIntermSymbol(-1, tempVarName, type); |
| 265 | init->setLeft(symbolNode); |
| 266 | init->setRight(original); |
| 267 | init->setType(type); |
| 268 | |
| 269 | TIntermAggregate *decl = new TIntermAggregate(EOpDeclaration); |
Zhenyao Mo | e40d1e9 | 2014-07-16 17:40:36 -0700 | [diff] [blame] | 270 | decl->getSequence()->push_back(init); |
Zhenyao Mo | cd68fe7 | 2014-07-11 10:45:44 -0700 | [diff] [blame] | 271 | |
| 272 | ASSERT(mSequenceStack.size() > 0); |
| 273 | TIntermSequence &sequence = mSequenceStack.back(); |
| 274 | sequence.push_back(decl); |
| 275 | |
| 276 | return tempVarName; |
| 277 | } |