diff --git a/Test/baseResults/hlsl.matrixSwizzle.vert.out b/Test/baseResults/hlsl.matrixSwizzle.vert.out new file mode 100755 index 00000000..fccdd91d --- /dev/null +++ b/Test/baseResults/hlsl.matrixSwizzle.vert.out @@ -0,0 +1,148 @@ +hlsl.matrixSwizzle.vert +Shader version: 450 +0:? Sequence +0:2 Function Definition: ShaderFunction(f1; (temp void) +0:2 Function Parameters: +0:2 'inf' (layout(location=0 ) in float) +0:? Sequence +0:5 move second child to first child (temp float) +0:5 direct index (temp float) +0:5 direct index (temp 4-component vector of float) +0:5 'm' (temp 3X4 matrix of float) +0:5 Constant: +0:5 2 (const int) +0:5 Constant: +0:5 3 (const int) +0:5 Constant: +0:5 1.000000 +0:6 move second child to first child (temp float) +0:6 direct index (temp float) +0:6 direct index (temp 4-component vector of float) +0:6 'm' (temp 3X4 matrix of float) +0:6 Constant: +0:6 2 (const int) +0:6 Constant: +0:6 3 (const int) +0:6 Constant: +0:6 2.000000 +0:8 move second child to first child (temp 4-component vector of float) +0:8 direct index (temp 4-component vector of float) +0:8 'm' (temp 3X4 matrix of float) +0:8 Constant: +0:8 0 (const int) +0:8 Constant: +0:8 3.000000 +0:8 3.000000 +0:8 3.000000 +0:8 3.000000 +0:9 move second child to first child (temp 4-component vector of float) +0:9 direct index (temp 4-component vector of float) +0:9 'm' (temp 3X4 matrix of float) +0:9 Constant: +0:9 1 (const int) +0:9 Constant: +0:9 3.000000 +0:9 3.000000 +0:9 3.000000 +0:9 3.000000 +0:? Linker Objects +0:? 'inf' (layout(location=0 ) in float) + + +Linked vertex stage: + + +Shader version: 450 +0:? Sequence +0:2 Function Definition: ShaderFunction(f1; (temp void) +0:2 Function Parameters: +0:2 'inf' (layout(location=0 ) in float) +0:? Sequence +0:5 move second child to first child (temp float) +0:5 direct index (temp float) +0:5 direct index (temp 4-component vector of float) +0:5 'm' (temp 3X4 matrix of float) +0:5 Constant: +0:5 2 (const int) +0:5 Constant: +0:5 3 (const int) +0:5 Constant: +0:5 1.000000 +0:6 move second child to first child (temp float) +0:6 direct index (temp float) +0:6 direct index (temp 4-component vector of float) +0:6 'm' (temp 3X4 matrix of float) +0:6 Constant: +0:6 2 (const int) +0:6 Constant: +0:6 3 (const int) +0:6 Constant: +0:6 2.000000 +0:8 move second child to first child (temp 4-component vector of float) +0:8 direct index (temp 4-component vector of float) +0:8 'm' (temp 3X4 matrix of float) +0:8 Constant: +0:8 0 (const int) +0:8 Constant: +0:8 3.000000 +0:8 3.000000 +0:8 3.000000 +0:8 3.000000 +0:9 move second child to first child (temp 4-component vector of float) +0:9 direct index (temp 4-component vector of float) +0:9 'm' (temp 3X4 matrix of float) +0:9 Constant: +0:9 1 (const int) +0:9 Constant: +0:9 3.000000 +0:9 3.000000 +0:9 3.000000 +0:9 3.000000 +0:? Linker Objects +0:? 'inf' (layout(location=0 ) in float) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 29 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Vertex 4 "ShaderFunction" 28 + Name 4 "ShaderFunction" + Name 10 "m" + Name 28 "inf" + Decorate 28(inf) Location 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8: TypeMatrix 7(fvec4) 3 + 9: TypePointer Function 8 + 11: TypeInt 32 1 + 12: 11(int) Constant 2 + 13: 6(float) Constant 1065353216 + 14: TypeInt 32 0 + 15: 14(int) Constant 3 + 16: TypePointer Function 6(float) + 18: 6(float) Constant 1073741824 + 20: 11(int) Constant 0 + 21: 6(float) Constant 1077936128 + 22: 7(fvec4) ConstantComposite 21 21 21 21 + 23: TypePointer Function 7(fvec4) + 25: 11(int) Constant 1 + 27: TypePointer Input 6(float) + 28(inf): 27(ptr) Variable Input +4(ShaderFunction): 2 Function None 3 + 5: Label + 10(m): 9(ptr) Variable Function + 17: 16(ptr) AccessChain 10(m) 12 15 + Store 17 13 + 19: 16(ptr) AccessChain 10(m) 12 15 + Store 19 18 + 24: 23(ptr) AccessChain 10(m) 20 + Store 24 22 + 26: 23(ptr) AccessChain 10(m) 25 + Store 26 22 + Return + FunctionEnd diff --git a/Test/hlsl.matrixSwizzle.vert b/Test/hlsl.matrixSwizzle.vert new file mode 100644 index 00000000..48b5531f --- /dev/null +++ b/Test/hlsl.matrixSwizzle.vert @@ -0,0 +1,10 @@ +void ShaderFunction(float inf) : COLOR0 +{ + float3x4 m; + + m._34 = 1.0; // AST should have a normal component select + m._m23 = 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) +} diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index 24370029..e8b40b26 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -62,6 +62,32 @@ struct TVectorFields { int num; }; +class TMatrixComponents { +public: + static const int maxMatrixComponents = 4; + struct tMatrixComponent { + int coord1; // stay agnostic about column/row; this is parse order + int coord2; + }; + + TMatrixComponents() : size_(0) { } + void push_back(tMatrixComponent comp) + { + if (size_ < maxMatrixComponents) + components[size_++] = comp; + } + int size() const { return size_; } + tMatrixComponent get(int i) const + { + assert(i < maxMatrixComponents); + return components[i]; + } + +private: + int size_; + tMatrixComponent components[4]; +}; + // // Some helper structures for TIntermediate. Their contents are encapsulated // by TIntermediate. diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index e9e301c0..b6dde702 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -154,6 +154,7 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.logical.binary.frag", "main"}, {"hlsl.logical.binary.vec.frag", "main"}, {"hlsl.matNx1.frag", "main"}, + {"hlsl.matrixSwizzle.vert", "ShaderFunction"}, {"hlsl.mintypes.frag", "main"}, {"hlsl.multiEntry.vert", "RealEntrypoint"}, {"hlsl.multiReturn.frag", "main"}, diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 8300140c..7b541db8 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -521,78 +521,162 @@ bool HlslParseContext::parseVectorFields(const TSourceLoc& loc, const TString& c estpq, } fieldSet[4]; - for (int i = 0; i < fields.num; ++i) { - switch (compString[i]) { - case 'x': - fields.offsets[i] = 0; - fieldSet[i] = exyzw; - break; - case 'r': - fields.offsets[i] = 0; - fieldSet[i] = ergba; - break; - case 's': - fields.offsets[i] = 0; - fieldSet[i] = estpq; - break; - case 'y': - fields.offsets[i] = 1; - fieldSet[i] = exyzw; - break; - case 'g': - fields.offsets[i] = 1; - fieldSet[i] = ergba; - break; - case 't': - fields.offsets[i] = 1; - fieldSet[i] = estpq; - break; - case 'z': - fields.offsets[i] = 2; - fieldSet[i] = exyzw; - break; - case 'b': - fields.offsets[i] = 2; - fieldSet[i] = ergba; - break; - case 'p': - fields.offsets[i] = 2; - fieldSet[i] = estpq; - break; + for (int i = 0; i < fields.num; ++i) { + switch (compString[i]) { + case 'x': + fields.offsets[i] = 0; + fieldSet[i] = exyzw; + break; + case 'r': + fields.offsets[i] = 0; + fieldSet[i] = ergba; + break; + case 's': + fields.offsets[i] = 0; + fieldSet[i] = estpq; + break; + case 'y': + fields.offsets[i] = 1; + fieldSet[i] = exyzw; + break; + case 'g': + fields.offsets[i] = 1; + fieldSet[i] = ergba; + break; + case 't': + fields.offsets[i] = 1; + fieldSet[i] = estpq; + break; + case 'z': + fields.offsets[i] = 2; + fieldSet[i] = exyzw; + break; + case 'b': + fields.offsets[i] = 2; + fieldSet[i] = ergba; + break; + case 'p': + fields.offsets[i] = 2; + fieldSet[i] = estpq; + break; - case 'w': - fields.offsets[i] = 3; - fieldSet[i] = exyzw; - break; - case 'a': - fields.offsets[i] = 3; - fieldSet[i] = ergba; - break; - case 'q': - fields.offsets[i] = 3; - fieldSet[i] = estpq; - break; - default: - error(loc, "illegal vector field selection", compString.c_str(), ""); + case 'w': + fields.offsets[i] = 3; + fieldSet[i] = exyzw; + break; + case 'a': + fields.offsets[i] = 3; + fieldSet[i] = ergba; + break; + case 'q': + fields.offsets[i] = 3; + fieldSet[i] = estpq; + break; + default: + error(loc, "illegal vector field selection", compString.c_str(), ""); + return false; + } + } + + for (int i = 0; i < fields.num; ++i) { + if (fields.offsets[i] >= vecSize) { + error(loc, "vector field selection out of range", compString.c_str(), ""); + return false; + } + + if (i > 0) { + if (fieldSet[i] != fieldSet[i - 1]) { + error(loc, "illegal - vector component fields not from the same set", compString.c_str(), ""); return false; } } + } - for (int i = 0; i < fields.num; ++i) { - if (fields.offsets[i] >= vecSize) { - error(loc, "vector field selection out of range", compString.c_str(), ""); + return true; +} + +// +// Look at a '.' field selector string and change it into components +// for a matrix. There are two types: +// +// _21 second row, first column (one based) +// _m21 third row, second column (zero based) +// +// Returns true if there is no error. +// +bool HlslParseContext::parseMatrixComponents(const TSourceLoc& loc, const TString& fields, int cols, int rows, + TMatrixComponents& components) +{ + int startPos[TMatrixComponents::maxMatrixComponents]; + int numComps = 0; + TString compString = fields; + + // Find where each component starts, + // recording the first character position after the '_'. + for (size_t c = 0; c < compString.size(); ++c) { + if (compString[c] == '_') { + if (numComps >= TMatrixComponents::maxMatrixComponents) { + error(loc, "matrix component swizzle has too many components", compString.c_str(), ""); return false; } - - if (i > 0) { - if (fieldSet[i] != fieldSet[i - 1]) { - error(loc, "illegal - vector component fields not from the same set", compString.c_str(), ""); - return false; - } + if (c > compString.size() - 3 || + ((compString[c+1] == 'm' || compString[c+1] == 'M') && c > compString.size() - 4)) { + error(loc, "matrix component swizzle missing", compString.c_str(), ""); + return false; } + startPos[numComps++] = c + 1; } + } - return true; + // Process each component + for (int i = 0; i < numComps; ++i) { + int pos = startPos[i]; + int bias = -1; + if (compString[pos] == 'm' || compString[pos] == 'M') { + bias = 0; + ++pos; + } + TMatrixComponents::tMatrixComponent comp; + comp.coord1 = compString[pos+0] - '0' + bias; + comp.coord2 = compString[pos+1] - '0' + bias; + if (comp.coord1 < 0 || comp.coord1 >= cols) { + error(loc, "matrix row component out of range", compString.c_str(), ""); + return false; + } + if (comp.coord2 < 0 || comp.coord2 >= rows) { + error(loc, "matrix column component out of range", compString.c_str(), ""); + return false; + } + components.push_back(comp); + } + + return true; +} + +// If the 'comps' express a column of a matrix, +// return the column. Column means the first coords all match. +// +// Otherwise, return -1. +// +int HlslParseContext::getMatrixComponentsColumn(int rows, const TMatrixComponents& comps) +{ + int col = -1; + + // right number of comps? + if (comps.size() != rows) + return -1; + + // all comps in the same column? + // rows in order? + col = comps.get(0).coord1; + for (int i = 0; i < rows; ++i) { + if (col != comps.get(i).coord1) + return -1; + if (i != comps.get(i).coord2) + return -1; + } + + return col; } // @@ -888,6 +972,40 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, (int)vectorString.size())); } } + } else if (base->isMatrix()) { + TMatrixComponents comps; + if (! parseMatrixComponents(loc, field, base->getMatrixCols(), base->getMatrixRows(), comps)) + return result; + + if (comps.size() == 1) { + // Representable by m[c][r] + if (base->getType().getQualifier().storage == EvqConst) { + result = intermediate.foldDereference(base, comps.get(0).coord1, loc); + result = intermediate.foldDereference(result, comps.get(1).coord2, loc); + } else { + result = intermediate.addIndex(EOpIndexDirect, base, intermediate.addConstantUnion(comps.get(0).coord1, loc), loc); + TType dereferencedCol(base->getType(), 0); + result->setType(dereferencedCol); + result = intermediate.addIndex(EOpIndexDirect, result, intermediate.addConstantUnion(comps.get(0).coord2, loc), loc); + TType dereferenced(dereferencedCol, 0); + result->setType(dereferenced); + } + } else { + int column = getMatrixComponentsColumn(base->getMatrixRows(), comps); + if (column >= 0) { + // Representable by m[c] + if (base->getType().getQualifier().storage == EvqConst) + result = intermediate.foldDereference(base, column, loc); + else { + result = intermediate.addIndex(EOpIndexDirect, base, intermediate.addConstantUnion(column, loc), loc); + TType dereferenced(base->getType(), 0); + result->setType(dereferenced); + } + } else { + // general case, not a column, not a single component + error(loc, "arbitrary matrix component selection not supported", field.c_str(), ""); + } + } } else if (base->getBasicType() == EbtStruct || base->getBasicType() == EbtBlock) { const TTypeList* fields = base->getType().getStruct(); bool fieldFound = false; diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index d56bd426..18fe45cf 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -97,6 +97,8 @@ public: TIntermAggregate* handleSamplerTextureCombine(const TSourceLoc& loc, TIntermTyped* argTex, TIntermTyped* argSampler); bool parseVectorFields(const TSourceLoc&, const TString&, int vecSize, TVectorFields&); + bool parseMatrixComponents(const TSourceLoc&, const TString&, int cols, int rows, TMatrixComponents&); + int getMatrixComponentsColumn(int rows, const TMatrixComponents&); void assignError(const TSourceLoc&, const char* op, TString left, TString right); void unaryOpError(const TSourceLoc&, const char* op, TString operand); void binaryOpError(const TSourceLoc&, const char* op, TString left, TString right);