mirror of
https://github.com/KhronosGroup/glslang
synced 2024-11-09 20:10:06 +00:00
Implement swizzles containing 0 and 1 to represent numbers not indexes.
This commit is contained in:
parent
b5f003d7a3
commit
94eb0cd55f
@ -481,13 +481,32 @@ const TFunction* TParseContextBase::selectFunction(
|
|||||||
// Look at a '.' field selector string and change it into numerical selectors
|
// Look at a '.' field selector string and change it into numerical selectors
|
||||||
// for a vector or scalar.
|
// for a vector or scalar.
|
||||||
//
|
//
|
||||||
|
// These are returned as indexes in selector.
|
||||||
|
// E.g. ".zy" will become selector = {2, 1}.
|
||||||
|
//
|
||||||
// Always return some form of swizzle, so the result is always usable.
|
// Always return some form of swizzle, so the result is always usable.
|
||||||
//
|
//
|
||||||
|
// '0' and '1' in the field will mean to use the numeric values of 0 and 1
|
||||||
|
// rather than the result of an index into the vector.
|
||||||
|
// These are represented by:
|
||||||
|
// '0': MaxSwizzleSelectors
|
||||||
|
// '1': MaxSwizzleSelectors + 1
|
||||||
|
// E.g., ".z01" will become selector = {2, 4, 5} (if MasSwizzleSelectors == 4).
|
||||||
|
//
|
||||||
|
// A leading underscore (prefix) will get ignored.
|
||||||
|
//
|
||||||
void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TString& compString, int vecSize,
|
void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TString& compString, int vecSize,
|
||||||
TSwizzleSelectors<TVectorSelector>& selector)
|
TSwizzleSelectors<TVectorSelector>& selector, bool& numeric)
|
||||||
{
|
{
|
||||||
|
// a swizzle does not contain numerics unless there are actually numbers
|
||||||
|
// in it, independent of whether there is a prefix
|
||||||
|
numeric = false;
|
||||||
|
|
||||||
|
// If the field uses prefix syntax, normalize it.
|
||||||
|
const int firstChar = compString[0] == '_';
|
||||||
|
|
||||||
// Too long?
|
// Too long?
|
||||||
if (compString.size() > MaxSwizzleSelectors)
|
if (compString.size() - firstChar > MaxSwizzleSelectors)
|
||||||
error(loc, "vector swizzle too long", compString.c_str(), "");
|
error(loc, "vector swizzle too long", compString.c_str(), "");
|
||||||
|
|
||||||
// Use this to test that all swizzle characters are from the same swizzle-namespace-set
|
// Use this to test that all swizzle characters are from the same swizzle-namespace-set
|
||||||
@ -495,12 +514,13 @@ void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TStrin
|
|||||||
exyzw,
|
exyzw,
|
||||||
ergba,
|
ergba,
|
||||||
estpq,
|
estpq,
|
||||||
} fieldSet[MaxSwizzleSelectors];
|
enumeric,
|
||||||
|
} fieldSet[MaxSwizzleSelectors + 1];
|
||||||
|
|
||||||
// Decode the swizzle string.
|
// Decode the swizzle string.
|
||||||
int size = std::min(MaxSwizzleSelectors, (int)compString.size());
|
const int size = std::min(MaxSwizzleSelectors, (int)compString.size() - firstChar);
|
||||||
for (int i = 0; i < size; ++i) {
|
for (int i = 0; i < size; ++i) {
|
||||||
switch (compString[i]) {
|
switch (compString[i + firstChar]) {
|
||||||
case 'x':
|
case 'x':
|
||||||
selector.push_back(0);
|
selector.push_back(0);
|
||||||
fieldSet[i] = exyzw;
|
fieldSet[i] = exyzw;
|
||||||
@ -553,6 +573,17 @@ void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TStrin
|
|||||||
fieldSet[i] = estpq;
|
fieldSet[i] = estpq;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '0':
|
||||||
|
selector.push_back(MaxSwizzleSelectors);
|
||||||
|
fieldSet[i] = enumeric;
|
||||||
|
numeric = true;
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
selector.push_back(MaxSwizzleSelectors + 1);
|
||||||
|
fieldSet[i] = enumeric;
|
||||||
|
numeric = true;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error(loc, "unknown swizzle selection", compString.c_str(), "");
|
error(loc, "unknown swizzle selection", compString.c_str(), "");
|
||||||
break;
|
break;
|
||||||
@ -561,13 +592,14 @@ void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TStrin
|
|||||||
|
|
||||||
// Additional error checking.
|
// Additional error checking.
|
||||||
for (int i = 0; i < selector.size(); ++i) {
|
for (int i = 0; i < selector.size(); ++i) {
|
||||||
if (selector[i] >= vecSize) {
|
if (selector[i] < MaxSwizzleSelectors && selector[i] >= vecSize) {
|
||||||
error(loc, "vector swizzle selection out of range", compString.c_str(), "");
|
error(loc, "vector swizzle selection out of range", compString.c_str(), "");
|
||||||
selector.resize(i);
|
selector.resize(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i > 0 && fieldSet[i] != fieldSet[i-1]) {
|
if (i > 0 && fieldSet[i] != enumeric && fieldSet[i-1] != enumeric &&
|
||||||
|
fieldSet[i] != fieldSet[i-1]) {
|
||||||
error(loc, "vector swizzle selectors not from the same set", compString.c_str(), "");
|
error(loc, "vector swizzle selectors not from the same set", compString.c_str(), "");
|
||||||
selector.resize(i);
|
selector.resize(i);
|
||||||
break;
|
break;
|
||||||
@ -579,6 +611,24 @@ void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TStrin
|
|||||||
selector.push_back(0);
|
selector.push_back(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TParseContextBase::replicateRValue(TIntermTyped* node, int num, TVector<TIntermTyped*>& replicates)
|
||||||
|
{
|
||||||
|
if (num == 0)
|
||||||
|
return;
|
||||||
|
if (num == 1) {
|
||||||
|
replicates.push_back(node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node->getAsSymbolNode()) {
|
||||||
|
replicates.push_back(node);
|
||||||
|
for (int i = 1; i < num; ++i)
|
||||||
|
replicates.push_back(intermediate.addSymbol(*node->getAsSymbolNode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// WIP: a complex expression needs to be evaluated exactly once, and then
|
||||||
|
// copies of the result put into the replicates.
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_HLSL
|
#ifdef ENABLE_HLSL
|
||||||
//
|
//
|
||||||
// Make the passed-in variable information become a member of the
|
// Make the passed-in variable information become a member of the
|
||||||
|
@ -886,7 +886,8 @@ TIntermTyped* TParseContext::handleDotSwizzle(const TSourceLoc& loc, TIntermType
|
|||||||
}
|
}
|
||||||
|
|
||||||
TSwizzleSelectors<TVectorSelector> selectors;
|
TSwizzleSelectors<TVectorSelector> selectors;
|
||||||
parseSwizzleSelector(loc, field, base->getVectorSize(), selectors);
|
bool numeric = false;
|
||||||
|
parseSwizzleSelector(loc, field, base->getVectorSize(), selectors, numeric);
|
||||||
|
|
||||||
if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitFloat())
|
if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitFloat())
|
||||||
requireFloat16Arithmetic(loc, ".", "can't swizzle types containing float16");
|
requireFloat16Arithmetic(loc, ".", "can't swizzle types containing float16");
|
||||||
@ -895,6 +896,9 @@ TIntermTyped* TParseContext::handleDotSwizzle(const TSourceLoc& loc, TIntermType
|
|||||||
if (base->isVector() && selectors.size() != 1 && base->getType().contains8BitInt())
|
if (base->isVector() && selectors.size() != 1 && base->getType().contains8BitInt())
|
||||||
requireInt8Arithmetic(loc, ".", "can't swizzle types containing (u)int8");
|
requireInt8Arithmetic(loc, ".", "can't swizzle types containing (u)int8");
|
||||||
|
|
||||||
|
if (numeric)
|
||||||
|
return handleNumericDotSwizzle(loc, base, selectors);
|
||||||
|
|
||||||
if (base->isScalar()) {
|
if (base->isScalar()) {
|
||||||
if (selectors.size() == 1)
|
if (selectors.size() == 1)
|
||||||
return result;
|
return result;
|
||||||
@ -927,6 +931,93 @@ TIntermTyped* TParseContext::handleDotSwizzle(const TSourceLoc& loc, TIntermType
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle a swizzle operation where at least one selector is numeric.
|
||||||
|
//
|
||||||
|
// Can return
|
||||||
|
// - a scalar constant (e.g. for ._1), but converted to the right type
|
||||||
|
// and constant folded
|
||||||
|
// - a vector constructor
|
||||||
|
// - a sequence containing
|
||||||
|
// 1. evaluation of 'base'
|
||||||
|
// 2. a scalar constant, converted, folded
|
||||||
|
// - a sequence containing
|
||||||
|
// 1. evaluation of 'base'
|
||||||
|
// 2. a vector constructor
|
||||||
|
//
|
||||||
|
// Note that none of the above include swizzle operations.
|
||||||
|
//
|
||||||
|
// Note: A vector constructor might require copies of the rvalue being swizzled,
|
||||||
|
// to avoid the tree accidentally becoming a DAG when there are multiple
|
||||||
|
// letter swizzles present needing multiple operations to get the
|
||||||
|
// components. This is quite unlike how swizzles are handled, or any
|
||||||
|
// other native GLSL operation.
|
||||||
|
//
|
||||||
|
TIntermTyped* TParseContext::handleNumericDotSwizzle(const TSourceLoc& loc, TIntermTyped* base,
|
||||||
|
const TSwizzleSelectors<TVectorSelector>& selectors)
|
||||||
|
{
|
||||||
|
const auto isLetter = [](int selector) { return selector < MaxSwizzleSelectors; };
|
||||||
|
const auto isNumber = [isLetter](int selector) { return !isLetter(selector); };
|
||||||
|
const auto getNumber = [](int selector) { return selector - MaxSwizzleSelectors; };
|
||||||
|
|
||||||
|
// The type of the result has the 'base' component type,
|
||||||
|
// but the component-count of 'selectors'.
|
||||||
|
TType type(base->getBasicType(), EvqTemporary, selectors.size());
|
||||||
|
|
||||||
|
// If only one selector, the result is a scalar.
|
||||||
|
// But, its type might be changing, so add a constructor.
|
||||||
|
// This will always result in an already folded scalar front-end constant.
|
||||||
|
if (selectors.size() == 1) {
|
||||||
|
assert(isNumber(selectors[0]));
|
||||||
|
return addConstructor(loc, intermediate.addConstantUnion(getNumber(selectors[0]), loc), type);
|
||||||
|
|
||||||
|
// WIP: this is incorrect if 'base' had side effects, it still needs to
|
||||||
|
// be evaluated as part of a sequence operation, unless the
|
||||||
|
// specification for this operation says those side effects are ignored.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, the result is like making a vector constructor,
|
||||||
|
// where we know we have more than one argument.
|
||||||
|
|
||||||
|
// Collect the arguments.
|
||||||
|
// This is complicated by the presence of more than one letter selector,
|
||||||
|
// because we need to reuse the r-value for each one, so it is a rare
|
||||||
|
// situation of needing to replicate the r-value.
|
||||||
|
|
||||||
|
// count the letter selectors (unless the base is a constant))
|
||||||
|
int letterCount = 0;
|
||||||
|
if (!base->getType().getQualifier().isFrontEndConstant()) {
|
||||||
|
for (int s = 0; s < selectors.size(); ++s)
|
||||||
|
letterCount += isLetter(selectors[s]) ? 1 : 0;
|
||||||
|
}
|
||||||
|
// get the replicates
|
||||||
|
TVector<TIntermTyped*> replicates;
|
||||||
|
replicateRValue(base, letterCount, replicates);
|
||||||
|
|
||||||
|
// process all the selectors to make the vector
|
||||||
|
TIntermAggregate* args = nullptr;
|
||||||
|
for (int s = 0; s < (int)selectors.size(); ++s) {
|
||||||
|
if (isNumber(selectors[s])) {
|
||||||
|
args = intermediate.growAggregate(args, intermediate.addConstantUnion(getNumber(selectors[s]), loc));
|
||||||
|
} else {
|
||||||
|
// traditional swizzle selector, which needs to consume the replicates
|
||||||
|
// (unless base is a constant)
|
||||||
|
TIntermTyped* arg;
|
||||||
|
if (base->getType().getQualifier().isFrontEndConstant()) {
|
||||||
|
arg = intermediate.foldDereference(base, selectors[s], loc);
|
||||||
|
} else {
|
||||||
|
TIntermTyped* rep = replicates.back();
|
||||||
|
replicates.pop_back();
|
||||||
|
TIntermTyped* index = intermediate.addConstantUnion(selectors[s], loc);
|
||||||
|
arg = intermediate.addIndex(EOpIndexDirect, rep, index, loc);
|
||||||
|
}
|
||||||
|
args = intermediate.growAggregate(args, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// form the constructor
|
||||||
|
return addConstructor(loc, args, type)->getAsAggregate();
|
||||||
|
}
|
||||||
|
|
||||||
void TParseContext::blockMemberExtensionCheck(const TSourceLoc& loc, const TIntermTyped* base, int member, const TString& memberName)
|
void TParseContext::blockMemberExtensionCheck(const TSourceLoc& loc, const TIntermTyped* base, int member, const TString& memberName)
|
||||||
{
|
{
|
||||||
// a block that needs extension checking is either 'base', or if arrayed,
|
// a block that needs extension checking is either 'base', or if arrayed,
|
||||||
|
@ -217,7 +217,8 @@ protected:
|
|||||||
/* output */ bool& tie);
|
/* output */ bool& tie);
|
||||||
|
|
||||||
virtual void parseSwizzleSelector(const TSourceLoc&, const TString&, int size,
|
virtual void parseSwizzleSelector(const TSourceLoc&, const TString&, int size,
|
||||||
TSwizzleSelectors<TVectorSelector>&);
|
TSwizzleSelectors<TVectorSelector>&, bool& numeric);
|
||||||
|
virtual void replicateRValue(TIntermTyped* node, int n, TVector<TIntermTyped*>& replicates);
|
||||||
|
|
||||||
// Manage the global uniform block (default uniforms in GLSL, $Global in HLSL)
|
// Manage the global uniform block (default uniforms in GLSL, $Global in HLSL)
|
||||||
TVariable* globalUniformBlock; // the actual block, inserted into the symbol table
|
TVariable* globalUniformBlock; // the actual block, inserted into the symbol table
|
||||||
@ -316,6 +317,8 @@ public:
|
|||||||
TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode);
|
TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode);
|
||||||
TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field);
|
TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field);
|
||||||
TIntermTyped* handleDotSwizzle(const TSourceLoc&, TIntermTyped* base, const TString& field);
|
TIntermTyped* handleDotSwizzle(const TSourceLoc&, TIntermTyped* base, const TString& field);
|
||||||
|
TIntermTyped* handleNumericDotSwizzle(const TSourceLoc&, TIntermTyped* base,
|
||||||
|
const TSwizzleSelectors<TVectorSelector>&);
|
||||||
void blockMemberExtensionCheck(const TSourceLoc&, const TIntermTyped* base, int member, const TString& memberName);
|
void blockMemberExtensionCheck(const TSourceLoc&, const TIntermTyped* base, int member, const TString& memberName);
|
||||||
TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
|
TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
|
||||||
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
|
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
|
||||||
|
@ -952,7 +952,8 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
|
|||||||
}
|
}
|
||||||
} else if (base->isVector() || base->isScalar()) {
|
} else if (base->isVector() || base->isScalar()) {
|
||||||
TSwizzleSelectors<TVectorSelector> selectors;
|
TSwizzleSelectors<TVectorSelector> selectors;
|
||||||
parseSwizzleSelector(loc, field, base->getVectorSize(), selectors);
|
bool numeric = false;
|
||||||
|
parseSwizzleSelector(loc, field, base->getVectorSize(), selectors, numeric);
|
||||||
|
|
||||||
if (base->isScalar()) {
|
if (base->isScalar()) {
|
||||||
if (selectors.size() == 1)
|
if (selectors.size() == 1)
|
||||||
|
Loading…
Reference in New Issue
Block a user