HLSL: matrix and vector truncations for m*v, v*m, m*m
HLSL truncates the vector, or one of the two matrix dimensions if there is a dimensional mismatch in m*v, v*m, or m*m. This PR adds that ability. Conversion constructors are added as required.
This commit is contained in:
parent
698bf7547a
commit
2e62910633
6 changed files with 523 additions and 0 deletions
|
|
@ -5008,6 +5008,12 @@ TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunct
|
|||
bool builtIn = false;
|
||||
int thisDepth = 0;
|
||||
|
||||
// For mat mul, the situation is unusual: we have to compare vector sizes to mat row or col sizes,
|
||||
// and clamp the opposite arg. Since that's complex, we farm it off to a separate method.
|
||||
// It doesn't naturally fall out of processing an argument at a time in isolation.
|
||||
if (function->getName() == "mul")
|
||||
addGenMulArgumentConversion(loc, *function, arguments);
|
||||
|
||||
TIntermAggregate* aggregate = arguments ? arguments->getAsAggregate() : nullptr;
|
||||
|
||||
// TODO: this needs improvement: there's no way at present to look up a signature in
|
||||
|
|
@ -5169,6 +5175,68 @@ void HlslParseContext::pushFrontArguments(TIntermTyped* front, TIntermTyped*& ar
|
|||
arguments = intermediate.growAggregate(front, arguments);
|
||||
}
|
||||
|
||||
//
|
||||
// HLSL allows mismatched dimensions on vec*mat, mat*vec, vec*vec, and mat*mat. This is a
|
||||
// situation not well suited to resolution in intrinsic selection, but we can do so here, since we
|
||||
// can look at both arguments insert explicit shape changes here, if required.
|
||||
//
|
||||
void HlslParseContext::addGenMulArgumentConversion(const TSourceLoc& loc, TFunction& call, TIntermTyped*& args)
|
||||
{
|
||||
TIntermAggregate* argAggregate = args ? args->getAsAggregate() : nullptr;
|
||||
|
||||
if (argAggregate == nullptr || argAggregate->getSequence().size() != 2) {
|
||||
// It really ought to have two arguments.
|
||||
error(loc, "expected: mul arguments", "", "");
|
||||
return;
|
||||
}
|
||||
|
||||
TIntermTyped* arg0 = argAggregate->getSequence()[0]->getAsTyped();
|
||||
TIntermTyped* arg1 = argAggregate->getSequence()[1]->getAsTyped();
|
||||
|
||||
if (arg0->isVector() && arg1->isVector()) {
|
||||
// For:
|
||||
// vec * vec: it's handled during intrinsic selection, so while we could do it here,
|
||||
// we can also ignore it, which is easier.
|
||||
} else if (arg0->isVector() && arg1->isMatrix()) {
|
||||
// vec * mat: we clamp the vec if the mat col is smaller, else clamp the mat col.
|
||||
if (arg0->getVectorSize() < arg1->getMatrixCols()) {
|
||||
// vec is smaller, so truncate larger mat dimension
|
||||
const TType truncType(arg1->getBasicType(), arg1->getQualifier().storage, arg1->getQualifier().precision,
|
||||
0, arg0->getVectorSize(), arg1->getMatrixRows());
|
||||
arg1 = addConstructor(loc, arg1, truncType);
|
||||
} else if (arg0->getVectorSize() > arg1->getMatrixCols()) {
|
||||
// vec is larger, so truncate vec to mat size
|
||||
const TType truncType(arg0->getBasicType(), arg0->getQualifier().storage, arg0->getQualifier().precision,
|
||||
arg1->getMatrixCols());
|
||||
arg0 = addConstructor(loc, arg0, truncType);
|
||||
}
|
||||
} else if (arg0->isMatrix() && arg1->isVector()) {
|
||||
// mat * vec: we clamp the vec if the mat col is smaller, else clamp the mat col.
|
||||
if (arg1->getVectorSize() < arg0->getMatrixRows()) {
|
||||
// vec is smaller, so truncate larger mat dimension
|
||||
const TType truncType(arg0->getBasicType(), arg0->getQualifier().storage, arg0->getQualifier().precision,
|
||||
0, arg0->getMatrixCols(), arg1->getVectorSize());
|
||||
arg0 = addConstructor(loc, arg0, truncType);
|
||||
} else if (arg1->getVectorSize() > arg0->getMatrixRows()) {
|
||||
// vec is larger, so truncate vec to mat size
|
||||
const TType truncType(arg1->getBasicType(), arg1->getQualifier().storage, arg1->getQualifier().precision,
|
||||
arg0->getMatrixRows());
|
||||
arg1 = addConstructor(loc, arg1, truncType);
|
||||
}
|
||||
} else if (arg0->isMatrix() && arg1->isMatrix()) {
|
||||
// mat * mat
|
||||
} else {
|
||||
// It's something with scalars: we'll just leave it alone.
|
||||
}
|
||||
|
||||
// Put arguments back.
|
||||
argAggregate->getSequence()[0] = arg0;
|
||||
argAggregate->getSequence()[1] = arg1;
|
||||
|
||||
call[0].type = &arg0->getWritableType();
|
||||
call[1].type = &arg1->getWritableType();
|
||||
}
|
||||
|
||||
//
|
||||
// Add any needed implicit conversions for function-call arguments to input parameters.
|
||||
//
|
||||
|
|
@ -7015,6 +7083,7 @@ void HlslParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQuali
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Look up a function name in the symbol table, and make sure it is a function.
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue