Add a secondary size field to the shader language types, to account for matrix rows. Also add some extra logic
to the promote method to check that the sizes of the arguments to multiplications are properly formed.
We require this extra information for non-square matrix support.
TRAC #23081
Signed-off-by: Geoff Lang
Signed-off-by: Nicolas Capens
Author: Jamie Madill
git-svn-id: https://angleproject.googlecode.com/svn/branches/es3proto@2392 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/Intermediate.cpp b/src/compiler/Intermediate.cpp
index 458989b..e06a7a6 100644
--- a/src/compiler/Intermediate.cpp
+++ b/src/compiler/Intermediate.cpp
@@ -323,7 +323,7 @@
if (newType != EbtVoid) {
child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary,
child->getNominalSize(),
- child->isMatrix(),
+ child->getSecondarySize(),
child->isArray()),
child);
if (child == 0)
@@ -519,7 +519,7 @@
return 0;
}
- TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray());
+ TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->getSecondarySize(), node->isArray());
newNode = new TIntermUnary(newOp, type);
newNode->setLine(node->getLine());
newNode->setOperand(node);
@@ -852,6 +852,36 @@
return true;
}
+bool validateMultiplication(TOperator op, const TType &left, const TType &right)
+{
+ switch (op)
+ {
+ case EOpMul:
+ case EOpMulAssign:
+ return left.getNominalSize() == right.getNominalSize() && left.getSecondarySize() == right.getSecondarySize();
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesScalarAssign:
+ return true;
+ case EOpVectorTimesMatrix:
+ return left.getNominalSize() == right.getRows();
+ case EOpVectorTimesMatrixAssign:
+ return left.getNominalSize() == right.getRows() && left.getNominalSize() == right.getCols();
+ case EOpMatrixTimesVector:
+ return left.getCols() == right.getNominalSize();
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesScalarAssign:
+ return true;
+ case EOpMatrixTimesMatrix:
+ return left.getCols() == right.getRows();
+ case EOpMatrixTimesMatrixAssign:
+ return left.getCols() == right.getCols() && left.getRows() == right.getRows();
+
+ default:
+ UNREACHABLE();
+ return false;
+ }
+}
+
//
// Establishes the type of the resultant operation, as well as
// makes the operator the correct one for the operands.
@@ -889,12 +919,12 @@
getTypePointer()->setQualifier(EvqTemporary);
}
- int size = std::max(left->getNominalSize(), right->getNominalSize());
+ const int nominalSize = std::max(left->getNominalSize(), right->getNominalSize());
//
- // All scalars. Code after this test assumes this case is removed!
+ // All scalars or structs. Code after this test assumes this case is removed!
//
- if (size == 1)
+ if (nominalSize == 1)
{
switch (op)
{
@@ -931,20 +961,6 @@
// If we reach here, at least one of the operands is vector or matrix.
// The other operand could be a scalar, vector, or matrix.
- // Are the sizes compatible?
- //
- if (left->getNominalSize() != right->getNominalSize())
- {
- // If the nominal size of operands do not match:
- // One of them must be scalar.
- if (left->getNominalSize() != 1 && right->getNominalSize() != 1)
- return false;
- // Operator cannot be of type pure assignment.
- if (op == EOpAssign || op == EOpInitialize)
- return false;
- }
-
- //
// Can these two operands be combined?
//
TBasicType basicType = left->getBasicType();
@@ -960,7 +976,7 @@
else
{
op = EOpMatrixTimesScalar;
- setType(TType(basicType, higherPrecision, EvqTemporary, size, true));
+ setType(TType(basicType, higherPrecision, EvqTemporary, right->getCols(), right->getRows()));
}
}
else if (left->isMatrix() && !right->isMatrix())
@@ -968,7 +984,7 @@
if (right->isVector())
{
op = EOpMatrixTimesVector;
- setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
+ setType(TType(basicType, higherPrecision, EvqTemporary, left->getRows(), 1));
}
else
{
@@ -988,7 +1004,7 @@
else if (left->isVector() || right->isVector())
{
op = EOpVectorTimesScalar;
- setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
+ setType(TType(basicType, higherPrecision, EvqTemporary, nominalSize, 1));
}
}
else
@@ -996,7 +1012,13 @@
infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
return false;
}
+
+ if (!validateMultiplication(op, left->getType(), right->getType()))
+ {
+ return false;
+ }
break;
+
case EOpMulAssign:
if (!left->isMatrix() && right->isMatrix())
{
@@ -1035,7 +1057,7 @@
if (! left->isVector())
return false;
op = EOpVectorTimesScalarAssign;
- setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
+ setType(TType(basicType, higherPrecision, EvqTemporary, left->getNominalSize(), 1));
}
}
else
@@ -1043,6 +1065,11 @@
infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
return false;
}
+
+ if (!validateMultiplication(op, left->getType(), right->getType()))
+ {
+ return false;
+ }
break;
case EOpAssign:
@@ -1053,10 +1080,28 @@
case EOpAddAssign:
case EOpSubAssign:
case EOpDivAssign:
- if ((left->isMatrix() && right->isVector()) ||
- (left->isVector() && right->isMatrix()))
- return false;
- setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
+ {
+ if ((left->isMatrix() && right->isVector()) ||
+ (left->isVector() && right->isMatrix()))
+ return false;
+
+ // Are the sizes compatible?
+ if (left->getNominalSize() != right->getNominalSize() || left->getSecondarySize() != right->getSecondarySize())
+ {
+ // If the nominal size of operands do not match:
+ // One of them must be scalar.
+ if (!left->isScalar() && !right->isScalar())
+ return false;
+
+ // Operator cannot be of type pure assignment.
+ if (op == EOpAssign || op == EOpInitialize)
+ return false;
+ }
+
+ const int secondarySize = std::max(left->getSecondarySize(), right->getSecondarySize());
+
+ setType(TType(basicType, higherPrecision, EvqTemporary, nominalSize, secondarySize));
+ }
break;
case EOpEqual:
@@ -1065,8 +1110,8 @@
case EOpGreaterThan:
case EOpLessThanEqual:
case EOpGreaterThanEqual:
- if ((left->isMatrix() && right->isVector()) ||
- (left->isVector() && right->isMatrix()))
+ if ((left->getNominalSize() != right->getNominalSize()) ||
+ (left->getSecondarySize() != right->getSecondarySize()))
return false;
setType(TType(EbtBool, EbpUndefined));
break;
@@ -1188,13 +1233,14 @@
return 0;
}
{// support MSVC++6.0
- int size = getNominalSize();
- tempConstArray = new ConstantUnion[size*size];
- for (int row = 0; row < size; row++) {
- for (int column = 0; column < size; column++) {
- tempConstArray[size * column + row].setFConst(0.0f);
- for (int i = 0; i < size; i++) {
- tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst()));
+ int cols = getCols();
+ int rows = getRows();
+ tempConstArray = new ConstantUnion[cols*rows];
+ for (int row = 0; row < rows; row++) {
+ for (int column = 0; column < cols; column++) {
+ tempConstArray[rows * column + row].setFConst(0.0f);
+ for (int i = 0; i < cols; i++) {
+ tempConstArray[rows * column + row].setFConst(tempConstArray[rows * column + row].getFConst() + unionArray[i * rows + row].getFConst() * (rightUnionArray[column * rows + i].getFConst()));
}
}
}
@@ -1488,7 +1534,7 @@
const TType& t = node->getType();
- return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
+ return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.getSecondarySize(), t.isArray()), node->getLine());
}
// static