// For the version, it uses the latest git tag followed by the number of commits.
// For the date, it uses the current date (when then script is run).
-#define GLSLANG_REVISION "Overload400-PrecQual.1523"
+#define GLSLANG_REVISION "Overload400-PrecQual.1524"
#define GLSLANG_DATE "27-Sep-2016"
return incumbent;
}
+//
+// Make the passed-in variable information become a member of the
+// global uniform block. If this doesn't exist yet, make it.
+//
+void TParseContextBase::growGlobalUniformBlock(TSourceLoc& loc, TType& memberType, TString& memberName)
+{
+ // make the global block, if not yet made
+ if (globalUniformBlock == nullptr) {
+ TString& blockName = *NewPoolTString(getGlobalUniformBlockName());
+ TQualifier blockQualifier;
+ blockQualifier.clear();
+ blockQualifier.storage = EvqUniform;
+ TType blockType(new TTypeList, blockName, blockQualifier);
+ TString* instanceName = NewPoolTString("");
+ globalUniformBlock = new TVariable(instanceName, blockType, true);
+ globalUniformBlockAdded = false;
+ }
+
+ // add the requested member as a member to the block
+ TType* type = new TType;
+ type->shallowCopy(memberType);
+ type->setFieldName(memberName);
+ TTypeLoc typeLoc = {type, loc};
+ globalUniformBlock->getType().getWritableStruct()->push_back(typeLoc);
+ globalUniformBlockChanged = true;
+}
+
+//
+// Insert into the symbol table the global uniform block created in
+// growGlobalUniformBlock(). The variables added as members won't be
+// found unless this is done.
+//
+bool TParseContextBase::insertGlobalUniformBlock()
+{
+ if (globalUniformBlock == nullptr)
+ return true;
+
+ if (globalUniformBlockAdded)
+ return ! globalUniformBlockChanged;
+
+ globalUniformBlockChanged = false;
+ globalUniformBlockAdded = symbolTable.insert(*globalUniformBlock);
+ if (globalUniformBlockAdded) {
+ intermediate.addSymbolLinkageNode(linkage, *globalUniformBlock);
+ finalizeGlobalUniformBlockLayout(*globalUniformBlock);
+ }
+
+ return globalUniformBlockAdded;
+}
+
} // end namespace glslang
TInfoSink& infoSink, bool forwardCompatible, EShMessages messages)
: TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
symbolTable(symbolTable),
- linkage(nullptr), scanContext(nullptr), ppContext(nullptr) { }
+ linkage(nullptr), scanContext(nullptr), ppContext(nullptr),
+ globalUniformBlock(nullptr) { }
virtual ~TParseContextBase() { }
virtual void setLimits(const TBuiltInResource&) = 0;
TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile
+ // Manage the global uniform block (default uniforms in GLSL, $Global in HLSL)
+ // TODO: This could perhaps get its own object, but the current design doesn't work
+ // yet when new uniform variables are declared between function definitions, so
+ // this is pending getting a fully functional design.
+ virtual void growGlobalUniformBlock(TSourceLoc&, TType&, TString& memberName);
+ virtual bool insertGlobalUniformBlock();
+
protected:
TParseContextBase(TParseContextBase&);
TParseContextBase& operator=(TParseContextBase&);
std::function<bool(const TType&, const TType&)>,
std::function<bool(const TType&, const TType&, const TType&)>,
/* output */ bool& tie);
+
+ // Manage the global uniform block (default uniforms in GLSL, $Global in HLSL)
+ TVariable* globalUniformBlock; // the actual block, inserted into the symbol table
+ bool globalUniformBlockAdded; // true once inserted into the symbol table
+ bool globalUniformBlockChanged; // true if members have changed
+ // override this to set the language-specific name
+ virtual const char* getGlobalUniformBlockName() { return ""; }
+ virtual void finalizeGlobalUniformBlockLayout(TVariable&) { }
};
//
if (! acceptFullySpecifiedType(declaredType))
return false;
- if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel()) {
- if (declaredType.getBasicType() == EbtSampler) {
- // Sampler/textures are uniform by default (if no explicit qualifier is present) in
- // HLSL. This line silently converts samplers *explicitly* declared static to uniform,
- // which is incorrect but harmless.
- declaredType.getQualifier().storage = EvqUniform;
- } else {
- declaredType.getQualifier().storage = EvqGlobal;
- }
- }
-
// identifier
HlslToken idToken;
while (acceptIdentifier(idToken)) {
parseContext.handleFunctionDeclarator(idToken.loc, function, true);
}
} else {
- // A variable declaration.
+ // A variable declaration. Fix the storage qualifier if it's a global.
+ if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
+ declaredType.getQualifier().storage = EvqUniform;
+
// We can handle multiple variables per type declaration, so
// the number of types can expand when arrayness is different.
TType variableType;
}
}
- if (typedefDecl)
- parseContext.declareTypedef(idToken.loc, *idToken.string, variableType, arraySizes);
- else if (variableType.getBasicType() == EbtBlock)
- parseContext.declareBlock(idToken.loc, variableType, idToken.string);
- else {
- // Declare the variable and add any initializer code to the AST.
- // The top-level node is always made into an aggregate, as that's
- // historically how the AST has been.
- node = intermediate.growAggregate(node,
- parseContext.declareVariable(idToken.loc, *idToken.string, variableType,
- expressionNode),
- idToken.loc);
+ // Hand off the actual declaration
+
+ // TODO: things scoped within an annotation need their own name space;
+ // TODO: strings are not yet handled.
+ if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) {
+ if (typedefDecl)
+ parseContext.declareTypedef(idToken.loc, *idToken.string, variableType);
+ else if (variableType.getBasicType() == EbtBlock)
+ parseContext.declareBlock(idToken.loc, variableType, idToken.string);
+ else {
+ if (variableType.getQualifier().storage == EvqUniform && variableType.getBasicType() != EbtSampler) {
+ // this isn't really an individual variable, but a member of the $Global buffer
+ parseContext.growGlobalUniformBlock(idToken.loc, variableType, *idToken.string);
+ } else {
+ // Declare the variable and add any initializer code to the AST.
+ // The top-level node is always made into an aggregate, as that's
+ // historically how the AST has been.
+ node = intermediate.growAggregate(node,
+ parseContext.declareVariable(idToken.loc, *idToken.string, variableType,
+ expressionNode),
+ idToken.loc);
+ }
+ }
}
}
do {
switch (peek()) {
case EHTokStatic:
- // normal glslang default
+ qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
break;
case EHTokExtern:
// TODO: no meaning in glslang?
} else
remapNonEntryPointIO(function);
+ // Insert the $Global constant buffer.
+ // TODO: this design fails if new members are declared between function definitions.
+ if (! insertGlobalUniformBlock())
+ error(loc, "failed to insert the global constant buffer", "uniform", "");
+
//
// New symbol table scope for body of function plus its arguments
//
//
TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, TString& identifier, TType& type, TIntermTyped* initializer)
{
- // TODO: things scoped within an annotation need their own name space;
- // haven't done that yet
- if (annotationNestingLevel > 0)
- return nullptr;
-
- // TODO: strings are not yet handled
- if (type.getBasicType() == EbtString)
- return nullptr;
-
if (voidErrorCheck(loc, identifier, type.getBasicType()))
return nullptr;
intermediate.addSymbolLinkageNode(linkage, variable);
}
+void HlslParseContext::finalizeGlobalUniformBlockLayout(TVariable& block)
+{
+ block.getWritableType().getQualifier().layoutPacking = ElpStd140;
+ block.getWritableType().getQualifier().layoutMatrix = ElmRowMajor;
+ fixBlockUniformOffsets(block.getType().getQualifier(), *block.getWritableType().getWritableStruct());
+}
+
//
// "For a block, this process applies to the entire block, or until the first member
// is reached that has a location layout qualifier. When a block member is declared with a location
// Also, compute and save the total size of the block. For the block's size, arrayness
// is not taken into account, as each element is backed by a separate buffer.
//
-void HlslParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typeList)
+void HlslParseContext::fixBlockUniformOffsets(const TQualifier& qualifier, TTypeList& typeList)
{
if (! qualifier.isUniformOrBuffer())
return;
// modify just the children's view of matrix layout, if there is one for this member
TLayoutMatrix subMatrixLayout = typeList[member].type->getQualifier().layoutMatrix;
int dummyStride;
- int memberAlignment = intermediate.getBaseAlignment(*typeList[member].type, memberSize, dummyStride, qualifier.layoutPacking == ElpStd140,
- subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : qualifier.layoutMatrix == ElmRowMajor);
+ int memberAlignment = intermediate.getBaseAlignment(*typeList[member].type, memberSize, dummyStride,
+ qualifier.layoutPacking == ElpStd140,
+ subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor
+ : qualifier.layoutMatrix == ElmRowMajor);
if (memberQualifier.hasOffset()) {
// "The specified offset must be a multiple
// of the base alignment of the type of the block member it qualifies, or a compile-time error results."
void setLimits(const TBuiltInResource&);
bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false);
+ virtual const char* getGlobalUniformBlockName() { return "$Global"; }
void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...);
TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&);
TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset);
void declareBlock(const TSourceLoc&, TType&, const TString* instanceName = 0, TArraySizes* arraySizes = 0);
+ void finalizeGlobalUniformBlockLayout(TVariable& block);
void fixBlockLocations(const TSourceLoc&, TQualifier&, TTypeList&, bool memberWithLocation, bool memberWithoutLocation);
void fixBlockXfbOffsets(TQualifier&, TTypeList&);
- void fixBlockUniformOffsets(TQualifier&, TTypeList&);
+ void fixBlockUniformOffsets(const TQualifier&, TTypeList&);
void addQualifierToExisting(const TSourceLoc&, TQualifier, const TString& identifier);
void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&);
void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&);
void unnestLooping() { --loopNestingLevel; }
void nestAnnotations() { ++annotationNestingLevel; }
void unnestAnnotations() { --annotationNestingLevel; }
+ int getAnnotationNestingLevel() { return annotationNestingLevel; }
void pushScope() { symbolTable.push(); }
void popScope() { symbolTable.pop(0); }