Support a uniform block to hold global uniform variables.
Used initially just by HLSL, for $Global. Could be an option for GLSL -> Vulkan.
This commit is contained in:
@@ -287,17 +287,6 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
|
||||
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)) {
|
||||
@@ -320,7 +309,10 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
|
||||
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;
|
||||
@@ -364,18 +356,29 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,7 +476,7 @@ bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
|
||||
do {
|
||||
switch (peek()) {
|
||||
case EHTokStatic:
|
||||
// normal glslang default
|
||||
qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
||||
break;
|
||||
case EHTokExtern:
|
||||
// TODO: no meaning in glslang?
|
||||
|
||||
@@ -957,6 +957,11 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
|
||||
} 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
|
||||
//
|
||||
@@ -4178,15 +4183,6 @@ void HlslParseContext::declareTypedef(const TSourceLoc& loc, TString& identifier
|
||||
//
|
||||
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;
|
||||
|
||||
@@ -4832,6 +4828,13 @@ void HlslParseContext::declareBlock(const TSourceLoc& loc, TType& type, const TS
|
||||
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
|
||||
@@ -4912,7 +4915,7 @@ void HlslParseContext::fixBlockXfbOffsets(TQualifier& qualifier, TTypeList& type
|
||||
// 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;
|
||||
@@ -4930,8 +4933,10 @@ void HlslParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList&
|
||||
// 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."
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
|
||||
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, ...);
|
||||
@@ -145,9 +146,10 @@ public:
|
||||
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&);
|
||||
@@ -160,6 +162,7 @@ public:
|
||||
void unnestLooping() { --loopNestingLevel; }
|
||||
void nestAnnotations() { ++annotationNestingLevel; }
|
||||
void unnestAnnotations() { --annotationNestingLevel; }
|
||||
int getAnnotationNestingLevel() { return annotationNestingLevel; }
|
||||
void pushScope() { symbolTable.push(); }
|
||||
void popScope() { symbolTable.pop(0); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user