#version 300 es
-layout(location = 7) in vec4 c;
+layout(location = 7) in vec3 c;
layout(LocatioN = 3) in vec4 p;
out vec4 pos;
-out vec4 color;
+out vec3 color;
layout(shared, column_major, row_major) uniform mat4 m4; // default is now shared and row_major
-//layout(std140) uniform Transform { // layout of this block is std140
-// mat4 M1; // row_major
-// layout(column_major) mat4 M2; // column major
-// mat3 N1; // row_major
-//};
-//
+layout(std140) uniform Transform { // layout of this block is std140
+ mat4 M1; // row_major
+ layout(column_major) mat4 M2; // column major
+ mat3 N1; // row_major
+} tblock;
+
//uniform T2 { // layout of this block is shared
//...
//};
//
-//layout(column_major) uniform T3 { // shared and column_major
-// mat4 M3; // column_major
-// layout(row_major) mat4 m4; // row major
-// mat3 N2; // column_major
-//};
+layout(column_major) uniform T3 { // shared and column_major
+ mat4 M3; // column_major
+ layout(row_major) mat4 m4; // row major
+ mat3 N2; // column_major
+};
void main()
{
- pos = p * m4;
- color = c;
+ pos = p * (m4 + tblock.M1 + tblock.M2);
+ color = c * tblock.N1;
}
\r
layout(shared, row_major) uniform; // default is now shared and row_major\r
\r
-layout(std140) uniform Transform { // layout of this block is std140\r
+layout(std140) uniform Transform2 { // layout of this block is std140\r
mat4 M1; // row_major\r
layout(column_major) mat4 M2; // column major\r
mat3 N1; // row_major\r
vec4 member2;\r
};\r
\r
-buffer Block {\r
+buffer Block2 {\r
coherent readonly vec4 member1;\r
coherent vec4 member2;\r
};\r
EbtBool,
EbtSampler,
EbtStruct,
+ EbtBlock,
EbtNumTypes
};
class TType {
public:
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
- explicit TType(TBasicType t, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0) :
+ TType(TBasicType t, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0) :
type(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0),
structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0),
fieldName(0), mangled(0), typeName(0)
qualifier.clear();
qualifier.storage = q;
}
- TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0) :
+ TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0) :
type(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0),
structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0),
fieldName(0), mangled(0), typeName(0)
typeName = NewPoolTString(p.userDef->getTypeName().c_str());
}
}
- explicit TType(TTypeList* userDef, const TString& n) :
+ TType(TTypeList* userDef, const TString& n, TStorageQualifier blockQualifier = EvqGlobal) :
type(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), arraySizes(0),
structure(userDef), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0)
{
sampler.clear();
qualifier.clear();
+ // is it an interface block?
+ if (blockQualifier != EvqGlobal) {
+ qualifier.storage = blockQualifier;
+ type = EbtBlock;
+ }
typeName = NewPoolTString(n.c_str());
}
- explicit TType() {}
+ TType() {}
virtual ~TType() {}
TType(const TType& type) { *this = type; }
void setArrayInformationType(TType* t) { arrayInformationType = t; }
TType* getArrayInformationType() { return arrayInformationType; }
virtual bool isVector() const { return vectorSize > 1; }
+ const char* getBasicString() const {
+ return TType::getBasicString(type);
+ }
static const char* getBasicString(TBasicType t) {
switch (t) {
case EbtVoid: return "void";
case EbtBool: return "bool";
case EbtSampler: return "sampler/image";
case EbtStruct: return "structure";
+ case EbtBlock: return "block";
default: return "unknown type";
}
}
if (type == EbtSampler)
return sampler.getString();
else
- return getBasicString(type);
+ return getBasicString();
}
- const char* getBasicString() const { return TType::getBasicString(type); }
const char* getStorageQualifierString() const { return ::getStorageQualifierString(qualifier.storage); }
const char* getPrecisionQualifierString() const { return ::getPrecisionQualifierString(qualifier.precision); }
TTypeList* getStruct() { return structure; }
{
int totalSize;
- if (getBasicType() == EbtStruct)
+ if (getBasicType() == EbtStruct || getBasicType() == EbtBlock)
totalSize = getStructSize();
else if (matrixCols)
totalSize = matrixCols * matrixRows;
//
TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
{
+ if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
+ return 0;
+
switch (op) {
case EOpLessThan:
case EOpGreaterThan:
{
TIntermTyped* child = childNode->getAsTyped();
+ if (child->getType().getBasicType() == EbtBlock)
+ return 0;
+
if (child == 0) {
infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line);
return 0;
}
//
-// Merge characteristics of the 'right' qualifier into the 'left'.
-// If there is duplication, issue error messages.
+// Merge characteristics of the 'src' qualifier into the 'dst'.
+// If there is duplication, issue error messages, unless 'force'
+// is specified, which means to just override default settings.
//
// Return true if there was an error.
//
-bool TParseContext::mergeQualifiersErrorCheck(int line, TPublicType& left, const TPublicType& right)
+bool TParseContext::mergeQualifiersErrorCheck(int line, TPublicType& dst, const TPublicType& src, bool force)
{
bool bad = false;
// Storage qualification
- if (left.qualifier.storage == EvqTemporary)
- left.qualifier.storage = right.qualifier.storage;
- else if (left.qualifier.storage == EvqIn && right.qualifier.storage == EvqOut ||
- left.qualifier.storage == EvqOut && right.qualifier.storage == EvqIn)
- left.qualifier.storage = EvqInOut;
- else if (left.qualifier.storage == EvqIn && right.qualifier.storage == EvqConst ||
- left.qualifier.storage == EvqConst && right.qualifier.storage == EvqIn)
- left.qualifier.storage = EvqConstReadOnly;
- else if ( left.qualifier.storage != EvqTemporary &&
- right.qualifier.storage != EvqTemporary) {
- error(line, "too many storage qualifiers", getStorageQualifierString(right.qualifier.storage), "");
+ if (dst.qualifier.storage == EvqTemporary || dst.qualifier.storage == EvqGlobal)
+ dst.qualifier.storage = src.qualifier.storage;
+ else if (dst.qualifier.storage == EvqIn && src.qualifier.storage == EvqOut ||
+ dst.qualifier.storage == EvqOut && src.qualifier.storage == EvqIn)
+ dst.qualifier.storage = EvqInOut;
+ else if (dst.qualifier.storage == EvqIn && src.qualifier.storage == EvqConst ||
+ dst.qualifier.storage == EvqConst && src.qualifier.storage == EvqIn)
+ dst.qualifier.storage = EvqConstReadOnly;
+ else if (src.qualifier.storage != EvqTemporary) {
+ error(line, "too many storage qualifiers", getStorageQualifierString(src.qualifier.storage), "");
bad = true;
}
// Precision qualifiers
- if (left.qualifier.precision == EpqNone)
- left.qualifier.precision = right.qualifier.precision;
- else if (right.qualifier.precision) {
- error(line, "only one precision qualifier allowed", getPrecisionQualifierString(right.qualifier.precision), "");
+ if (! force && src.qualifier.precision != EpqNone && dst.qualifier.precision != EpqNone) {
+ error(line, "only one precision qualifier allowed", getPrecisionQualifierString(src.qualifier.precision), "");
bad = true;
}
+ if (dst.qualifier.precision == EpqNone || force && src.qualifier.precision != EpqNone)
+ dst.qualifier.precision = src.qualifier.precision;
// Layout qualifiers
- mergeLayoutQualifiers(line, left, right);
+ mergeLayoutQualifiers(line, dst, src);
// other qualifiers
- #define MERGE_SINGLETON(field) bad |= left.qualifier.field && right.qualifier.field; left.qualifier.field |= right.qualifier.field;
+ #define MERGE_SINGLETON(field) bad |= dst.qualifier.field && src.qualifier.field; dst.qualifier.field |= src.qualifier.field;
MERGE_SINGLETON(invariant);
MERGE_SINGLETON(centroid);
MERGE_SINGLETON(smooth);
return converted;
}
+//
+// Do everything needed to add an interface block.
+//
+void TParseContext::addBlock(int line, TPublicType& qualifier, const TString& blockName, TTypeList& typeList, const TString* instanceName, TArraySizes arraySizes)
+{
+ // First, error checks
+
+ if (reservedErrorCheck(line, blockName)) {
+ recover();
+
+ return;
+ }
+ if (instanceName && reservedErrorCheck(line, *instanceName)) {
+ recover();
+
+ return;
+ }
+ if (qualifier.type != EbtVoid) {
+ error(line, "interface blocks cannot be declared with a type", blockName.c_str(), "");
+ recover();
+
+ return;
+ }
+ if (qualifier.qualifier.storage == EvqUniform) {
+ requireProfile(line, (EProfileMask)(~ENoProfileMask), "uniform block");
+ profileRequires(line, EEsProfile, 300, 0, "uniform block");
+ } else {
+ error(line, "only uniform interface blocks are supported", blockName.c_str(), "");
+ recover();
+
+ return;
+ }
+
+ // Build and add the interface block as a new type named blockName
+
+ TType* blockType = new TType(&typeList, blockName, qualifier.qualifier.storage);
+ TVariable* userTypeDef = new TVariable(&blockName, *blockType, true);
+ if (! symbolTable.insert(*userTypeDef)) {
+ error(line, "redefinition", blockName.c_str(), "block name");
+ recover();
+
+ return;
+ }
+
+ // TODO: semantics: check for qualifiers that don't belong within a block
+ for (unsigned int member = 0; member < typeList.size(); ++member) {
+ //printf("%s: %s\n", typeList[member].type->getFieldName().c_str(), typeList[member].type->getCompleteString().c_str());
+ }
+
+ // Add the variable, as anonymous or named instanceName
+
+ // make an anonymous variable if no name was provided
+ if (! instanceName)
+ instanceName = new TString("");
+
+ TVariable* variable = new TVariable(instanceName, *blockType);
+
+ if (! symbolTable.insert(*variable)) {
+ error(line, "redefinition", variable->getName().c_str(), "");
+ delete variable;
+ recover();
+
+ return;
+ }
+}
+
//
// This function returns the tree representation for the vector field(s) being accessed from contant vector.
// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
bool samplerErrorCheck(int line, const TPublicType& pType, const char* reason);
bool globalQualifierFixAndErrorCheck(int line, TQualifier&, const TPublicType&);
bool structQualifierErrorCheck(int line, const TPublicType& pType);
- bool mergeQualifiersErrorCheck(int line, TPublicType& left, const TPublicType& right);
+ bool mergeQualifiersErrorCheck(int line, TPublicType& dst, const TPublicType& src, bool force);
void setDefaultPrecision(int line, TPublicType&, TPrecisionQualifier);
bool parameterSamplerErrorCheck(int line, TStorageQualifier qualifier, const TType& type);
bool containsSampler(const TType& type);
TIntermTyped* addConstructor(TIntermNode*, const TType&, TOperator, TFunction*, TSourceLoc);
TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc);
TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermNode*, TSourceLoc, bool subset);
+ void addBlock(int line, TPublicType& qualifier, const TString& blockName, TTypeList& typeList, const TString* instanceName = 0, TArraySizes arraySizes = 0);
TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, TSourceLoc);
TIntermTyped* addConstMatrixNode(int , TIntermTyped*, TSourceLoc);
TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line);
TIntermTyped* addConstStruct(TString& , TIntermTyped*, TSourceLoc);
+
bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, TSourceLoc);
void requireProfile(int line, EProfileMask profileMask, const char *featureDesc);
void requireStage(int line, EShLanguageMask languageMask, const char *featureDesc);
} else if ($1->isMatrix()) {\r
parseContext.error($2.line, "field selection not allowed on matrix", ".", "");\r
parseContext.recover();\r
- } else if ($1->getBasicType() == EbtStruct) {\r
+ } else if ($1->getBasicType() == EbtStruct || $1->getBasicType() == EbtBlock) {\r
bool fieldFound = false;\r
TTypeList* fields = $1->getType().getStruct();\r
if (fields == 0) {\r
$$ = 0;\r
}\r
| type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE SEMICOLON {\r
- // block\r
+ parseContext.addBlock($2.line, $1, *$2.string, *$4);\r
$$ = 0;\r
}\r
| type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON {\r
- // block\r
+ parseContext.addBlock($2.line, $1, *$2.string, *$4, $6.string);\r
$$ = 0;\r
}\r
| type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE IDENTIFIER array_specifier SEMICOLON {\r
- // block\r
+ parseContext.addBlock($2.line, $1, *$2.string, *$4, $6.string, $7.arraySizes);\r
$$ = 0;\r
}\r
| type_qualifier SEMICOLON {\r
if ($$.type == EbtVoid)\r
$$.type = $2.type;\r
\r
- if (parseContext.mergeQualifiersErrorCheck($$.line, $$, $2))\r
+ if (parseContext.mergeQualifiersErrorCheck($$.line, $$, $2, false))\r
parseContext.recover();\r
}\r
;\r
\r
struct_specifier\r
: STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE {\r
+ // TODO: semantics: check for qualifiers that don't belong in a struct\r
TType* structure = new TType($4, *$2.string);\r
TVariable* userTypeDef = new TVariable($2.string, *structure, true);\r
if (! parseContext.symbolTable.insert(*userTypeDef)) {\r
for (unsigned int i = 0; i < $2->size(); ++i) {\r
for (unsigned int j = 0; j < $$->size(); ++j) {\r
if ((*$$)[j].type->getFieldName() == (*$2)[i].type->getFieldName()) {\r
- parseContext.error((*$2)[i].line, "duplicate field name in structure:", "struct", (*$2)[i].type->getFieldName().c_str());\r
+ parseContext.error((*$2)[i].line, "duplicate member name:", "", (*$2)[i].type->getFieldName().c_str());\r
parseContext.recover();\r
}\r
}\r
\r
$$ = $3;\r
\r
- if (parseContext.voidErrorCheck($2.line, (*$3)[0].type->getFieldName(), $2)) {\r
+ if (parseContext.voidErrorCheck($2.line, (*$3)[0].type->getFieldName(), $2))\r
+ parseContext.recover();\r
+ if (parseContext.mergeQualifiersErrorCheck($2.line, $2, $1, true))\r
parseContext.recover();\r
- }\r
for (unsigned int i = 0; i < $$->size(); ++i) {\r
//\r
// Careful not to replace already know aspects of type, like array-ness\r
//\r
(*$$)[i].type->setElementType($2.type, $2.vectorSize, $2.matrixCols, $2.matrixRows, $2.userDef);\r
-\r
+ (*$$)[i].type->getQualifier() = $2.qualifier;\r
if ($2.arraySizes)\r
(*$$)[i].type->setArraySizes($2.arraySizes);\r
if ($2.userDef)\r