Adding Interface Blocks to glsl parser
Added code to parse interface blocks and the
corresponding layout qualifiers to the glsl parser.
Change-Id: Idfcbf08f3f877ea9641ae611e6bddd2be1ffb952
Reviewed-on: https://swiftshader-review.googlesource.com/3480
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/compiler/ParseHelper.cpp b/src/OpenGL/compiler/ParseHelper.cpp
index 5c95f15..9f86042 100644
--- a/src/OpenGL/compiler/ParseHelper.cpp
+++ b/src/OpenGL/compiler/ParseHelper.cpp
@@ -1762,6 +1762,42 @@
}
}
+void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
+{
+ if(shaderVersion < 300)
+ {
+ error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only", "layout");
+ recover();
+ return;
+ }
+
+ if(typeQualifier.qualifier != EvqUniform)
+ {
+ error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "global layout must be uniform");
+ recover();
+ return;
+ }
+
+ const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
+ ASSERT(!layoutQualifier.isEmpty());
+
+ if(layoutLocationErrorCheck(typeQualifier.line, typeQualifier.layoutQualifier))
+ {
+ recover();
+ return;
+ }
+
+ if(layoutQualifier.matrixPacking != EmpUnspecified)
+ {
+ defaultMatrixPacking = layoutQualifier.matrixPacking;
+ }
+
+ if(layoutQualifier.blockStorage != EbsUnspecified)
+ {
+ defaultBlockStorage = layoutQualifier.blockStorage;
+ }
+}
+
// This function is used to test for the correctness of the parameters passed to various constructor functions
// and also convert them to the right datatype if it is allowed and required.
//
@@ -1981,6 +2017,146 @@
}
//
+// Interface/uniform blocks
+//
+TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualifier, const TSourceLoc& nameLine, const TString& blockName, TFieldList* fieldList,
+ const TString* instanceName, const TSourceLoc& instanceLine, TIntermTyped* arrayIndex, const TSourceLoc& arrayIndexLine)
+{
+ if(reservedErrorCheck(nameLine, blockName))
+ recover();
+
+ if(typeQualifier.qualifier != EvqUniform)
+ {
+ error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "interface blocks must be uniform");
+ recover();
+ }
+
+ TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
+ if(layoutLocationErrorCheck(typeQualifier.line, blockLayoutQualifier))
+ {
+ recover();
+ }
+
+ if(blockLayoutQualifier.matrixPacking == EmpUnspecified)
+ {
+ blockLayoutQualifier.matrixPacking = defaultMatrixPacking;
+ }
+
+ if(blockLayoutQualifier.blockStorage == EbsUnspecified)
+ {
+ blockLayoutQualifier.blockStorage = defaultBlockStorage;
+ }
+
+ TSymbol* blockNameSymbol = new TSymbol(&blockName);
+ if(!symbolTable.declare(*blockNameSymbol)) {
+ error(nameLine, "redefinition", blockName.c_str(), "interface block name");
+ recover();
+ }
+
+ // check for sampler types and apply layout qualifiers
+ for(size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) {
+ TField* field = (*fieldList)[memberIndex];
+ TType* fieldType = field->type();
+ if(IsSampler(fieldType->getBasicType())) {
+ error(field->line(), "unsupported type", fieldType->getBasicString(), "sampler types are not allowed in interface blocks");
+ recover();
+ }
+
+ const TQualifier qualifier = fieldType->getQualifier();
+ switch(qualifier)
+ {
+ case EvqGlobal:
+ case EvqUniform:
+ break;
+ default:
+ error(field->line(), "invalid qualifier on interface block member", getQualifierString(qualifier));
+ recover();
+ break;
+ }
+
+ // check layout qualifiers
+ TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
+ if(layoutLocationErrorCheck(field->line(), fieldLayoutQualifier))
+ {
+ recover();
+ }
+
+ if(fieldLayoutQualifier.blockStorage != EbsUnspecified)
+ {
+ error(field->line(), "invalid layout qualifier:", getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here");
+ recover();
+ }
+
+ if(fieldLayoutQualifier.matrixPacking == EmpUnspecified)
+ {
+ fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
+ }
+ else if(!fieldType->isMatrix())
+ {
+ error(field->line(), "invalid layout qualifier:", getMatrixPackingString(fieldLayoutQualifier.matrixPacking), "can only be used on matrix types");
+ recover();
+ }
+
+ fieldType->setLayoutQualifier(fieldLayoutQualifier);
+ }
+
+ // add array index
+ int arraySize = 0;
+ if(arrayIndex != NULL)
+ {
+ if(arraySizeErrorCheck(arrayIndexLine, arrayIndex, arraySize))
+ recover();
+ }
+
+ TInterfaceBlock* interfaceBlock = new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier);
+ TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier, arraySize);
+
+ TString symbolName = "";
+ int symbolId = 0;
+
+ if(!instanceName)
+ {
+ // define symbols for the members of the interface block
+ for(size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
+ {
+ TField* field = (*fieldList)[memberIndex];
+ TType* fieldType = field->type();
+
+ // set parent pointer of the field variable
+ fieldType->setInterfaceBlock(interfaceBlock);
+
+ TVariable* fieldVariable = new TVariable(&field->name(), *fieldType);
+ fieldVariable->setQualifier(typeQualifier.qualifier);
+
+ if(!symbolTable.declare(*fieldVariable)) {
+ error(field->line(), "redefinition", field->name().c_str(), "interface block member name");
+ recover();
+ }
+ }
+ }
+ else
+ {
+ // add a symbol for this interface block
+ TVariable* instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
+ instanceTypeDef->setQualifier(typeQualifier.qualifier);
+
+ if(!symbolTable.declare(*instanceTypeDef)) {
+ error(instanceLine, "redefinition", instanceName->c_str(), "interface block instance name");
+ recover();
+ }
+
+ symbolId = instanceTypeDef->getUniqueId();
+ symbolName = instanceTypeDef->getName();
+ }
+
+ TIntermAggregate *aggregate = intermediate.makeAggregate(intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line), nameLine);
+ aggregate->setOp(EOpDeclaration);
+
+ exitStructDeclaration();
+ return aggregate;
+}
+
+//
// Parse an array index expression
//
TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc &location, TIntermTyped *indexExpression)