mirror of
https://github.com/KhronosGroup/glslang
synced 2024-09-19 12:19:53 +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
|
||||
// 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.
|
||||
//
|
||||
// '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,
|
||||
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?
|
||||
if (compString.size() > MaxSwizzleSelectors)
|
||||
if (compString.size() - firstChar > MaxSwizzleSelectors)
|
||||
error(loc, "vector swizzle too long", compString.c_str(), "");
|
||||
|
||||
// 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,
|
||||
ergba,
|
||||
estpq,
|
||||
} fieldSet[MaxSwizzleSelectors];
|
||||
enumeric,
|
||||
} fieldSet[MaxSwizzleSelectors + 1];
|
||||
|
||||
// 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) {
|
||||
switch (compString[i]) {
|
||||
switch (compString[i + firstChar]) {
|
||||
case 'x':
|
||||
selector.push_back(0);
|
||||
fieldSet[i] = exyzw;
|
||||
@ -553,6 +573,17 @@ void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TStrin
|
||||
fieldSet[i] = estpq;
|
||||
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:
|
||||
error(loc, "unknown swizzle selection", compString.c_str(), "");
|
||||
break;
|
||||
@ -561,13 +592,14 @@ void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TStrin
|
||||
|
||||
// Additional error checking.
|
||||
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(), "");
|
||||
selector.resize(i);
|
||||
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(), "");
|
||||
selector.resize(i);
|
||||
break;
|
||||
@ -579,6 +611,24 @@ void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TStrin
|
||||
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
|
||||
//
|
||||
// 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;
|
||||
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())
|
||||
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())
|
||||
requireInt8Arithmetic(loc, ".", "can't swizzle types containing (u)int8");
|
||||
|
||||
if (numeric)
|
||||
return handleNumericDotSwizzle(loc, base, selectors);
|
||||
|
||||
if (base->isScalar()) {
|
||||
if (selectors.size() == 1)
|
||||
return result;
|
||||
@ -927,6 +931,93 @@ TIntermTyped* TParseContext::handleDotSwizzle(const TSourceLoc& loc, TIntermType
|
||||
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)
|
||||
{
|
||||
// a block that needs extension checking is either 'base', or if arrayed,
|
||||
|
@ -217,7 +217,8 @@ protected:
|
||||
/* output */ bool& tie);
|
||||
|
||||
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)
|
||||
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* handleDotDereference(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);
|
||||
TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
|
||||
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
|
||||
|
@ -952,7 +952,8 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
|
||||
}
|
||||
} else if (base->isVector() || base->isScalar()) {
|
||||
TSwizzleSelectors<TVectorSelector> selectors;
|
||||
parseSwizzleSelector(loc, field, base->getVectorSize(), selectors);
|
||||
bool numeric = false;
|
||||
parseSwizzleSelector(loc, field, base->getVectorSize(), selectors, numeric);
|
||||
|
||||
if (base->isScalar()) {
|
||||
if (selectors.size() == 1)
|
||||
|
Loading…
Reference in New Issue
Block a user