//
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", "");
//
// 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;
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;
}
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);
}
//
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) {
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;
}
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
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)
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;
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)
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 {
#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.
// 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;
}
}
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;
inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey)
{
- resolver.notifyInOut(stage, entKey.second);
+ resolver.notifyInOut(entKey.second.stage, entKey.second);
}
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) {
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)) {
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)) {
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;
TIoMapResolver& resolver;
TInfoSink& infoSink;
bool& error;
-
+ TVarLiveMap* uniformVarMap[EShLangCount];
private:
TResolverUniformAdaptor& operator=(TResolverUniformAdaptor&) = delete;
};
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);
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) {
// 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);
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)) {
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;
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 {
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;
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;
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;
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);
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) {
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];
}
}
-const TString& TDefaultGlslIoResolver::getAccessName(const TIntermSymbol* symbol)
-{
- return symbol->getBasicType() == EbtBlock ?
- symbol->getType().getTypeName() :
- symbol->getName();
-}
-
//TDefaultGlslIoResolver end
/*
}
// 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);
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);
//
// 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) {
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);
});
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);
}
}