Commit fdf6347f by John Kessenich

HLSL: Add EOpMatrixSwizzle, selectively decomposed to other ops, for issue #670.

Since EOpMatrixSwizzle is a new op, existing back-ends only work when the front end first decomposes it to other operations. So far, this is only being done for simple assignment into matrix swizzles.
parent 001dfa1c
......@@ -1115,6 +1115,9 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()));
}
return false;
case glslang::EOpMatrixSwizzle:
logger->missingFunctionality("matrix swizzle");
return true;
case glslang::EOpLogicalOr:
case glslang::EOpLogicalAnd:
{
......
......@@ -2,9 +2,32 @@ void ShaderFunction(float inf) : COLOR0
{
float3x4 m;
// tests that convert to non-matrix swizzles
m._34 = 1.0; // AST should have a normal component select
m._m23 = 2.0; // same code
m[2][3] = 2.0; // same code
m._11_12_13_14 = float4(3.0); // AST should have normal column selection (first row)
m._m10_m11_m12_m13 = float4(3.0); // AST should have normal column selection (second row)
m[1] = float4(3.0); // same code
// tests that stay as matrix swizzles
float3 f3;
m._11_22_23 = f3;
m._21_12_31 = float3(5.0);
m._11_12_21 = 2 * f3;
// r-value
f3 = m._21_12_31;
}
float3x3 createMat3x3(float3 a, float3 b, float3 c)
{
float3x3 m;
m._11_21_31 = a;
m._12_22_32 = b;
m._13_23_33 = c;
return m;
}
......@@ -626,6 +626,9 @@ enum TOperator {
// geometry methods
EOpMethodAppend, // Geometry shader methods
EOpMethodRestartStrip, // ...
// matrix
EOpMatrixSwizzle, // select multiple matrix components (non-column)
};
class TIntermTraverser;
......
......@@ -2,5 +2,5 @@
// For the version, it uses the latest git tag followed by the number of commits.
// For the date, it uses the current date (when then script is run).
#define GLSLANG_REVISION "Overload400-PrecQual.1764"
#define GLSLANG_DATE "12-Jan-2017"
#define GLSLANG_REVISION "Overload400-PrecQual.1766"
#define GLSLANG_DATE "13-Jan-2017"
......@@ -1408,6 +1408,26 @@ TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc&
return node;
}
// A matrix swizzle is a sequence of nodes, 2N long, where N is the
// number of components in the swizzle, alternating col,row, col,row, ...
TIntermTyped* TIntermediate::addSwizzle(TMatrixComponents& comps, const TSourceLoc& loc)
{
TIntermAggregate* node = new TIntermAggregate(EOpSequence);
node->setLoc(loc);
TIntermConstantUnion* constIntNode;
TIntermSequence &sequenceVector = node->getSequence();
for (int i = 0; i < comps.size(); i++) {
constIntNode = addConstantUnion(comps.get(i).coord1, loc);
sequenceVector.push_back(constIntNode);
constIntNode = addConstantUnion(comps.get(i).coord2, loc);
sequenceVector.push_back(constIntNode);
}
return node;
}
//
// Follow the left branches down to the root of an l-value
// expression (just "." and []).
......@@ -1425,10 +1445,10 @@ const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool
if (binary == nullptr)
return node;
TOperator op = binary->getOp();
if (op != EOpIndexDirect && op != EOpIndexIndirect && op != EOpIndexDirectStruct && op != EOpVectorSwizzle)
if (op != EOpIndexDirect && op != EOpIndexIndirect && op != EOpIndexDirectStruct && op != EOpVectorSwizzle && op != EOpMatrixSwizzle)
return nullptr;
if (! swizzleOkay) {
if (op == EOpVectorSwizzle)
if (op == EOpVectorSwizzle || op == EOpMatrixSwizzle)
return nullptr;
if ((op == EOpIndexDirect || op == EOpIndexIndirect) &&
(binary->getLeft()->getType().isVector() || binary->getLeft()->getType().isScalar()) &&
......
......@@ -129,6 +129,7 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op,
case EOpIndexIndirect: // fall through
case EOpIndexDirectStruct: // fall through
case EOpVectorSwizzle:
case EOpMatrixSwizzle:
return lValueErrorCheck(loc, op, binaryNode->getLeft());
default:
break;
......@@ -208,6 +209,7 @@ void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op,
case EOpIndexIndirect:
case EOpIndexDirectStruct:
case EOpVectorSwizzle:
case EOpMatrixSwizzle:
rValueErrorCheck(loc, op, binaryNode->getLeft());
default:
break;
......
......@@ -146,6 +146,7 @@ bool TOutputTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
out.debug << (*node->getLeft()->getType().getStruct())[node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()].type->getFieldName();
out.debug << ": direct index for structure"; break;
case EOpVectorSwizzle: out.debug << "vector swizzle"; break;
case EOpMatrixSwizzle: out.debug << "matrix swizzle"; break;
case EOpAdd: out.debug << "add"; break;
case EOpSub: out.debug << "subtract"; break;
......
......@@ -275,6 +275,7 @@ public:
TIntermBranch* addBranch(TOperator, const TSourceLoc&);
TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
TIntermTyped* addSwizzle(TVectorFields&, const TSourceLoc&);
TIntermTyped* addSwizzle(TMatrixComponents&, const TSourceLoc&);
// Low level functions to add nodes (no conversions or other higher level transformations)
// If a type is provided, the node's type will be set to it.
......
......@@ -90,6 +90,7 @@ bool isDereferenceOperation(glslang::TOperator op)
case glslang::EOpIndexDirectStruct:
case glslang::EOpIndexIndirect:
case glslang::EOpVectorSwizzle:
case glslang::EOpMatrixSwizzle:
return true;
default:
return false;
......
......@@ -966,10 +966,9 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
result->setType(TType(base->getBasicType(), EvqTemporary));
} else {
TString vectorString = field;
TIntermTyped* index = intermediate.addSwizzle(fields, loc);
result = intermediate.addIndex(EOpVectorSwizzle, base, index, loc);
result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, (int)vectorString.size()));
result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, fields.num));
}
}
} else if (base->isMatrix()) {
......@@ -979,7 +978,7 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
if (comps.size() == 1) {
// Representable by m[c][r]
if (base->getType().getQualifier().storage == EvqConst) {
if (base->getType().getQualifier().isFrontEndConstant()) {
result = intermediate.foldDereference(base, comps.get(0).coord1, loc);
result = intermediate.foldDereference(result, comps.get(1).coord2, loc);
} else {
......@@ -994,7 +993,7 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
int column = getMatrixComponentsColumn(base->getMatrixRows(), comps);
if (column >= 0) {
// Representable by m[c]
if (base->getType().getQualifier().storage == EvqConst)
if (base->getType().getQualifier().isFrontEndConstant())
result = intermediate.foldDereference(base, column, loc);
else {
result = intermediate.addIndex(EOpIndexDirect, base, intermediate.addConstantUnion(column, loc), loc);
......@@ -1003,7 +1002,9 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
}
} else {
// general case, not a column, not a single component
error(loc, "arbitrary matrix component selection not supported", field.c_str(), "");
TIntermTyped* index = intermediate.addSwizzle(comps, loc);
result = intermediate.addIndex(EOpMatrixSwizzle, base, index, loc);
result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, comps.size()));
}
}
} else if (base->getBasicType() == EbtStruct || base->getBasicType() == EbtBlock) {
......@@ -1890,11 +1891,17 @@ void HlslParseContext::handleFunctionArgument(TFunction* function,
// Some simple source assignments need to be flattened to a sequence
// of AST assignments. Catch these and flatten, otherwise, pass through
// to intermediate.addAssign().
TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op, TIntermTyped* left, TIntermTyped* right) const
//
// Also, assignment to matrix swizzles requires multiple component assignments,
// intercept those as well.
TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op, TIntermTyped* left, TIntermTyped* right)
{
if (left == nullptr || right == nullptr)
return nullptr;
if (left->getAsOperator() && left->getAsOperator()->getOp() == EOpMatrixSwizzle)
return handleAssignToMatrixSwizzle(loc, op, left, right);
const bool isSplitLeft = wasSplit(left);
const bool isSplitRight = wasSplit(right);
......@@ -1902,7 +1909,7 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
const bool isFlattenRight = wasFlattened(right);
// OK to do a single assign if both are split, or both are unsplit. But if one is and the other
// isn't, we fall back to a memberwise copy.
// isn't, we fall back to a member-wise copy.
if (! isFlattenLeft && ! isFlattenRight && !isSplitLeft && !isSplitRight)
return intermediate.addAssign(op, left, right, loc);
......@@ -2079,6 +2086,65 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
return assignList;
}
// An assignment to matrix swizzle must be decomposed into individual assignments.
// These must be selected component-wise from the RHS and stored component-wise
// into the LHS.
TIntermTyped* HlslParseContext::handleAssignToMatrixSwizzle(const TSourceLoc& loc, TOperator op, TIntermTyped* left, TIntermTyped* right)
{
assert(left->getAsOperator() && left->getAsOperator()->getOp() == EOpMatrixSwizzle);
if (op != EOpAssign)
error(loc, "only simple assignment to non-simple matrix swizzle is supported", "assign", "");
// isolate the matrix and swizzle nodes
TIntermTyped* matrix = left->getAsBinaryNode()->getLeft()->getAsTyped();
const TIntermSequence& swizzle = left->getAsBinaryNode()->getRight()->getAsAggregate()->getSequence();
// if the RHS isn't already a simple vector, let's store into one
TIntermSymbol* vector = right->getAsSymbolNode();
TIntermTyped* vectorAssign = nullptr;
if (vector == nullptr) {
// create a new intermediate vector variable to assign to
TType vectorType(matrix->getBasicType(), EvqTemporary, matrix->getQualifier().precision, swizzle.size()/2);
vector = intermediate.addSymbol(*makeInternalVariable("intermVec", vectorType), loc);
// assign the right to the new vector
vectorAssign = handleAssign(loc, op, vector, right);
}
// Assign the vector components to the matrix components.
// Store this as a sequence, so a single aggregate node represents this
// entire operation.
TIntermAggregate* result = intermediate.makeAggregate(vectorAssign);
TType columnType(matrix->getType(), 0);
TType componentType(columnType, 0);
TType indexType(EbtInt);
for (int i = 0; i < (int)swizzle.size(); i += 2) {
// the right component, single index into the RHS vector
TIntermTyped* rightComp = intermediate.addIndex(EOpIndexDirect, vector,
intermediate.addConstantUnion(i/2, loc), loc);
// the left component, double index into the LHS matrix
TIntermTyped* leftComp = intermediate.addIndex(EOpIndexDirect, matrix,
intermediate.addConstantUnion(swizzle[i]->getAsConstantUnion()->getConstArray(),
indexType, loc),
loc);
leftComp->setType(columnType);
leftComp = intermediate.addIndex(EOpIndexDirect, leftComp,
intermediate.addConstantUnion(swizzle[i+1]->getAsConstantUnion()->getConstArray(),
indexType, loc),
loc);
leftComp->setType(componentType);
// Add the assignment to the aggregate
result = intermediate.growAggregate(result, intermediate.addAssign(op, leftComp, rightComp, loc));
}
result->setOp(EOpSequence);
return result;
}
//
// HLSL atomic operations have slightly different arguments than
// GLSL/AST/SPIRV. The semantics are converted below in decomposeIntrinsic.
......
......@@ -78,7 +78,8 @@ public:
void remapNonEntryPointIO(TFunction& function);
TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*);
void handleFunctionArgument(TFunction*, TIntermTyped*& arguments, TIntermTyped* newArg);
TIntermTyped* handleAssign(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right) const;
TIntermTyped* handleAssign(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right);
TIntermTyped* handleAssignToMatrixSwizzle(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right);
TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermTyped*);
void decomposeIntrinsic(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
void decomposeSampleMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment