Add support for parsing interface blocks to the shader translator.

TRAC #22930 Signed-off-by: Nicolas Capens Signed-off-by: Geoff Lang Author: Jamie Madill git-svn-id: https://angleproject.googlecode.com/svn/branches/es3proto@2341 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent a9100887
......@@ -46,6 +46,7 @@ enum TBasicType
EbtSampler2DRect, // Only valid if GL_ARB_texture_rectangle exists.
EbtGuardSamplerEnd, // non type: see implementation of IsSampler()
EbtStruct,
EbtInterfaceBlock,
EbtAddress, // should be deprecated??
EbtInvariant // used as a type when qualifying a previously declared variable as being invariant
};
......@@ -63,6 +64,7 @@ inline const char* getBasicString(TBasicType t)
case EbtSamplerExternalOES: return "samplerExternalOES"; break;
case EbtSampler2DRect: return "sampler2DRect"; break;
case EbtStruct: return "structure"; break;
case EbtInterfaceBlock: return "interface block"; break;
default: return "unknown type";
}
}
......
......@@ -656,7 +656,7 @@ bool TParseContext::containsSampler(TType& type)
if (IsSampler(type.getBasicType()))
return true;
if (type.getBasicType() == EbtStruct) {
if (type.getBasicType() == EbtStruct || type.getBasicType() == EbtInterfaceBlock) {
TTypeList& structure = *type.getStruct();
for (unsigned int i = 0; i < structure.size(); ++i) {
if (containsSampler(*structure[i].type))
......@@ -1451,6 +1451,102 @@ TIntermTyped* TParseContext::addConstStruct(const TString &identifier, TIntermTy
return typedNode;
}
//
// Interface/uniform blocks
//
TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualifier, TSourceLoc nameLine, const TString& blockName, TTypeList* typeList,
const TString& instanceName, TSourceLoc instanceLine, TIntermTyped* arrayIndex, 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();
}
TSymbol* blockNameSymbol = new TInterfaceBlockName(&blockName);
if (!symbolTable.declare(*blockNameSymbol)) {
error(nameLine, "redefinition", blockName.c_str(), "interface block name");
recover();
}
// check for sampler types
for (size_t memberIndex = 0; memberIndex < typeList->size(); ++memberIndex) {
const TTypeLine& memberTypeLine = (*typeList)[memberIndex];
TType* memberType = memberTypeLine.type;
if (IsSampler(memberType->getBasicType())) {
error(memberTypeLine.line, "unsupported type", memberType->getBasicString(), "sampler types are not allowed in interface blocks");
recover();
}
const TQualifier qualifier = memberTypeLine.type->getQualifier();
switch (qualifier)
{
case EvqGlobal:
case EvqUniform:
break;
default:
error(memberTypeLine.line, "invalid qualifier on interface block member", getQualifierString(qualifier));
recover();
break;
}
}
TType* interfaceBlock = new TType(typeList, blockName);
interfaceBlock->setBasicType(EbtInterfaceBlock);
interfaceBlock->setQualifier(typeQualifier.qualifier);
TString symbolName = "";
int symbolId = 0;
if (instanceName == "")
{
// define symbols for the members of the interface block
for (size_t memberIndex = 0; memberIndex < typeList->size(); ++memberIndex) {
const TTypeLine& memberTypeLine = (*typeList)[memberIndex];
TType* memberType = memberTypeLine.type;
memberType->setInterfaceBlockType(interfaceBlock);
TVariable* memberVariable = new TVariable(&memberType->getFieldName(), *memberType);
memberVariable->setQualifier(typeQualifier.qualifier);
if (!symbolTable.declare(*memberVariable)) {
error(memberTypeLine.line, "redefinition", memberType->getFieldName().c_str(), "interface block member name");
recover();
}
}
}
else
{
interfaceBlock->setInstanceName(instanceName);
// add array index
if (arrayIndex != NULL)
{
int size;
if (arraySizeErrorCheck(arrayIndexLine, arrayIndex, size))
recover();
interfaceBlock->setArraySize(size);
}
// add a symbol for this interface block
TVariable* instanceTypeDef = new TVariable(&instanceName, *interfaceBlock, 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();
}
exitStructDeclaration();
TIntermAggregate *aggregate = intermediate.makeAggregate(intermediate.addSymbol(symbolId, symbolName, *interfaceBlock, typeQualifier.line), nameLine);
aggregate->setOp(EOpDeclaration);
return aggregate;
}
bool TParseContext::enterStructDeclaration(int line, const TString& identifier)
{
++structNestingLevel;
......@@ -1768,9 +1864,53 @@ TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
}
}
}
else if (baseExpression->getBasicType() == EbtInterfaceBlock)
{
bool fieldFound = false;
const TTypeList* fields = baseExpression->getType().getStruct();
if (fields == 0)
{
error(dotLocation, "interface block has no fields", "Internal Error");
recover();
indexedExpression = baseExpression;
}
else
{
unsigned int i;
for (i = 0; i < fields->size(); ++i)
{
if ((*fields)[i].type->getFieldName() == fieldString)
{
fieldFound = true;
break;
}
}
if (fieldFound)
{
ConstantUnion *unionArray = new ConstantUnion[1];
unionArray->setIConst(i);
TIntermTyped* index = intermediate.addConstantUnion(unionArray, *(*fields)[i].type, fieldLocation);
indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index, dotLocation);
indexedExpression->setType(*(*fields)[i].type);
}
else
{
error(dotLocation, " no such field in interface block", fieldString.c_str());
recover();
indexedExpression = baseExpression;
}
}
}
else
{
error(dotLocation, " field selection requires structure, vector, or matrix on left hand side", fieldString.c_str());
if (shaderVersion < 300)
{
error(dotLocation, " field selection requires structure, vector, or matrix on left hand side", fieldString.c_str());
}
else
{
error(dotLocation, " field selection requires structure, vector, matrix, or interface block on left hand side", fieldString.c_str());
}
recover();
indexedExpression = baseExpression;
}
......
......@@ -134,6 +134,9 @@ struct TParseContext {
TTypeList *addStructDeclaratorList(const TPublicType& typeSpecifier, TTypeList *typeList);
TPublicType addStructure(TSourceLoc structLine, TSourceLoc nameLine, const TString &structName, TTypeList* typeList);
TIntermAggregate* addInterfaceBlock(const TPublicType& typeQualifier, TSourceLoc nameLine, const TString& blockName, TTypeList* typeList,
const TString& instanceName, TSourceLoc instanceLine, TIntermTyped* arrayIndex, TSourceLoc arrayIndexLine);
// Performs an error check for embedded struct declarations.
// Returns true if an error was raised due to the declaration of
// this struct.
......
......@@ -22,7 +22,7 @@
TType::TType(const TPublicType &p) :
type(p.type), precision(p.precision), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize),
maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0)
maxArraySize(0), arrayInformationType(0), interfaceBlockType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0)
{
if (p.userDef) {
structure = p.userDef->getStruct();
......@@ -57,6 +57,21 @@ void TType::buildMangledName(TString& mangledName)
(*structure)[i].type->buildMangledName(mangledName);
}
}
break;
case EbtInterfaceBlock:
{
mangledName += "interface-block-";
if (typeName)
{
mangledName += *typeName;
}
for (unsigned int i = 0; i < structure->size(); ++i)
{
mangledName += '-';
(*structure)[i].type->buildMangledName(mangledName);
}
}
break;
default:
break;
}
......@@ -136,6 +151,11 @@ void TFunction::dump(TInfoSink &infoSink) const
infoSink.debug << getName().c_str() << ": " << returnType.getBasicString() << " " << getMangledName().c_str() << "\n";
}
void TInterfaceBlockName::dump(TInfoSink &infoSink) const
{
infoSink.debug << "interface block " << getName().c_str() << "\n";
}
void TSymbolTableLevel::dump(TInfoSink &infoSink) const
{
tLevel::const_iterator it;
......@@ -255,6 +275,11 @@ TFunction* TFunction::clone(TStructureMap& remapper)
return function;
}
TInterfaceBlockName* TInterfaceBlockName::clone(TStructureMap& remapper)
{
return new TInterfaceBlockName(this->name);
}
TSymbolTableLevel* TSymbolTableLevel::clone(TStructureMap& remapper)
{
TSymbolTableLevel *symTableLevel = new TSymbolTableLevel();
......
......@@ -186,6 +186,21 @@ protected:
bool defined;
};
//
// Interface block name sub-symbol
//
class TInterfaceBlockName : public TSymbol
{
public:
TInterfaceBlockName(const TString *name)
: TSymbol(name)
{}
virtual ~TInterfaceBlockName() {}
virtual void dump(TInfoSink &infoSink) const;
virtual TInterfaceBlockName* clone(TStructureMap& remapper);
};
class TSymbolTableLevel {
public:
......
......@@ -42,13 +42,13 @@ public:
TType() {}
TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false) :
type(t), precision(p), qualifier(q), size(s), matrix(m), array(a), arraySize(0),
maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0)
maxArraySize(0), arrayInformationType(0), interfaceBlockType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0), instanceName(0)
{
}
explicit TType(const TPublicType &p);
TType(TTypeList* userDef, const TString& n, TPrecision p = EbpUndefined) :
type(EbtStruct), precision(p), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0),
maxArraySize(0), arrayInformationType(0), structure(userDef), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0)
maxArraySize(0), arrayInformationType(0), interfaceBlockType(0), structure(userDef), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), instanceName(0)
{
typeName = NewPoolTString(n.c_str());
}
......@@ -91,11 +91,16 @@ public:
if (copyOf.mangled)
mangled = NewPoolTString(copyOf.mangled->c_str());
instanceName = 0;
if (copyOf.instanceName)
instanceName = NewPoolTString(copyOf.instanceName->c_str());
structureSize = copyOf.structureSize;
maxArraySize = copyOf.maxArraySize;
deepestStructNesting = copyOf.deepestStructNesting;
assert(copyOf.arrayInformationType == 0);
arrayInformationType = 0; // arrayInformationType should not be set for builtIn symbol table level
interfaceBlockType = 0;
}
TType* clone(TStructureMap& remapper)
......@@ -184,6 +189,9 @@ public:
void clearArrayness() { array = false; arraySize = 0; maxArraySize = 0; }
void setArrayInformationType(TType* t) { arrayInformationType = t; }
TType* getArrayInformationType() const { return arrayInformationType; }
void setInterfaceBlockType(TType* t) { interfaceBlockType = t; }
TType* getInterfaceBlockType() const { return interfaceBlockType; }
bool isInterfaceBlockMember() const { return interfaceBlockType != NULL; }
bool isVector() const { return size > 1 && !matrix; }
bool isScalar() const { return size == 1 && !matrix && !structure; }
......@@ -222,6 +230,25 @@ public:
return *mangled;
}
void setInstanceName(const TString& n)
{
assert(type == EbtInterfaceBlock);
instanceName = NewPoolTString(n.c_str());
}
bool hasInstanceName() const
{
assert(type == EbtInterfaceBlock);
return instanceName != NULL;
}
const TString& getInstanceName() const
{
assert(type == EbtInterfaceBlock);
assert(instanceName);
return *instanceName;
}
bool sameElementType(const TType& right) const {
return type == right.type &&
size == right.size &&
......@@ -285,6 +312,7 @@ protected:
int arraySize;
int maxArraySize;
TType* arrayInformationType;
TType* interfaceBlockType;
TTypeList* structure; // 0 unless this is a struct
mutable int structureSize;
......@@ -293,6 +321,7 @@ protected:
TString *fieldName; // for structure field names
TString *mangled;
TString *typeName; // for structure field type name
TString *instanceName; // for interface block instance names
};
//
......
......@@ -42,8 +42,8 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
#define YYLTYPE_IS_TRIVIAL 1
#define YYLEX_PARAM context->scanner
%}
%}
%expect 1 /* One shift reduce conflict because of if | else */
%pure-parser
%parse-param {TParseContext* context}
......@@ -113,9 +113,9 @@ extern void yyerror(TParseContext* context, const char* reason);
} \
}
#define ES3_ONLY(S, L) { \
#define ES3_ONLY(TOKEN, LINE, REASON) { \
if (context->shaderVersion != 300) { \
context->error(L, " supported in GLSL ES 3.00 only ", S); \
context->error(LINE, REASON " supported in GLSL ES 3.00 only ", TOKEN); \
context->recover(); \
} \
}
......@@ -177,6 +177,8 @@ extern void yyerror(TParseContext* context, const char* reason);
%type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype
%type <interm> function_call_or_method
%type <lex> enter_struct
%start translation_unit
%%
......@@ -799,6 +801,14 @@ constant_expression
}
;
enter_struct
: IDENTIFIER LEFT_BRACE {
if (context->enterStructDeclaration($1.line, *$1.string))
context->recover();
$$ = $1;
}
;
declaration
: function_prototype SEMICOLON {
TFunction &function = *($1.function);
......@@ -843,6 +853,18 @@ declaration
}
$$ = 0;
}
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON {
ES3_ONLY(getQualifierString($1.qualifier), $1.line, "interface blocks");
$$ = context->addInterfaceBlock($1, $2.line, *$2.string, $3, "", 0, NULL, 0);
}
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON {
ES3_ONLY(getQualifierString($1.qualifier), $1.line, "interface blocks");
$$ = context->addInterfaceBlock($1, $2.line, *$2.string, $3, *$5.string, $5.line, NULL, 0);
}
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET SEMICOLON {
ES3_ONLY(getQualifierString($1.qualifier), $1.line, "interface blocks");
$$ = context->addInterfaceBlock($1, $2.line, *$2.string, $3, *$5.string, $5.line, $7, $6.line);
}
;
function_prototype
......@@ -1425,22 +1447,22 @@ storage_qualifier
$$.line = $1.line;
}
| IN_QUAL {
ES3_ONLY("in", $1.line);
ES3_ONLY("in", $1.line, "storage qualifier");
$$.qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqSmoothIn : EvqAttribute;
$$.line = $1.line;
}
| OUT_QUAL {
ES3_ONLY("out", $1.line);
ES3_ONLY("out", $1.line, "storage qualifier");
$$.qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragColor : EvqSmoothOut;
$$.line = $1.line;
}
| CENTROID IN_QUAL {
ES3_ONLY("centroid in", $1.line);
ES3_ONLY("centroid in", $1.line, "storage qualifier");
$$.qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqCentroidIn : EvqAttribute;
$$.line = $1.line;
}
| CENTROID OUT_QUAL {
ES3_ONLY("centroid out", $1.line);
ES3_ONLY("centroid out", $1.line, "storage qualifier");
$$.qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragColor : EvqCentroidOut;
$$.line = $1.line;
}
......@@ -1660,6 +1682,11 @@ struct_declaration
: type_specifier struct_declarator_list SEMICOLON {
$$ = context->addStructDeclaratorList($1, $2);
}
| type_qualifier type_specifier struct_declarator_list SEMICOLON {
// ES3 Only, but errors should be handled elsewhere
$2.qualifier = $1.qualifier;
$$ = context->addStructDeclaratorList($2, $3);
}
;
struct_declarator_list
......
......@@ -85,6 +85,7 @@ enum TOperator {
EOpIndexDirect,
EOpIndexIndirect,
EOpIndexDirectStruct,
EOpIndexDirectInterfaceBlock,
EOpVectorSwizzle,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment