8. io mapping refine & qualifier member check & resolver expand (#2396)

* Code refine and adding missing features

1. Add new level for built in symbols.
2. Fix issues for structure members' qualifiers.
3. Global qualifier fix.
4. IO Mapper refine. Add support for checking with mangle names.

* Additional missing features

* Invariant member. (Only check non-interface).

* Split block nesting level and struct nesting level. To fix issues of checking 'invariant' qualifier.

Current grammar would check block/struct member without its parent class's information.
So we split nesting level, and 'invariant' would only be checked within a struct.

* Format anonymous block names. Refine codes for symbols from all kinds of resouces.

* Fix writeonly check.

* Use LValueBase to find operator.

* Fix random null ptr issue.

* invariant check, stage in io mapping, reference parameter should be used and remove wrong codes introduced with ordering vector.

* Remained: to be fixed with double check link.vk.multiblocksValid

* Fix version error.

invariant

* Revert loc modification.
This commit is contained in:
Chow 2020-11-04 04:34:19 +08:00 committed by GitHub
parent d550bebee9
commit 478b232952
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 565 additions and 149 deletions

View file

@ -1282,6 +1282,8 @@ public:
TIntermTyped* getConstSubtree() const { return constSubtree; }
#ifndef GLSLANG_WEB
void setFlattenSubset(int subset) { flattenSubset = subset; }
virtual const TString& getAccessName() const;
int getFlattenSubset() const { return flattenSubset; } // -1 means full object
#endif

View file

@ -71,6 +71,13 @@ void TIntermConstantUnion::traverse(TIntermTraverser *it)
it->visitConstantUnion(this);
}
const TString& TIntermSymbol::getAccessName() const {
if (getBasicType() == EbtBlock)
return getType().getTypeName();
else
return getName();
}
//
// Traverse a binary node.
//

View file

@ -127,22 +127,6 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op,
{
TIntermBinary* binaryNode = node->getAsBinaryNode();
if (binaryNode) {
switch(binaryNode->getOp()) {
case EOpIndexDirect:
case EOpIndexIndirect: // fall through
case EOpIndexDirectStruct: // fall through
case EOpVectorSwizzle:
case EOpMatrixSwizzle:
return lValueErrorCheck(loc, op, binaryNode->getLeft());
default:
break;
}
error(loc, " l-value required", op, "", "");
return true;
}
const char* symbol = nullptr;
TIntermSymbol* symNode = node->getAsSymbolNode();
if (symNode != nullptr)
@ -203,15 +187,40 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op,
// Everything else is okay, no error.
//
if (message == nullptr)
{
if (binaryNode) {
switch (binaryNode->getOp()) {
case EOpIndexDirect:
case EOpIndexIndirect: // fall through
case EOpIndexDirectStruct: // fall through
case EOpVectorSwizzle:
case EOpMatrixSwizzle:
return lValueErrorCheck(loc, op, binaryNode->getLeft());
default:
break;
}
error(loc, " l-value required", op, "", "");
return true;
}
return false;
}
//
// If we get here, we have an error and a message.
//
const TIntermTyped* leftMostTypeNode = TIntermediate::findLValueBase(node, true);
if (symNode)
error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message);
else
error(loc, " l-value required", op, "(%s)", message);
if (binaryNode && binaryNode->getAsOperator()->getOp() == EOpIndexDirectStruct)
if(IsAnonymous(leftMostTypeNode->getAsSymbolNode()->getName()))
error(loc, " l-value required", op, "\"%s\" (%s)", leftMostTypeNode->getAsSymbolNode()->getAccessName().c_str(), message);
else
error(loc, " l-value required", op, "\"%s\" (%s)", leftMostTypeNode->getAsSymbolNode()->getName().c_str(), message);
else
error(loc, " l-value required", op, "(%s)", message);
return true;
}
@ -219,28 +228,41 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op,
// Test for and give an error if the node can't be read from.
void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
{
TIntermBinary* binaryNode = node->getAsBinaryNode();
const TIntermSymbol* symNode = node->getAsSymbolNode();
if (! node)
return;
TIntermBinary* binaryNode = node->getAsBinaryNode();
if (binaryNode) {
switch(binaryNode->getOp()) {
case EOpIndexDirect:
case EOpIndexIndirect:
case EOpIndexDirectStruct:
case EOpVectorSwizzle:
case EOpMatrixSwizzle:
rValueErrorCheck(loc, op, binaryNode->getLeft());
default:
break;
if (node->getQualifier().isWriteOnly()) {
const TIntermTyped* leftMostTypeNode = TIntermediate::findLValueBase(node, true);
if (symNode != nullptr)
error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str());
else if (binaryNode &&
(binaryNode->getAsOperator()->getOp() == EOpIndexDirectStruct ||
binaryNode->getAsOperator()->getOp() == EOpIndexDirect))
if(IsAnonymous(leftMostTypeNode->getAsSymbolNode()->getName()))
error(loc, "can't read from writeonly object: ", op, leftMostTypeNode->getAsSymbolNode()->getAccessName().c_str());
else
error(loc, "can't read from writeonly object: ", op, leftMostTypeNode->getAsSymbolNode()->getName().c_str());
else
error(loc, "can't read from writeonly object: ", op, "");
} else {
if (binaryNode) {
switch (binaryNode->getOp()) {
case EOpIndexDirect:
case EOpIndexIndirect:
case EOpIndexDirectStruct:
case EOpVectorSwizzle:
case EOpMatrixSwizzle:
rValueErrorCheck(loc, op, binaryNode->getLeft());
default:
break;
}
}
return;
}
TIntermSymbol* symNode = node->getAsSymbolNode();
if (symNode && symNode->getQualifier().isWriteOnly())
error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str());
}
// Add 'symbol' to the list of deferred linkage symbols, which

View file

@ -3368,7 +3368,7 @@ void TParseContext::transparentOpaqueCheck(const TSourceLoc& loc, const TType& t
//
void TParseContext::memberQualifierCheck(glslang::TPublicType& publicType)
{
globalQualifierFixCheck(publicType.loc, publicType.qualifier);
globalQualifierFixCheck(publicType.loc, publicType.qualifier, true);
checkNoShaderLayouts(publicType.loc, publicType.shaderQualifiers);
if (publicType.qualifier.isNonUniform()) {
error(publicType.loc, "not allowed on block or structure members", "nonuniformEXT", "");
@ -3379,7 +3379,7 @@ void TParseContext::memberQualifierCheck(glslang::TPublicType& publicType)
//
// Check/fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level.
//
void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier)
void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier, bool isMemberCheck)
{
bool nonuniformOkay = false;
@ -3404,6 +3404,16 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q
case EvqTemporary:
nonuniformOkay = true;
break;
case EvqUniform:
// According to GLSL spec: The std430 qualifier is supported only for shader storage blocks; a shader using
// the std430 qualifier on a uniform block will fail to compile.
// Only check the global declaration: layout(std430) uniform;
if (blockName == nullptr &&
qualifier.layoutPacking == ElpStd430)
{
error(loc, "it is invalid to declare std430 qualifier on uniform", "", "");
}
break;
default:
break;
}
@ -3411,7 +3421,9 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q
if (!nonuniformOkay && qualifier.isNonUniform())
error(loc, "for non-parameter, can only apply to 'in' or no storage qualifier", "nonuniformEXT", "");
invariantCheck(loc, qualifier);
// Storage qualifier isn't ready for memberQualifierCheck, we should skip invariantCheck for it.
if (!isMemberCheck || structNestingLevel > 0)
invariantCheck(loc, qualifier);
}
//
@ -4083,6 +4095,9 @@ void TParseContext::checkRuntimeSizable(const TSourceLoc& loc, const TIntermType
if (isRuntimeLength(base))
return;
if (base.getType().getQualifier().builtIn == EbvSampleMask)
return;
// Check for last member of a bufferreference type, which is runtime sizeable
// but doesn't support runtime length
if (base.getType().getQualifier().storage == EvqBuffer) {
@ -4634,14 +4649,14 @@ void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& quali
void TParseContext::nestedBlockCheck(const TSourceLoc& loc)
{
if (structNestingLevel > 0)
if (structNestingLevel > 0 || blockNestingLevel > 0)
error(loc, "cannot nest a block definition inside a structure or block", "", "");
++structNestingLevel;
++blockNestingLevel;
}
void TParseContext::nestedStructCheck(const TSourceLoc& loc)
{
if (structNestingLevel > 0)
if (structNestingLevel > 0 || blockNestingLevel > 0)
error(loc, "cannot nest a structure definition inside a structure or block", "", "");
++structNestingLevel;
}
@ -6537,13 +6552,15 @@ void TParseContext::declareTypeDefaults(const TSourceLoc& loc, const TPublicType
error(loc, "atomic_uint binding is too large", "binding", "");
return;
}
if(publicType.qualifier.hasOffset()) {
if (publicType.qualifier.hasOffset())
atomicUintOffsets[publicType.qualifier.layoutBinding] = publicType.qualifier.layoutOffset;
}
return;
}
if (publicType.arraySizes) {
error(loc, "expect an array name", "", "");
}
if (publicType.qualifier.hasLayout() && !publicType.qualifier.hasBufferReference())
warn(loc, "useless application of layout qualifier", "layout", "");
#endif
@ -6634,6 +6651,22 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
if (type.getQualifier().storage == EvqShared && type.containsCoopMat())
error(loc, "qualifier", "Cooperative matrix types must not be used in shared memory", "");
if (profile == EEsProfile) {
if (type.getQualifier().isPipeInput() && type.getBasicType() == EbtStruct) {
if (type.getQualifier().isArrayedIo(language)) {
TType perVertexType(type, 0);
if (perVertexType.containsArray() && perVertexType.containsBuiltIn() == false) {
error(loc, "A per vertex structure containing an array is not allowed as input in ES", type.getTypeName().c_str(), "");
}
}
else if (type.containsArray() && type.containsBuiltIn() == false) {
error(loc, "A structure containing an array is not allowed as input in ES", type.getTypeName().c_str(), "");
}
if (type.containsStructure())
error(loc, "A structure containing an struct is not allowed as input in ES", type.getTypeName().c_str(), "");
}
}
if (identifier != "gl_FragCoord" && (publicType.shaderQualifiers.originUpperLeft || publicType.shaderQualifiers.pixelCenterInteger))
error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", "");
if (identifier != "gl_FragDepth" && publicType.shaderQualifiers.getDepth() != EldNone)
@ -6956,6 +6989,15 @@ TIntermTyped* TParseContext::convertInitializerList(const TSourceLoc& loc, const
error(loc, "wrong vector size (or rows in a matrix column):", "initializer list", type.getCompleteString().c_str());
return nullptr;
}
TBasicType destType = type.getBasicType();
for (int i = 0; i < type.getVectorSize(); ++i) {
TBasicType initType = initList->getSequence()[i]->getAsTyped()->getBasicType();
if (destType != initType && !intermediate.canImplicitlyPromote(initType, destType)) {
error(loc, "type mismatch in initializer list", "initializer list", type.getCompleteString().c_str());
return nullptr;
}
}
} else {
error(loc, "unexpected initializer-list type:", "initializer list", type.getCompleteString().c_str());
return nullptr;
@ -7492,10 +7534,10 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
TType& memberType = *typeList[member].type;
TQualifier& memberQualifier = memberType.getQualifier();
const TSourceLoc& memberLoc = typeList[member].loc;
globalQualifierFixCheck(memberLoc, memberQualifier);
if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != currentBlockQualifier.storage)
error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", memberType.getFieldName().c_str(), "");
memberQualifier.storage = currentBlockQualifier.storage;
globalQualifierFixCheck(memberLoc, memberQualifier);
#ifndef GLSLANG_WEB
inheritMemoryQualifiers(currentBlockQualifier, memberQualifier);
if (currentBlockQualifier.perPrimitiveNV)
@ -8193,7 +8235,7 @@ void TParseContext::invariantCheck(const TSourceLoc& loc, const TQualifier& qual
bool pipeOut = qualifier.isPipeOutput();
bool pipeIn = qualifier.isPipeInput();
if (version >= 300 || (!isEsProfile() && version >= 420)) {
if ((version >= 300 && isEsProfile()) || (!isEsProfile() && version >= 420)) {
if (! pipeOut)
error(loc, "can only apply to an output", "invariant", "");
} else {

View file

@ -83,7 +83,7 @@ public:
: TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
scopeMangler("::"),
symbolTable(symbolTable),
statementNestingLevel(0), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0),
statementNestingLevel(0), loopNestingLevel(0), structNestingLevel(0), blockNestingLevel(0), controlFlowNestingLevel(0),
currentFunctionType(nullptr),
postEntryPointReturn(false),
contextPragma(true, false),
@ -178,7 +178,8 @@ public:
TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile
int statementNestingLevel; // 0 if outside all flow control or compound statements
int loopNestingLevel; // 0 if outside all loops
int structNestingLevel; // 0 if outside blocks and structures
int structNestingLevel; // 0 if outside structures
int blockNestingLevel; // 0 if outside blocks
int controlFlowNestingLevel; // 0 if outside all flow control
const TType* currentFunctionType; // the return type of the function that's currently being parsed
bool functionReturnsValue; // true if a non-void function has a return
@ -365,7 +366,7 @@ public:
void accStructCheck(const TSourceLoc & loc, const TType & type, const TString & identifier);
void transparentOpaqueCheck(const TSourceLoc&, const TType&, const TString& identifier);
void memberQualifierCheck(glslang::TPublicType&);
void globalQualifierFixCheck(const TSourceLoc&, TQualifier&);
void globalQualifierFixCheck(const TSourceLoc&, TQualifier&, bool isMemberCheck = false);
void globalQualifierTypeCheck(const TSourceLoc&, const TQualifier&, const TPublicType&);
bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType);
void mergeQualifiers(const TSourceLoc&, TQualifier& dst, const TQualifier& src, bool force);

View file

@ -982,7 +982,7 @@ int TScanContext::tokenizeIdentifier()
return keyword;
case PACKED:
if ((parseContext.isEsProfile() && parseContext.version < 300) ||
(!parseContext.isEsProfile() && parseContext.version < 330))
(!parseContext.isEsProfile() && parseContext.version < 140))
return reservedWord();
return identifierOrType();

View file

@ -146,6 +146,8 @@ void TType::buildMangledName(TString& mangledName) const
if (typeName)
mangledName += *typeName;
for (unsigned int i = 0; i < structure->size(); ++i) {
if ((*structure)[i].type->getBasicType() == EbtVoid)
continue;
mangledName += '-';
(*structure)[i].type->buildMangledName(mangledName);
}

View file

@ -613,20 +613,24 @@ public:
//
protected:
static const int globalLevel = 3;
bool isSharedLevel(int level) { return level <= 1; } // exclude all per-compile levels
bool isBuiltInLevel(int level) { return level <= 2; } // exclude user globals
bool isGlobalLevel(int level) { return level <= globalLevel; } // include user globals
static bool isSharedLevel(int level) { return level <= 1; } // exclude all per-compile levels
static bool isBuiltInLevel(int level) { return level <= 2; } // exclude user globals
static bool isGlobalLevel(int level) { return level <= globalLevel; } // include user globals
public:
bool isEmpty() { return table.size() == 0; }
bool atBuiltInLevel() { return isBuiltInLevel(currentLevel()); }
bool atGlobalLevel() { return isGlobalLevel(currentLevel()); }
static bool isBuiltInSymbol(int uniqueId) {
int level = uniqueId >> LevelFlagBitOffset;
return isBuiltInLevel(level);
}
void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; }
void setSeparateNameSpaces() { separateNameSpaces = true; }
void push()
{
table.push_back(new TSymbolTableLevel);
updateUniqueIdLevelFlag();
}
// Make a new symbol-table level to represent the scope introduced by a structure
@ -639,6 +643,7 @@ public:
{
assert(thisSymbol.getName().size() == 0);
table.push_back(new TSymbolTableLevel);
updateUniqueIdLevelFlag();
table.back()->setThisLevel();
insert(thisSymbol);
}
@ -648,6 +653,7 @@ public:
table[currentLevel()]->getPreviousDefaultPrecisions(p);
delete table.back();
table.pop_back();
updateUniqueIdLevelFlag();
}
//
@ -867,12 +873,20 @@ public:
table[level]->readOnly();
}
// Add current level in the high-bits of unique id
void updateUniqueIdLevelFlag() {
// clamp level to avoid overflow
uint32_t level = currentLevel() > 7 ? 7 : currentLevel();
uniqueId &= ((1 << LevelFlagBitOffset) - 1);
uniqueId |= (level << LevelFlagBitOffset);
}
protected:
TSymbolTable(TSymbolTable&);
TSymbolTable& operator=(TSymbolTableLevel&);
int currentLevel() const { return static_cast<int>(table.size()) - 1; }
static const uint32_t LevelFlagBitOffset = 28;
std::vector<TSymbolTableLevel*> table;
int uniqueId; // for unique identification in code generation
bool noBuiltInRedeclarations;

View file

@ -905,7 +905,7 @@ declaration
block_structure
: type_qualifier IDENTIFIER LEFT_BRACE { parseContext.nestedBlockCheck($1.loc); } struct_declaration_list RIGHT_BRACE {
--parseContext.structNestingLevel;
--parseContext.blockNestingLevel;
parseContext.blockName = $2.string;
parseContext.globalQualifierFixCheck($1.loc, $1.qualifier);
parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers);

View file

@ -905,7 +905,7 @@ declaration
block_structure
: type_qualifier IDENTIFIER LEFT_BRACE { parseContext.nestedBlockCheck($1.loc); } struct_declaration_list RIGHT_BRACE {
--parseContext.structNestingLevel;
--parseContext.blockNestingLevel;
parseContext.blockName = $2.string;
parseContext.globalQualifierFixCheck($1.loc, $1.qualifier);
parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers);

View file

@ -5186,7 +5186,7 @@ yyreduce:
case 104:
#line 907 "MachineIndependent/glslang.y" /* yacc.c:1646 */
{
--parseContext.structNestingLevel;
--parseContext.blockNestingLevel;
parseContext.blockName = (yyvsp[-4].lex).string;
parseContext.globalQualifierFixCheck((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).qualifier);
parseContext.checkNoShaderLayouts((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).shaderQualifiers);

View file

@ -37,9 +37,11 @@
#include "../Include/Common.h"
#include "../Include/InfoSink.h"
#include "../Include/Types.h"
#include "gl_types.h"
#include "iomapper.h"
#include "SymbolTable.h"
//
// Map IO bindings.
@ -82,17 +84,17 @@ public:
// If a global is being visited, then we should also traverse it incase it's evaluation
// ends up visiting inputs we want to tag as live
else if (base->getQualifier().storage == EvqGlobal)
addGlobalReference(base->getName());
addGlobalReference(base->getAccessName());
if (target) {
TVarEntryInfo ent = {base->getId(), base, ! traverseAll};
ent.stage = intermediate.getStage();
TVarLiveMap::iterator at = target->find(
ent.symbol->getName()); // std::lower_bound(target->begin(), target->end(), ent, TVarEntryInfo::TOrderById());
ent.symbol->getAccessName()); // std::lower_bound(target->begin(), target->end(), ent, TVarEntryInfo::TOrderById());
if (at != target->end() && at->second.id == ent.id)
at->second.live = at->second.live || ! traverseAll; // update live state
else
(*target)[ent.symbol->getName()] = ent;
(*target)[ent.symbol->getAccessName()] = ent;
}
}
@ -125,7 +127,8 @@ public:
return;
TVarEntryInfo ent = { base->getId() };
TVarLiveMap::const_iterator at = source->find(base->getName());
// Fix a defect, when block has no instance name, we need to find its block name
TVarLiveMap::const_iterator at = source->find(base->getAccessName());
if (at == source->end())
return;
@ -181,7 +184,7 @@ struct TNotifyInOutAdaptor
inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey)
{
resolver.notifyInOut(stage, entKey.second);
resolver.notifyInOut(entKey.second.stage, entKey.second);
}
private:
@ -189,12 +192,13 @@ private:
};
struct TResolverUniformAdaptor {
TResolverUniformAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e)
TResolverUniformAdaptor(EShLanguage s, TIoMapResolver& r, TVarLiveMap* uniform[EShLangCount], TInfoSink& i, bool& e)
: stage(s)
, resolver(r)
, infoSink(i)
, error(e)
{
memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*)));
}
inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
@ -206,9 +210,9 @@ struct TResolverUniformAdaptor {
ent.newIndex = -1;
const bool isValid = resolver.validateBinding(stage, ent);
if (isValid) {
resolver.resolveBinding(stage, ent);
resolver.resolveSet(stage, ent);
resolver.resolveUniformLocation(stage, ent);
resolver.resolveBinding(ent.stage, ent);
resolver.resolveSet(ent.stage, ent);
resolver.resolveUniformLocation(ent.stage, ent);
if (ent.newBinding != -1) {
if (ent.newBinding >= int(TQualifier::layoutBindingEnd)) {
@ -217,6 +221,17 @@ struct TResolverUniformAdaptor {
infoSink.info.message(EPrefixInternalError, err.c_str());
error = true;
}
if (ent.symbol->getQualifier().hasBinding()) {
for (uint32_t idx = EShLangVertex; idx < EShLangCount; ++idx) {
if (idx == ent.stage || uniformVarMap[idx] == nullptr)
continue;
auto entKey2 = uniformVarMap[idx]->find(entKey.first);
if (entKey2 != uniformVarMap[idx]->end()) {
entKey2->second.newBinding = ent.newBinding;
}
}
}
}
if (ent.newSet != -1) {
if (ent.newSet >= int(TQualifier::layoutSetEnd)) {
@ -225,6 +240,16 @@ struct TResolverUniformAdaptor {
infoSink.info.message(EPrefixInternalError, err.c_str());
error = true;
}
if (ent.symbol->getQualifier().hasSet()) {
for (uint32_t idx = EShLangVertex; idx < EShLangCount; ++idx) {
if ((idx == stage) || (uniformVarMap[idx] == nullptr))
continue;
auto entKey2 = uniformVarMap[idx]->find(entKey.first);
if (entKey2 != uniformVarMap[idx]->end()) {
entKey2->second.newSet = ent.newSet;
}
}
}
}
} else {
TString errorMsg = "Invalid binding: " + entKey.first;
@ -239,7 +264,7 @@ struct TResolverUniformAdaptor {
TIoMapResolver& resolver;
TInfoSink& infoSink;
bool& error;
TVarLiveMap* uniformVarMap[EShLangCount];
private:
TResolverUniformAdaptor& operator=(TResolverUniformAdaptor&) = delete;
};
@ -261,7 +286,7 @@ struct TResolverInOutAdaptor {
ent.newBinding = -1;
ent.newSet = -1;
ent.newIndex = -1;
const bool isValid = resolver.validateInOut(stage, ent);
const bool isValid = resolver.validateInOut(ent.stage, ent);
if (isValid) {
resolver.resolveInOutLocation(stage, ent);
resolver.resolveInOutComponent(stage, ent);
@ -296,17 +321,116 @@ private:
struct TSymbolValidater
{
TSymbolValidater(TIoMapResolver& r, TInfoSink& i, TVarLiveMap* in[EShLangCount], TVarLiveMap* out[EShLangCount],
TVarLiveMap* uniform[EShLangCount], bool& hadError)
TVarLiveMap* uniform[EShLangCount], bool& hadError, EProfile profile, int version)
: preStage(EShLangCount)
, currentStage(EShLangCount)
, nextStage(EShLangCount)
, resolver(r)
, infoSink(i)
, hadError(hadError)
, profile(profile)
, version(version)
{
memcpy(inVarMaps, in, EShLangCount * (sizeof(TVarLiveMap*)));
memcpy(outVarMaps, out, EShLangCount * (sizeof(TVarLiveMap*)));
memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*)));
std::map<TString, TString> anonymousMemberMap;
std::vector<TRange> usedUniformLocation;
std::vector<TString> usedUniformName;
usedUniformLocation.clear();
usedUniformName.clear();
for (int i = 0; i < EShLangCount; i++) {
if (uniformVarMap[i]) {
for (auto uniformVar : *uniformVarMap[i])
{
TIntermSymbol* pSymbol = uniformVar.second.symbol;
TQualifier qualifier = uniformVar.second.symbol->getQualifier();
TString symbolName = pSymbol->getAccessName();
// All the uniform needs multi-stage location check (block/default)
int uniformLocation = qualifier.layoutLocation;
if (uniformLocation != TQualifier::layoutLocationEnd) {
// Total size of current uniform, could be block, struct or other types.
int size = TIntermediate::computeTypeUniformLocationSize(pSymbol->getType());
TRange locationRange(uniformLocation, uniformLocation + size - 1);
// Combine location and component ranges
int overlapLocation = -1;
bool diffLocation = false;
// Check for collisions, except for vertex inputs on desktop targeting OpenGL
overlapLocation = checkLocationOverlap(locationRange, usedUniformLocation, symbolName, usedUniformName, diffLocation);
// Overlap locations of uniforms, regardless of components (multi stages)
if (overlapLocation == -1) {
usedUniformLocation.push_back(locationRange);
usedUniformName.push_back(symbolName);
}
else if (overlapLocation >= 0) {
if (diffLocation == true) {
TString err = "Uniform location should be equal for same uniforms: " + overlapLocation;
infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true;
break;
}
else {
TString err = "Uniform location overlaps across stages: " + overlapLocation;
infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true;
break;
}
}
}
if ((uniformVar.second.symbol->getBasicType() == EbtBlock) &&
IsAnonymous(uniformVar.second.symbol->getName()))
{
auto blockType = uniformVar.second.symbol->getType().getStruct();
for (size_t memberIdx = 0; memberIdx < blockType->size(); ++memberIdx) {
auto memberName = (*blockType)[memberIdx].type->getFieldName();
if (anonymousMemberMap.find(memberName) != anonymousMemberMap.end())
{
if (anonymousMemberMap[memberName] != uniformVar.second.symbol->getType().getTypeName())
{
TString err = "Invalid block member name: " + memberName;
infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true;
break;
}
}
else
{
anonymousMemberMap[memberName] = uniformVar.second.symbol->getType().getTypeName();
}
}
}
if (hadError)
break;
}
}
}
}
// In case we need to new an intermediate, which costs too much
int checkLocationOverlap(const TRange& locationRange, std::vector<TRange>& usedUniformLocation, const TString symbolName, std::vector<TString>& usedUniformName, bool& diffLocation)
{
for (size_t r = 0; r < usedUniformLocation.size(); ++r) {
if (usedUniformName[r] == symbolName) {
diffLocation = true;
return (usedUniformLocation[r].start == locationRange.start &&
usedUniformLocation[r].last == locationRange.last)
? -2 : std::max(locationRange.start, usedUniformLocation[r].start);
}
if (locationRange.overlap(usedUniformLocation[r])) {
// there is a collision; pick one
return std::max(locationRange.start, usedUniformLocation[r].start);
}
}
return -1; // no collision
}
inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
@ -339,11 +463,24 @@ struct TSymbolValidater
// validate stage in;
if (preStage == EShLangCount)
return;
if (name == "gl_PerVertex")
if (TSymbolTable::isBuiltInSymbol(base->getId()))
return;
if (outVarMaps[preStage] != nullptr) {
auto ent2 = outVarMaps[preStage]->find(name);
uint32_t location = base->getType().getQualifier().layoutLocation;
if (ent2 == outVarMaps[preStage]->end() &&
location != glslang::TQualifier::layoutLocationEnd) {
for (auto var = outVarMaps[preStage]->begin(); var != ent2; var++) {
if (var->second.symbol->getType().getQualifier().layoutLocation == location) {
ent2 = var;
break;
}
}
}
if (ent2 != outVarMaps[preStage]->end()) {
auto& type1 = base->getType();
auto& type2 = ent2->second.symbol->getType();
hadError = hadError || typeCheck(&type1, &type2, name.c_str(), false);
if (ent2->second.symbol->getType().getQualifier().isArrayedIo(preStage)) {
TType subType(ent2->second.symbol->getType(), 0);
subType.appendMangledName(mangleName2);
@ -351,23 +488,49 @@ struct TSymbolValidater
else {
ent2->second.symbol->getType().appendMangledName(mangleName2);
}
if (mangleName1 == mangleName2)
if (mangleName1 == mangleName2) {
// For ES 3.0 only, other versions have no such restrictions
// According to ES 3.0 spec: The type and presence of the interpolation qualifiers and
// storage qualifiers of variables with the same name declared in all linked shaders must
// match, otherwise the link command will fail.
if (profile == EEsProfile && version == 300) {
// Don't need to check smooth qualifier, as it uses the default interpolation mode
if (ent1.stage == EShLangFragment && type1.isBuiltIn() == false) {
if (type1.getQualifier().flat != type2.getQualifier().flat ||
type1.getQualifier().nopersp != type2.getQualifier().nopersp) {
TString err = "Interpolation qualifier mismatch : " + entKey.first;
infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true;
}
}
}
return;
}
else {
TString err = "Invalid In/Out variable type : " + entKey.first;
infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true;
}
}
else if (!base->getType().isBuiltIn()) {
// According to spec: A link error is generated if any statically referenced input variable
// or block does not have a matching output
if (profile == EEsProfile && ent1.live) {
hadError = true;
TString errorStr = name + ": not been declare as a output variable in pre shader stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
}
return;
}
} else if (base->getQualifier().storage == EvqVaryingOut) {
// validate stage out;
if (nextStage == EShLangCount)
return;
if (name == "gl_PerVertex")
if (TSymbolTable::isBuiltInSymbol(base->getId()))
return;
if (outVarMaps[nextStage] != nullptr) {
if (inVarMaps[nextStage] != nullptr) {
auto ent2 = inVarMaps[nextStage]->find(name);
if (ent2 != inVarMaps[nextStage]->end()) {
if (ent2->second.symbol->getType().getQualifier().isArrayedIo(nextStage)) {
@ -400,11 +563,50 @@ struct TSymbolValidater
hadError = true;
}
mangleName2.clear();
// validate instance name of blocks
if (hadError == false &&
base->getType().getBasicType() == EbtBlock &&
IsAnonymous(base->getName()) != IsAnonymous(ent2->second.symbol->getName())) {
TString err = "Matched uniform block names must also either all be lacking "
"an instance name or all having an instance name: " + entKey.first;
infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true;
}
// validate uniform block member qualifier and member names
auto& type1 = base->getType();
auto& type2 = ent2->second.symbol->getType();
if (hadError == false && base->getType().getBasicType() == EbtBlock) {
hadError = hadError || typeCheck(&type1, &type2, name.c_str(), true);
}
else {
hadError = hadError || typeCheck(&type1, &type2, name.c_str(), false);
}
}
else if (base->getBasicType() == EbtBlock)
{
if (IsAnonymous(base->getName()))
{
// The name of anonymous block member can't same with default uniform variable.
auto blockType1 = base->getType().getStruct();
for (size_t memberIdx = 0; memberIdx < blockType1->size(); ++memberIdx) {
auto memberName = (*blockType1)[memberIdx].type->getFieldName();
if (uniformVarMap[i]->find(memberName) != uniformVarMap[i]->end())
{
TString err = "Invalid Uniform variable name : " + memberName;
infoSink.info.message(EPrefixInternalError, err.c_str());
hadError = true;
break;
}
}
}
}
}
}
}
}
TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount], *uniformVarMap[EShLangCount];
// Use for mark pre stage, to get more interface symbol information.
EShLanguage preStage, currentStage, nextStage;
@ -412,9 +614,118 @@ struct TSymbolValidater
TIoMapResolver& resolver;
TInfoSink& infoSink;
bool& hadError;
EProfile profile;
int version;
private:
TSymbolValidater& operator=(TSymbolValidater&) = delete;
bool qualifierCheck(const TType* const type1, const TType* const type2, const std::string& name, bool isBlock)
{
bool hasError = false;
const TQualifier& qualifier1 = type1->getQualifier();
const TQualifier& qualifier2 = type2->getQualifier();
if (isBlock == false &&
(type1->getQualifier().storage == EvqUniform && type2->getQualifier().storage == EvqUniform) ||
(type1->getQualifier().storage == EvqGlobal && type2->getQualifier().storage == EvqGlobal)) {
if (qualifier1.precision != qualifier2.precision) {
hasError = true;
std::string errorStr = name + ": have precision conflict cross stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
if (qualifier1.hasFormat() && qualifier2.hasFormat()) {
if (qualifier1.layoutFormat != qualifier2.layoutFormat) {
hasError = true;
std::string errorStr = name + ": have layout format conflict cross stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
}
}
if (isBlock == true) {
if (qualifier1.layoutPacking != qualifier2.layoutPacking) {
hasError = true;
std::string errorStr = name + ": have layoutPacking conflict cross stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
if (qualifier1.layoutMatrix != qualifier2.layoutMatrix) {
hasError = true;
std::string errorStr = name + ": have layoutMatrix conflict cross stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
if (qualifier1.layoutOffset != qualifier2.layoutOffset) {
hasError = true;
std::string errorStr = name + ": have layoutOffset conflict cross stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
if (qualifier1.layoutAlign != qualifier2.layoutAlign) {
hasError = true;
std::string errorStr = name + ": have layoutAlign conflict cross stage.";
infoSink.info.message(EPrefixError, errorStr.c_str());
}
}
return hasError;
}
bool typeCheck(const TType* const type1, const TType* const type2, const std::string& name, bool isBlock)
{
bool hasError = false;
if (!(type1->isStruct() && type2->isStruct())) {
hasError = hasError || qualifierCheck(type1, type2, name, isBlock);
}
else {
if (type1->getBasicType() == EbtBlock && type2->getBasicType() == EbtBlock)
isBlock = true;
const TTypeList* typeList1 = type1->getStruct();
const TTypeList* typeList2 = type2->getStruct();
std::string newName = name;
size_t memberCount = typeList1->size();
size_t index2 = 0;
for (size_t index = 0; index < memberCount; index++, index2++) {
// Skip inactive member
if (typeList1->at(index).type->getBasicType() == EbtVoid)
continue;
while (index2 < typeList2->size() && typeList2->at(index2).type->getBasicType() == EbtVoid) {
++index2;
}
// TypeList1 has more members in list
if (index2 == typeList2->size()) {
std::string errorStr = name + ": struct mismatch.";
infoSink.info.message(EPrefixError, errorStr.c_str());
hasError = true;
break;
}
if (typeList1->at(index).type->getFieldName() != typeList2->at(index2).type->getFieldName()) {
std::string errorStr = name + ": member name mismatch.";
infoSink.info.message(EPrefixError, errorStr.c_str());
hasError = true;
}
else {
newName = typeList1->at(index).type->getFieldName().c_str();
}
hasError = hasError || typeCheck(typeList1->at(index).type, typeList2->at(index2).type, newName, isBlock);
}
while (index2 < typeList2->size())
{
// TypeList2 has more members
if (typeList2->at(index2).type->getBasicType() != EbtVoid) {
std::string errorStr = name + ": struct mismatch.";
infoSink.info.message(EPrefixError, errorStr.c_str());
hasError = true;
break;
}
++index2;
}
}
return hasError;
}
};
struct TSlotCollector {
@ -500,7 +811,7 @@ int TDefaultIoResolverBase::resolveSet(EShLanguage /*stage*/, TVarEntryInfo& ent
int TDefaultIoResolverBase::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) {
const TType& type = ent.symbol->getType();
const char* name = ent.symbol->getName().c_str();
const char* name = ent.symbol->getAccessName().c_str();
// kick out of not doing this
if (! doAutoLocationMapping()) {
return ent.newLocation = -1;
@ -609,7 +920,7 @@ TDefaultGlslIoResolver::TDefaultGlslIoResolver(const TIntermediate& intermediate
int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) {
const TType& type = ent.symbol->getType();
const TString& name = getAccessName(ent.symbol);
const TString& name = ent.symbol->getAccessName();
if (currentStage != stage) {
preStage = currentStage;
currentStage = stage;
@ -693,7 +1004,7 @@ int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInf
int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) {
const TType& type = ent.symbol->getType();
const TString& name = getAccessName(ent.symbol);
const TString& name = ent.symbol->getAccessName();
// kick out of not doing this
if (! doAutoLocationMapping()) {
return ent.newLocation = -1;
@ -764,7 +1075,7 @@ int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEn
int TDefaultGlslIoResolver::resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent) {
const TType& type = ent.symbol->getType();
const TString& name = getAccessName(ent.symbol);
const TString& name = ent.symbol->getAccessName();
// On OpenGL arrays of opaque types take a separate binding for each element
int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1;
TResourceType resource = getResourceType(type);
@ -839,7 +1150,7 @@ void TDefaultGlslIoResolver::endCollect(EShLanguage /*stage*/) {
void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) {
const TType& type = ent.symbol->getType();
const TString& name = getAccessName(ent.symbol);
const TString& name = ent.symbol->getAccessName();
TStorageQualifier storage = type.getQualifier().storage;
EShLanguage stage(EShLangCount);
switch (storage) {
@ -899,7 +1210,7 @@ void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink&
void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) {
const TType& type = ent.symbol->getType();
const TString& name = getAccessName(ent.symbol);
const TString& name = ent.symbol->getAccessName();
int resource = getResourceType(type);
if (type.getQualifier().hasBinding()) {
TVarSlotMap& varSlotMap = resourceSlotMap[resource];
@ -922,13 +1233,6 @@ void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink&
}
}
const TString& TDefaultGlslIoResolver::getAccessName(const TIntermSymbol* symbol)
{
return symbol->getBasicType() == EbtBlock ?
symbol->getType().getTypeName() :
symbol->getName();
}
//TDefaultGlslIoResolver end
/*
@ -1117,25 +1421,23 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSi
}
// sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
std::for_each(inVarMap.begin(), inVarMap.end(),
[&inVector](TVarLivePair p) { inVector.push_back(p); });
for (auto& var : inVarMap) { inVector.push_back(var); }
std::sort(inVector.begin(), inVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
});
std::for_each(outVarMap.begin(), outVarMap.end(),
[&outVector](TVarLivePair p) { outVector.push_back(p); });
for (auto& var : outVarMap) { outVector.push_back(var); }
std::sort(outVector.begin(), outVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
});
std::for_each(uniformVarMap.begin(), uniformVarMap.end(),
[&uniformVector](TVarLivePair p) { uniformVector.push_back(p); });
for (auto& var : uniformVarMap) { uniformVector.push_back(var); }
std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
});
bool hadError = false;
TVarLiveMap* dummyUniformVarMap[EShLangCount] = {};
TNotifyInOutAdaptor inOutNotify(stage, *resolver);
TNotifyUniformAdaptor uniformNotify(stage, *resolver);
TResolverUniformAdaptor uniformResolve(stage, *resolver, infoSink, hadError);
TResolverUniformAdaptor uniformResolve(stage, *resolver, dummyUniformVarMap, infoSink, hadError);
TResolverInOutAdaptor inOutResolve(stage, *resolver, infoSink, hadError);
resolver->beginNotifications(stage);
std::for_each(inVector.begin(), inVector.end(), inOutNotify);
@ -1143,22 +1445,22 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSi
std::for_each(uniformVector.begin(), uniformVector.end(), uniformNotify);
resolver->endNotifications(stage);
resolver->beginResolve(stage);
std::for_each(inVector.begin(), inVector.end(), inOutResolve);
for (auto& var : inVector) { inOutResolve(var); }
std::for_each(inVector.begin(), inVector.end(), [&inVarMap](TVarLivePair p) {
auto at = inVarMap.find(p.second.symbol->getName());
if (at != inVarMap.end())
auto at = inVarMap.find(p.second.symbol->getAccessName());
if (at != inVarMap.end() && p.second.id == at->second.id)
at->second = p.second;
});
std::for_each(outVector.begin(), outVector.end(), inOutResolve);
for (auto& var : outVector) { inOutResolve(var); }
std::for_each(outVector.begin(), outVector.end(), [&outVarMap](TVarLivePair p) {
auto at = outVarMap.find(p.second.symbol->getName());
if (at != outVarMap.end())
auto at = outVarMap.find(p.second.symbol->getAccessName());
if (at != outVarMap.end() && p.second.id == at->second.id)
at->second = p.second;
});
std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve);
std::for_each(uniformVector.begin(), uniformVector.end(), [&uniformVarMap](TVarLivePair p) {
auto at = uniformVarMap.find(p.second.symbol->getName());
if (at != uniformVarMap.end())
auto at = uniformVarMap.find(p.second.symbol->getAccessName());
if (at != uniformVarMap.end() && p.second.id == at->second.id)
at->second = p.second;
});
resolver->endResolve(stage);
@ -1174,9 +1476,14 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSi
//
// Returns false if the input is too malformed to do this.
bool TGlslIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSink& infoSink, TIoMapResolver* resolver) {
bool somethingToDo = !intermediate.getResourceSetBinding().empty() ||
intermediate.getAutoMapBindings() ||
intermediate.getAutoMapLocations();
// Profile and version are use for symbol validate.
profile = intermediate.getProfile();
version = intermediate.getVersion();
bool somethingToDo = ! intermediate.getResourceSetBinding().empty() || intermediate.getAutoMapBindings() ||
intermediate.getAutoMapLocations();
// Restrict the stricter condition to further check 'somethingToDo' only if 'somethingToDo' has not been set, reduce
// unnecessary or insignificant for-loop operation after 'somethingToDo' have been true.
for (int res = 0; (res < EResCount && !somethingToDo); ++res) {
@ -1236,31 +1543,30 @@ bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) {
resolver->endResolve(EShLangCount);
if (!hadError) {
//Resolve uniform location, ubo/ssbo/opaque bindings across stages
TResolverUniformAdaptor uniformResolve(EShLangCount, *resolver, infoSink, hadError);
TResolverUniformAdaptor uniformResolve(EShLangCount, *resolver, uniformVarMap, infoSink, hadError);
TResolverInOutAdaptor inOutResolve(EShLangCount, *resolver, infoSink, hadError);
TSymbolValidater symbolValidater(*resolver, infoSink, inVarMaps, outVarMaps, uniformVarMap, hadError);
TSymbolValidater symbolValidater(*resolver, infoSink, inVarMaps,
outVarMaps, uniformVarMap, hadError, profile, version);
TVarLiveVector uniformVector;
resolver->beginResolve(EShLangCount);
for (int stage = EShLangVertex; stage < EShLangCount; stage++) {
if (inVarMaps[stage] != nullptr) {
inOutResolve.setStage(EShLanguage(stage));
std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), symbolValidater);
std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), inOutResolve);
std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), symbolValidater);
std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), inOutResolve);
for (auto& var : *(inVarMaps[stage])) { symbolValidater(var); }
for (auto& var : *(inVarMaps[stage])) { inOutResolve(var); }
for (auto& var : *(outVarMaps[stage])) { symbolValidater(var); }
for (auto& var : *(outVarMaps[stage])) { inOutResolve(var); }
}
if (uniformVarMap[stage] != nullptr) {
uniformResolve.setStage(EShLanguage(stage));
// sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(),
[&uniformVector](TVarLivePair p) { uniformVector.push_back(p); });
for (auto& var : *(uniformVarMap[stage])) { uniformVector.push_back(var); }
}
}
std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
});
std::for_each(uniformVector.begin(), uniformVector.end(), symbolValidater);
std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve);
for (auto& var : uniformVector) { symbolValidater(var); }
for (auto& var : uniformVector) { uniformResolve(var); }
std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
});
@ -1269,14 +1575,18 @@ bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) {
if (intermediates[stage] != nullptr) {
// traverse each stage, set new location to each input/output and unifom symbol, set new binding to
// ubo, ssbo and opaque symbols
TVarLiveMap** pUniformVarMap = uniformVarMap;
TVarLiveMap** pUniformVarMap = uniformResolve.uniformVarMap;
std::for_each(uniformVector.begin(), uniformVector.end(), [pUniformVarMap, stage](TVarLivePair p) {
auto at = pUniformVarMap[stage]->find(p.second.symbol->getName());
if (at != pUniformVarMap[stage]->end())
auto at = pUniformVarMap[stage]->find(p.second.symbol->getAccessName());
if (at != pUniformVarMap[stage]->end() && at->second.id == p.second.id){
int resolvedBinding = at->second.newBinding;
at->second = p.second;
if (resolvedBinding > 0)
at->second.newBinding = resolvedBinding;
}
});
TVarSetTraverser iter_iomap(*intermediates[stage], *inVarMaps[stage], *outVarMaps[stage],
*uniformVarMap[stage]);
*uniformResolve.uniformVarMap[stage]);
intermediates[stage]->getTreeRoot()->traverse(&iter_iomap);
}
}

View file

@ -203,7 +203,6 @@ public:
void endCollect(EShLanguage) override;
void reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) override;
void reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) override;
const TString& getAccessName(const TIntermSymbol*);
// in/out symbol and uniform symbol are stored in the same resourceSlotMap, the storage key is used to identify each type of symbol.
// We use stage and storage qualifier to construct a storage key. it can help us identify the same storage resource used in different stage.
// if a resource is a program resource and we don't need know it usage stage, we can use same stage to build storage key.
@ -263,10 +262,12 @@ public:
class TGlslIoMapper : public TIoMapper {
public:
TGlslIoMapper() {
memset(inVarMaps, 0, sizeof(TVarLiveMap*) * EShLangCount);
memset(outVarMaps, 0, sizeof(TVarLiveMap*) * EShLangCount);
memset(uniformVarMap, 0, sizeof(TVarLiveMap*) * EShLangCount);
memset(intermediates, 0, sizeof(TIntermediate*) * EShLangCount);
memset(inVarMaps, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1));
memset(outVarMaps, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1));
memset(uniformVarMap, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1));
memset(intermediates, 0, sizeof(TIntermediate*) * (EShLangCount + 1));
profile = ENoProfile;
version = 0;
}
virtual ~TGlslIoMapper() {
for (size_t stage = 0; stage < EShLangCount; stage++) {
@ -293,6 +294,8 @@ public:
*uniformVarMap[EShLangCount];
TIntermediate* intermediates[EShLangCount];
bool hadError = false;
EProfile profile;
int version;
};
} // end namespace glslang

View file

@ -658,14 +658,17 @@ public:
blocks.back().numMembers = countAggregateMembers(type);
EShLanguageMask& stages = blocks.back().stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
if (updateStageMasks) {
EShLanguageMask& stages = blocks.back().stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
}
}
else {
blockIndex = it->second;
EShLanguageMask& stages = blocks[blockIndex].stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
if (updateStageMasks) {
EShLanguageMask& stages = blocks[blockIndex].stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
}
}
}