Full stack: distinguish between a scalar and a vector of size 1.

There have been GLSL extensions considering this, and HLSL does it.
This is a fully backward compatible change that allows this distinction.
This commit is contained in:
John Kessenich
2016-05-20 12:06:03 -06:00
parent 823fc65644
commit 8d72f1a2c4
9 changed files with 152 additions and 29 deletions

View File

@@ -1366,7 +1366,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
{ {
// for scalar dot product, use multiply // for scalar dot product, use multiply
glslang::TIntermSequence& glslangOperands = node->getSequence(); glslang::TIntermSequence& glslangOperands = node->getSequence();
if (! glslangOperands[0]->getAsTyped()->isVector()) if (glslangOperands[0]->getAsTyped()->getVectorSize() == 1)
binOp = glslang::EOpMul; binOp = glslang::EOpMul;
break; break;
} }
@@ -2750,7 +2750,7 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv
break; break;
case glslang::EOpVectorTimesScalar: case glslang::EOpVectorTimesScalar:
case glslang::EOpVectorTimesScalarAssign: case glslang::EOpVectorTimesScalarAssign:
if (isFloat) { if (isFloat && (builder.isVector(left) || builder.isVector(right))) {
if (builder.isVector(right)) if (builder.isVector(right))
std::swap(left, right); std::swap(left, right);
assert(builder.isScalar(right)); assert(builder.isScalar(right));
@@ -4096,7 +4096,7 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla
glslang::TVector<glslang::TTypeLoc>::const_iterator iter; glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter) for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false)); spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false));
} else if (glslangType.isVector()) { } else if (glslangType.getVectorSize() > 1) {
for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) { for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
bool zero = nextConst >= consts.size(); bool zero = nextConst >= consts.size();
switch (glslangType.getBasicType()) { switch (glslangType.getBasicType()) {

View File

@@ -0,0 +1,100 @@
hlsl.float1.frag
Shader version: 100
gl_FragCoord origin is upper left
0:? Sequence
0:1 move second child to first child (temp 1-component vector of float)
0:1 'f1' (temp 1-component vector of float)
0:1 Constant:
0:1 1.000000
0:2 move second child to first child (temp float)
0:2 'scalar' (temp float)
0:2 Constant:
0:2 2.000000
0:8 Function Definition: ShaderFunction(vf1;f1; (temp 1-component vector of float)
0:5 Function Parameters:
0:5 'inFloat1' (temp 1-component vector of float)
0:5 'inScalar' (temp float)
0:? Sequence
0:6 Branch: Return with expression
0:6 add (temp 1-component vector of float)
0:6 vector-scale (temp 1-component vector of float)
0:6 'f1' (temp 1-component vector of float)
0:6 'scalar' (temp float)
0:6 vector-scale (temp 1-component vector of float)
0:6 'inFloat1' (temp 1-component vector of float)
0:6 'inScalar' (temp float)
0:? Linker Objects
0:? 'f1' (temp 1-component vector of float)
0:? 'scalar' (temp float)
Linked fragment stage:
Shader version: 100
gl_FragCoord origin is upper left
0:? Sequence
0:1 move second child to first child (temp 1-component vector of float)
0:1 'f1' (temp 1-component vector of float)
0:1 Constant:
0:1 1.000000
0:2 move second child to first child (temp float)
0:2 'scalar' (temp float)
0:2 Constant:
0:2 2.000000
0:8 Function Definition: ShaderFunction(vf1;f1; (temp 1-component vector of float)
0:5 Function Parameters:
0:5 'inFloat1' (temp 1-component vector of float)
0:5 'inScalar' (temp float)
0:? Sequence
0:6 Branch: Return with expression
0:6 add (temp 1-component vector of float)
0:6 vector-scale (temp 1-component vector of float)
0:6 'f1' (temp 1-component vector of float)
0:6 'scalar' (temp float)
0:6 vector-scale (temp 1-component vector of float)
0:6 'inFloat1' (temp 1-component vector of float)
0:6 'inScalar' (temp float)
0:? Linker Objects
0:? 'f1' (temp 1-component vector of float)
0:? 'scalar' (temp float)
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 24
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "PixelShaderFunction"
ExecutionMode 4 OriginUpperLeft
Source HLSL 100
Name 4 "PixelShaderFunction"
Name 11 "ShaderFunction(vf1;f1;"
Name 9 "inFloat1"
Name 10 "inScalar"
Name 13 "f1"
Name 15 "scalar"
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
7: TypePointer Function 6(float)
8: TypeFunction 6(float) 7(ptr) 7(ptr)
4(PixelShaderFunction): 2 Function None 3
5: Label
FunctionEnd
11(ShaderFunction(vf1;f1;): 6(float) Function None 8
9(inFloat1): 7(ptr) FunctionParameter
10(inScalar): 7(ptr) FunctionParameter
12: Label
13(f1): 7(ptr) Variable Function
15(scalar): 7(ptr) Variable Function
14: 6(float) Load 13(f1)
16: 6(float) Load 15(scalar)
17: 6(float) IMul 14 16
18: 6(float) Load 9(inFloat1)
19: 6(float) Load 10(inScalar)
20: 6(float) IMul 18 19
21: 6(float) FAdd 17 20
ReturnValue 21
FunctionEnd

7
Test/hlsl.float1.frag Normal file
View File

@@ -0,0 +1,7 @@
float1 f1 = float1(1.0);
float scalar = 2.0;
float1 ShaderFunction(float1 inFloat1, float inScalar) : COLOR0
{
return f1 * scalar + inFloat1 * inScalar;
}

View File

@@ -1044,8 +1044,8 @@ public:
// for "empty" type (no args) or simple scalar/vector/matrix // for "empty" type (no args) or simple scalar/vector/matrix
explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0) : explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0) :
basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(nullptr), basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(false),
structure(nullptr), fieldName(nullptr), typeName(nullptr) arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
{ {
sampler.clear(); sampler.clear();
qualifier.clear(); qualifier.clear();
@@ -1053,8 +1053,8 @@ public:
} }
// for explicit precision qualifier // for explicit precision qualifier
TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0) : TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0) :
basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(nullptr), basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(false),
structure(nullptr), fieldName(nullptr), typeName(nullptr) arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
{ {
sampler.clear(); sampler.clear();
qualifier.clear(); qualifier.clear();
@@ -1064,8 +1064,9 @@ public:
} }
// for turning a TPublicType into a TType, using a shallow copy // for turning a TPublicType into a TType, using a shallow copy
explicit TType(const TPublicType& p) : explicit TType(const TPublicType& p) :
basicType(p.basicType), vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), arraySizes(p.arraySizes), basicType(p.basicType),
structure(nullptr), fieldName(nullptr), typeName(nullptr) vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false),
arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr)
{ {
if (basicType == EbtSampler) if (basicType == EbtSampler)
sampler = p.sampler; sampler = p.sampler;
@@ -1100,19 +1101,25 @@ public:
// do a vector/matrix dereference // do a vector/matrix dereference
shallowCopy(type); shallowCopy(type);
if (matrixCols > 0) { if (matrixCols > 0) {
// dereference from matrix to vector
if (rowMajor) if (rowMajor)
vectorSize = matrixCols; vectorSize = matrixCols;
else else
vectorSize = matrixRows; vectorSize = matrixRows;
matrixCols = 0; matrixCols = 0;
matrixRows = 0; matrixRows = 0;
} else if (vectorSize > 1) if (vectorSize == 1)
vector1 = true;
} else if (isVector()) {
// dereference from vector to scalar
vectorSize = 1; vectorSize = 1;
vector1 = false;
}
} }
} }
// for making structures, ... // for making structures, ...
TType(TTypeList* userDef, const TString& n) : TType(TTypeList* userDef, const TString& n) :
basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
arraySizes(nullptr), structure(userDef), fieldName(nullptr) arraySizes(nullptr), structure(userDef), fieldName(nullptr)
{ {
sampler.clear(); sampler.clear();
@@ -1121,7 +1128,7 @@ public:
} }
// For interface blocks // For interface blocks
TType(TTypeList* userDef, const TString& n, const TQualifier& q) : TType(TTypeList* userDef, const TString& n, const TQualifier& q) :
basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr) qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr)
{ {
sampler.clear(); sampler.clear();
@@ -1140,6 +1147,7 @@ public:
vectorSize = copyOf.vectorSize; vectorSize = copyOf.vectorSize;
matrixCols = copyOf.matrixCols; matrixCols = copyOf.matrixCols;
matrixRows = copyOf.matrixRows; matrixRows = copyOf.matrixRows;
vector1 = copyOf.vector1;
arraySizes = copyOf.arraySizes; // copying the pointer only, not the contents arraySizes = copyOf.arraySizes; // copying the pointer only, not the contents
structure = copyOf.structure; structure = copyOf.structure;
fieldName = copyOf.fieldName; fieldName = copyOf.fieldName;
@@ -1180,6 +1188,8 @@ public:
return newType; return newType;
} }
void makeVector() { vector1 = true; }
// Merge type from parent, where a parentType is at the beginning of a declaration, // Merge type from parent, where a parentType is at the beginning of a declaration,
// establishing some characteristics for all subsequent names, while this type // establishing some characteristics for all subsequent names, while this type
// is on the individual names. // is on the individual names.
@@ -1190,6 +1200,7 @@ public:
vectorSize = parentType.vectorSize; vectorSize = parentType.vectorSize;
matrixCols = parentType.matrixCols; matrixCols = parentType.matrixCols;
matrixRows = parentType.matrixRows; matrixRows = parentType.matrixRows;
vector1 = false; // TPublicType is only GLSL which so far has no vec1
qualifier = parentType.qualifier; qualifier = parentType.qualifier;
sampler = parentType.sampler; sampler = parentType.sampler;
if (parentType.arraySizes) if (parentType.arraySizes)
@@ -1223,7 +1234,7 @@ public:
virtual TQualifier& getQualifier() { return qualifier; } virtual TQualifier& getQualifier() { return qualifier; }
virtual const TQualifier& getQualifier() const { return qualifier; } virtual const TQualifier& getQualifier() const { return qualifier; }
virtual int getVectorSize() const { return vectorSize; } virtual int getVectorSize() const { return vectorSize; } // returns 1 for either scalar or vector of size 1, valid for both
virtual int getMatrixCols() const { return matrixCols; } virtual int getMatrixCols() const { return matrixCols; }
virtual int getMatrixRows() const { return matrixRows; } virtual int getMatrixRows() const { return matrixRows; }
virtual int getOuterArraySize() const { return arraySizes->getOuterSize(); } virtual int getOuterArraySize() const { return arraySizes->getOuterSize(); }
@@ -1234,8 +1245,8 @@ public:
virtual const TArraySizes* getArraySizes() const { return arraySizes; } virtual const TArraySizes* getArraySizes() const { return arraySizes; }
virtual TArraySizes& getArraySizes() { assert(arraySizes != nullptr); return *arraySizes; } virtual TArraySizes& getArraySizes() { assert(arraySizes != nullptr); return *arraySizes; }
virtual bool isScalar() const { return vectorSize == 1 && ! isStruct() && ! isArray(); } virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray(); }
virtual bool isVector() const { return vectorSize > 1; } virtual bool isVector() const { return vectorSize > 1 || vector1; }
virtual bool isMatrix() const { return matrixCols ? true : false; } virtual bool isMatrix() const { return matrixCols ? true : false; }
virtual bool isArray() const { return arraySizes != nullptr; } virtual bool isArray() const { return arraySizes != nullptr; }
virtual bool isExplicitlySizedArray() const { return isArray() && getOuterArraySize() != UnsizedArraySize; } virtual bool isExplicitlySizedArray() const { return isArray() && getOuterArraySize() != UnsizedArraySize; }
@@ -1508,7 +1519,7 @@ public:
if (qualifier.specConstant) if (qualifier.specConstant)
p += snprintf(p, end - p, "specialization-constant "); p += snprintf(p, end - p, "specialization-constant ");
p += snprintf(p, end - p, "%s ", getStorageQualifierString()); p += snprintf(p, end - p, "%s ", getStorageQualifierString());
if (arraySizes) { if (isArray()) {
for(int i = 0; i < (int)arraySizes->getNumDims(); ++i) { for(int i = 0; i < (int)arraySizes->getNumDims(); ++i) {
int size = arraySizes->getDimSize(i); int size = arraySizes->getDimSize(i);
if (size == 0) if (size == 0)
@@ -1519,9 +1530,9 @@ public:
} }
if (qualifier.precision != EpqNone) if (qualifier.precision != EpqNone)
p += snprintf(p, end - p, "%s ", getPrecisionQualifierString()); p += snprintf(p, end - p, "%s ", getPrecisionQualifierString());
if (matrixCols > 0) if (isMatrix())
p += snprintf(p, end - p, "%dX%d matrix of ", matrixCols, matrixRows); p += snprintf(p, end - p, "%dX%d matrix of ", matrixCols, matrixRows);
else if (vectorSize > 1) else if (isVector())
p += snprintf(p, end - p, "%d-component vector of ", vectorSize); p += snprintf(p, end - p, "%d-component vector of ", vectorSize);
*p = 0; *p = 0;
@@ -1653,6 +1664,7 @@ public:
vectorSize == right.vectorSize && vectorSize == right.vectorSize &&
matrixCols == right.matrixCols && matrixCols == right.matrixCols &&
matrixRows == right.matrixRows && matrixRows == right.matrixRows &&
vector1 == right.vector1 &&
sameStructType(right); sameStructType(right);
} }
@@ -1675,9 +1687,14 @@ protected:
void buildMangledName(TString&); void buildMangledName(TString&);
TBasicType basicType : 8; TBasicType basicType : 8;
int vectorSize : 4; int vectorSize : 4; // 1 means either scalar or 1-component vector; see vector1 to disambiguate.
int matrixCols : 4; int matrixCols : 4;
int matrixRows : 4; int matrixRows : 4;
bool vector1 : 1; // Backward-compatible tracking of a 1-component vector distinguished from a scalar.
// GLSL 4.5 never has a 1-component vector; so this will always be false until such
// functionality is added.
// HLSL does have a 1-component vectors, so this will be true to disambiguate
// from a scalar.
TSampler sampler; TSampler sampler;
TQualifier qualifier; TQualifier qualifier;

View File

@@ -1629,8 +1629,10 @@ bool TIntermBinary::promote()
return false; return false;
if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize()) if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize())
return false; return false;
if (right->isVector() || right->isMatrix()) if (right->isVector() || right->isMatrix()) {
setType(TType(basicType, EvqTemporary, right->getVectorSize(), right->getMatrixCols(), right->getMatrixRows())); type.shallowCopy(right->getType());
type.getQualifier().makeTemporary();
}
break; break;
default: default:

View File

@@ -72,6 +72,7 @@ INSTANTIATE_TEST_CASE_P(
ToSpirv, HlslCompileTest, ToSpirv, HlslCompileTest,
::testing::ValuesIn(std::vector<FileNameEntryPointPair>{ ::testing::ValuesIn(std::vector<FileNameEntryPointPair>{
{"hlsl.assoc.frag", "PixelShaderFunction"}, {"hlsl.assoc.frag", "PixelShaderFunction"},
{"hlsl.float1.frag", "PixelShaderFunction"},
{"hlsl.float4.frag", "PixelShaderFunction"}, {"hlsl.float4.frag", "PixelShaderFunction"},
{"hlsl.max.frag", "PixelShaderFunction"}, {"hlsl.max.frag", "PixelShaderFunction"},
{"hlsl.precedence.frag", "PixelShaderFunction"}, {"hlsl.precedence.frag", "PixelShaderFunction"},

View File

@@ -219,8 +219,12 @@ bool HlslGrammar::acceptType(TType& type)
new(&type) TType(EbtInt); new(&type) TType(EbtInt);
break; break;
case EHTokFloat: case EHTokFloat:
new(&type) TType(EbtFloat);
break;
case EHTokFloat1: case EHTokFloat1:
new(&type) TType(EbtFloat); new(&type) TType(EbtFloat);
type.makeVector();
break; break;
case EHTokFloat2: case EHTokFloat2:

View File

@@ -1655,13 +1655,6 @@ void HlslParseContext::boolCheck(const TSourceLoc& loc, const TIntermTyped* type
error(loc, "boolean expression expected", "", ""); error(loc, "boolean expression expected", "", "");
} }
// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
void HlslParseContext::boolCheck(const TSourceLoc& loc, const TPublicType& pType)
{
if (pType.basicType != EbtBool || pType.arraySizes || pType.matrixCols > 1 || (pType.vectorSize > 1))
error(loc, "boolean expression expected", "", "");
}
// //
// Fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level. // Fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level.
// //

View File

@@ -107,7 +107,6 @@ public:
void arrayDimMerge(TType& type, const TArraySizes* sizes); void arrayDimMerge(TType& type, const TArraySizes* sizes);
bool voidErrorCheck(const TSourceLoc&, const TString&, TBasicType); bool voidErrorCheck(const TSourceLoc&, const TString&, TBasicType);
void boolCheck(const TSourceLoc&, const TIntermTyped*); void boolCheck(const TSourceLoc&, const TIntermTyped*);
void boolCheck(const TSourceLoc&, const TPublicType&);
void globalQualifierFix(const TSourceLoc&, TQualifier&); void globalQualifierFix(const TSourceLoc&, TQualifier&);
bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType); bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType);
void mergeQualifiers(const TSourceLoc&, TQualifier& dst, const TQualifier& src, bool force); void mergeQualifiers(const TSourceLoc&, TQualifier& dst, const TQualifier& src, bool force);