Add layout binding qualifier for blocks and samplers (atomics are not yet in, nor link validation).

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23590 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2013-10-18 21:37:55 +00:00
parent 8f13e1322d
commit ab3080353a
8 changed files with 155 additions and 54 deletions

View File

@ -62,3 +62,12 @@ void bar(in highp volatile vec4 v)
f.xxxxx; // ERROR
f.xxy; // ERROR
}
layout(binding = 3) uniform; // ERROR
layout(binding = 3) uniform boundblock { int aoeu; } boundInst;
layout(binding = 7) uniform anonblock { int aoeu; } ;
layout(location = 1) in; // ERROR
layout(binding = 1) in inblock { int aoeua; }; // ERROR
layout(binding = 100000) uniform anonblock2 { int aooeu; } ;
layout(binding = 4) uniform sampler2D sampb1;
layout(binding = 5) uniform sampler2D sampb2[10];

View File

@ -1,4 +1,4 @@
ERROR: 0:4: 'color' : can only use location layout qualifier on a vertex input or fragment output
ERROR: 0:4: 'input location layout qualifier' : not supported in this stage: fragment
ERROR: 1 compilation errors. No code generated.
ERROR: node is still EOpNull!

View File

@ -7,7 +7,7 @@ ERROR: 0:19: 'badf' : member of uniform block cannot have an auxiliary or interp
ERROR: 0:20: 'badg' : member storage qualifier cannot contradict block storage qualifier
ERROR: 0:28: 'T3' : nameless block contains a member that already has a name at global scope
ERROR: 0:35: 'output block' : not supported with this profile: es
ERROR: 0:39: 'badoutA' : can only use location layout qualifier on a vertex input or fragment output
ERROR: 0:39: 'output location layout qualifier' : not supported in this stage: vertex
ERROR: 0:47: 'shared' : not supported with this profile: es
ERROR: 0:47: 'shared' : not supported in this stage: vertex
ERROR: 12 compilation errors. No code generated.
@ -33,11 +33,11 @@ ERROR: node is still EOpNull!
0:43 Constant:
0:43 1 (const int)
0:43 M4: direct index for structure (layout(row_major shared ) highp 4X4 matrix of float)
0:43 '__anon__1' (layout(shared ) uniform block)
0:43 '__anon__1' (layout(column_major shared ) uniform block)
0:43 Constant:
0:43 1 (const uint)
0:43 M3: direct index for structure (layout(column_major shared ) highp 4X4 matrix of float)
0:43 '__anon__1' (layout(shared ) uniform block)
0:43 '__anon__1' (layout(column_major shared ) uniform block)
0:43 Constant:
0:43 0 (const uint)
0:43 t2m: direct index for structure (layout(row_major shared ) highp 4X4 matrix of float)

View File

@ -20,7 +20,11 @@ ERROR: 0:44: '=' : cannot convert from 'float' to 'int'
ERROR: 0:54: 'y' : vector field selection out of range
ERROR: 0:62: 'xxxxx' : illegal vector field selection
ERROR: 0:63: 'xxy' : vector field selection out of range
ERROR: 20 compilation errors. No code generated.
ERROR: 0:66: 'binding' : cannot declare a default, include a type or full declaration
ERROR: 0:69: 'location' : cannot declare a default, use a full declaration
ERROR: 0:70: 'binding' : requires uniform or buffer storage qualifier
ERROR: 0:71: 'binding' : binding is too large
ERROR: 24 compilation errors. No code generated.
ERROR: node is still EOpNull!
0:20 Function Definition: foo( (const int)
@ -112,6 +116,12 @@ ERROR: node is still EOpNull!
0:? 4.200000
0:? 'dx' (const float)
0:? 4.200000
0:? 'boundInst' (layout(binding=3 shared ) uniform block)
0:? '__anon__0' (layout(binding=7 shared ) uniform block)
0:? '__anon__1' (layout(binding=1 ) in block)
0:? '__anon__2' (layout(shared ) uniform block)
0:? 'sampb1' (layout(binding=4 ) uniform sampler2D)
0:? 'sampb2' (layout(binding=5 ) uniform 10-element array of sampler2D)
0:? 'gl_VertexID' (gl_VertexId int)
0:? 'gl_InstanceID' (gl_InstanceId int)

View File

@ -15,23 +15,20 @@ ERROR: 0:46: 'stream' : there is no such layout identifier taking an assigned va
ERROR: 0:47: 'stream' : there is no such layout identifier taking an assigned value
ERROR: 0:50: 'stream' : there is no such layout identifier taking an assigned value
ERROR: 0:55: 'stream' : there is no such layout identifier taking an assigned value
ERROR: 0:77: 'binding' : not supported
ERROR: 0:80: 's17' : redefinition
ERROR: 0:85: 'binding' : not supported
ERROR: 0:85: 'offset' : there is no such layout identifier taking an assigned value
ERROR: 0:87: 'binding' : not supported
ERROR: 0:89: 'binding' : not supported
ERROR: 0:85: 'binding' : requires block, or sampler/image, or atomic-counter type
ERROR: 0:87: 'binding' : requires block, or sampler/image, or atomic-counter type
ERROR: 0:89: 'offset' : there is no such layout identifier taking an assigned value
ERROR: 0:91: 'binding' : not supported
WARNING: 0:89: '' : cannot set qualifier defaults when using a type and no identifier
ERROR: 0:91: 'bar' : redefinition
ERROR: 0:92: 'offset' : there is no such layout identifier taking an assigned value
ERROR: 0:92: 'bar' : redefinition
ERROR: 0:94: 'binding' : not supported
ERROR: 0:94: 'offset' : there is no such layout identifier taking an assigned value
ERROR: 0:94: 'a2' : redefinition
ERROR: 0:95: 'binding' : not supported
ERROR: 0:96: 'binding' : not supported
ERROR: 0:97: 'binding' : not supported
ERROR: 0:95: 'binding' : requires block, or sampler/image, or atomic-counter type
ERROR: 0:96: 'binding' : requires block, or sampler/image, or atomic-counter type
ERROR: 0:97: 'binding' : requires block, or sampler/image, or atomic-counter type
ERROR: 0:106: '' : vertex input cannot be further qualified
ERROR: 0:112: 'ColorIvn' : identifier not previously declared
ERROR: 0:132: 'shared' : not supported in this stage: vertex
@ -43,7 +40,7 @@ ERROR: 0:153: '' : function does not return a value: func3
ERROR: 0:192: 'constructor' : constructing from a non-dereferenced array
ERROR: 0:193: 'constructor' : constructing from a non-dereferenced array
ERROR: 0:194: 'constructor' : constructing from a non-dereferenced array
ERROR: 44 compilation errors. No code generated.
ERROR: 40 compilation errors. No code generated.
ERROR: node is still EOpNull!
0:134 Function Definition: funcA(I21; (4-component vector of float)
@ -289,13 +286,13 @@ ERROR: node is still EOpNull!
0:? '__anon__2' (out block)
0:? 'var7' (smooth out 4-component vector of float)
0:? '__anon__3' (layout(std140 ) uniform block)
0:? '__anon__4' (layout(shared ) uniform block)
0:? 's17' (uniform sampler2D)
0:? 'a2' (uniform int)
0:? 'bar' (uniform int)
0:? 'b2' (uniform int)
0:? 'c2' (uniform int)
0:? 'd2' (uniform int)
0:? '__anon__4' (layout(column_major shared ) uniform block)
0:? 's17' (layout(binding=3 ) uniform sampler2D)
0:? 'a2' (layout(binding=2 ) uniform int)
0:? 'bar' (layout(binding=2 ) uniform int)
0:? 'b2' (layout(binding=2 ) uniform int)
0:? 'c2' (layout(binding=3 ) uniform int)
0:? 'd2' (layout(binding=2 ) uniform int)
0:? '__anon__5' (out block)
0:? 'ColorInv' (smooth out 3-component vector of float)
0:? 'Color4' (invariant centroid smooth out 3-component vector of float)
@ -306,7 +303,7 @@ ERROR: node is still EOpNull!
0:? 'c' (in 4-component vector of float)
0:? 'd' (in 4-component vector of float)
0:? 'v' (smooth out 4-component vector of float)
0:? '__anon__6' (layout(shared ) uniform block)
0:? '__anon__6' (layout(shared ) coherent uniform block)
0:? '__anon__7' (layout(shared ) uniform block)
0:? 'shv' (shared 4-component vector of float)
0:? 'img1' (uniform image2D)

View File

@ -297,21 +297,29 @@ public:
layoutMatrix = ElmNone;
layoutPacking = ElpNone;
layoutSlotLocation = layoutLocationEnd;
layoutBinding = layoutBindingEnd;
}
bool hasLayout() const
{
return layoutMatrix != ElmNone ||
layoutPacking != ElpNone ||
layoutSlotLocation != layoutLocationEnd;
hasLocation() ||
hasBinding();
}
TLayoutMatrix layoutMatrix : 3;
TLayoutPacking layoutPacking : 4;
unsigned int layoutSlotLocation : 7; // ins/outs should have small numbers, buffer offsets could be large
static const unsigned int layoutLocationEnd = 0x3F;
unsigned int layoutBinding : 8;
static const unsigned int layoutBindingEnd = 0xFF;
bool hasLocation() const
{
return layoutSlotLocation != layoutLocationEnd;
}
bool hasBinding() const
{
return layoutBinding != layoutBindingEnd;
}
static const char* getLayoutPackingString(TLayoutPacking packing)
{
switch (packing) {
@ -430,17 +438,20 @@ public:
typeName = NewPoolTString(p.userDef->getTypeName().c_str());
}
}
TType(TTypeList* userDef, const TString& n, TStorageQualifier blockQualifier = EvqGlobal) :
basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), arraySizes(0),
structure(userDef), fieldName(0)
TType(TTypeList* userDef, const TString& n) :
basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0),
arraySizes(0), structure(userDef), fieldName(0)
{
sampler.clear();
qualifier.clear();
// is it an interface block?
if (blockQualifier != EvqGlobal) {
qualifier.storage = blockQualifier;
basicType = EbtBlock;
}
typeName = NewPoolTString(n.c_str());
}
// For interface blocks
TType(TTypeList* userDef, const TString& n, const TQualifier& q) :
basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0),
qualifier(q), arraySizes(0), structure(userDef), fieldName(0)
{
sampler.clear();
typeName = NewPoolTString(n.c_str());
}
virtual ~TType() {}
@ -628,6 +639,8 @@ public:
p += snprintf(p, end - p, "layout(");
if (qualifier.hasLocation())
p += snprintf(p, end - p, "location=%d ", qualifier.layoutSlotLocation);
if (qualifier.hasBinding())
p += snprintf(p, end - p, "binding=%d ", qualifier.layoutBinding);
if (qualifier.layoutMatrix != ElmNone)
p += snprintf(p, end - p, "%s ", TQualifier::getLayoutMatrixString(qualifier.layoutMatrix));
if (qualifier.layoutPacking != ElpNone)

View File

@ -2086,7 +2086,8 @@ void TParseContext::finalize()
// Layout qualifier stuff.
//
// Put the id's layout qualification into the public type.
// Put the id's layout qualification into the public type. This is before we know any
// type information for error checking.
void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType, TString& id)
{
std::transform(id.begin(), id.end(), id.begin(), ::tolower);
@ -2100,28 +2101,38 @@ void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType,
publicType.qualifier.layoutPacking = ElpShared;
else if (id == TQualifier::getLayoutPackingString(ElpStd140))
publicType.qualifier.layoutPacking = ElpStd140;
else if (id == TQualifier::getLayoutPackingString(ElpStd430))
else if (id == TQualifier::getLayoutPackingString(ElpStd430)) {
requireProfile(loc, ECoreProfile | ECompatibilityProfile, "std430");
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, 0, "std430");
publicType.qualifier.layoutPacking = ElpStd430;
else if (id == "location")
} else if (id == "location")
error(loc, "requires an integer assignment (e.g., location = 4)", "location", "");
else if (id == "binding")
else if (id == "binding") {
error(loc, "requires an integer assignment (e.g., binding = 4)", "binding", "");
else
} else
error(loc, "unrecognized layout identifier", id.c_str(), "");
}
// Put the id's layout qualifier value into the public type.
// Put the id's layout qualifier value into the public type. This is before we know any
// type information for error checking.
void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType, TString& id, int value)
{
std::transform(id.begin(), id.end(), id.begin(), ::tolower);
if (id == "location") {
requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, "location");
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 330, 0, "location");
if ((unsigned int)value >= TQualifier::layoutLocationEnd)
error(loc, "value is too large", id.c_str(), "");
error(loc, "location is too large", id.c_str(), "");
else
publicType.qualifier.layoutSlotLocation = value;
} else if (id == "binding")
error(loc, "not supported", "binding", "");
else
} else if (id == "binding") {
requireProfile(loc, ECoreProfile | ECompatibilityProfile, "binding");
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, GL_ARB_shading_language_420pack, "binding");
if ((unsigned int)value >= TQualifier::layoutBindingEnd)
error(loc, "binding is too large", id.c_str(), "");
else
publicType.qualifier.layoutBinding = value;
} else
error(loc, "there is no such layout identifier taking an assigned value", id.c_str(), "");
// TODO: semantics: error check: make sure locations are non-overlapping across the whole stage
@ -2139,6 +2150,37 @@ void TParseContext::mergeLayoutQualifiers(TSourceLoc loc, TQualifier& dst, const
if (src.hasLocation())
dst.layoutSlotLocation = src.layoutSlotLocation;
if (src.hasBinding())
dst.layoutBinding = src.layoutBinding;
}
// Do error layout error checking given a full variable/block declaration.
void TParseContext::layoutCheck(TSourceLoc loc, const TSymbol& symbol)
{
const TType& type = symbol.getType();
const TQualifier& qualifier = type.getQualifier();
if (qualifier.hasLocation()) {
// TODO: location = functionality, when is it allowed?
}
if (qualifier.hasBinding()) {
// Binding checking, from the spec:
//
// "If the binding point for any uniform or shader storage block instance is less than zero, or greater than or
// equal to the implementation-dependent maximum number of uniform buffer bindings, a compile-time
// error will occur. When the binding identifier is used with a uniform or shader storage block instanced as
// an array of size N, all elements of the array from binding through binding + N 1 must be within this
// range."
//
// TODO: binding error checking against limits, arrays
//
if (qualifier.storage != EvqUniform && qualifier.storage != EvqBuffer)
error(loc, "requires uniform or buffer storage qualifier", "binding", "");
if (type.getBasicType() != EbtSampler && type.getBasicType() != EbtBlock)
error(loc, "requires block, or sampler/image, or atomic-counter type", "binding", "");
// TODO: atomic counter functionality: include in test above
}
}
/////////////////////////////////////////////////////////////////////////////////
@ -2229,6 +2271,10 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier,
initNode = executeInitializer(loc, identifier, initializer, variable);
}
// look for errors in layout qualifier use
if (symbol)
layoutCheck(loc, *symbol);
// see if it's a linker-level object to track
if (symbol && newDeclaration && symbolTable.atGlobalLevel())
intermediate.addSymbolLinkageNode(linkage, *symbol);
@ -2648,7 +2694,7 @@ void TParseContext::addBlock(TSourceLoc loc, TTypeList& typeList, const TString*
arrayDimCheck(loc, arraySizes, 0);
// fix and check for qualifiers and types that don't belong within a block
// fix and check for member qualifiers and types that don't belong within a block
for (unsigned int member = 0; member < typeList.size(); ++member) {
TQualifier& memberQualifier = typeList[member].type->getQualifier();
TSourceLoc memberLoc = typeList[member].loc;
@ -2683,7 +2729,7 @@ void TParseContext::addBlock(TSourceLoc loc, TTypeList& typeList, const TString*
// Build and add the interface block as a new type named blockName
TType blockType(&typeList, *blockName, currentBlockDefaults.storage);
TType blockType(&typeList, *blockName, currentBlockDefaults);
if (arraySizes)
blockType.setArraySizes(arraySizes);
blockType.getQualifier().layoutPacking = defaultQualification.layoutPacking;
@ -2717,18 +2763,21 @@ void TParseContext::addBlock(TSourceLoc loc, TTypeList& typeList, const TString*
if (! instanceName)
instanceName = NewPoolTString("");
TVariable* variable = new TVariable(instanceName, blockType);
if (! symbolTable.insert(*variable)) {
TVariable& variable = *new TVariable(instanceName, blockType);
if (! symbolTable.insert(variable)) {
if (*instanceName == "")
error(loc, "nameless block contains a member that already has a name at global scope", blockName->c_str(), "");
else
error(loc, "block instance name redefinition", variable->getName().c_str(), "");
error(loc, "block instance name redefinition", variable.getName().c_str(), "");
return;
}
// Check for general layout qualifier errors
layoutCheck(loc, variable);
// Save it in the AST for linker use.
intermediate.addSymbolLinkageNode(linkage, *variable);
intermediate.addSymbolLinkageNode(linkage, variable);
}
// For an identifier that is already declared, add more qualification to it.
@ -2769,6 +2818,10 @@ void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier,
addQualifierToExisting(loc, qualifier, *identifiers[i]);
}
//
// Update qualifier defaults for all forms of declarations, which
// must error check for their form before calling here.
//
void TParseContext::updateQualifierDefaults(TQualifier qualifier)
{
switch (qualifier.storage) {
@ -2798,27 +2851,41 @@ void TParseContext::updateQualifierDefaults(TQualifier qualifier)
}
}
//
// Update defaults for qualifiers. This is called directly for the case
// of a declaration with just a qualifier.
//
void TParseContext::updateQualifierDefaults(TSourceLoc loc, TQualifier qualifier)
{
if (qualifier.isAuxiliary() ||
qualifier.isMemory() ||
qualifier.isInterpolation() ||
qualifier.precision != EpqNone)
error(loc, "cannot use auxiliary, memory, interpolation, or precision qualifier in a standalone qualifier", "", "");
error(loc, "cannot use auxiliary, memory, interpolation, or precision qualifier in a default qualifier declaration (declaration with no type)", "", "");
switch (qualifier.storage) {
case EvqUniform:
case EvqBuffer:
case EvqVaryingIn:
case EvqVaryingOut:
break;
default:
error(loc, "standalone qualifier requires 'uniform', 'in', or 'out' storage qualification", "", "");
error(loc, "default qualifier requires 'uniform', 'buffer', 'in', or 'out' storage qualification", "", "");
return;
}
if (qualifier.hasBinding())
error(loc, "cannot declare a default, include a type or full declaration", "binding", "");
if (qualifier.hasLocation())
error(loc, "cannot declare a default, use a full declaration", "location", "");
updateQualifierDefaults(qualifier);
}
//
// Update defaults for qualifiers when declared with a type, and optionally an id.
// (But, not the case of just a qualifier; this is called when a type is present.)
//
void TParseContext::updateTypedDefaults(TSourceLoc loc, TQualifier qualifier, const TString* id)
{
bool cantHaveId = false;
@ -2836,11 +2903,15 @@ void TParseContext::updateTypedDefaults(TSourceLoc loc, TQualifier qualifier, co
if (qualifier.layoutPacking != ElpNone)
error(loc, "cannot specify packing on a variable declaration", id->c_str(), "");
} else if (qualifier.storage == EvqVaryingIn) {
if (qualifier.hasLayout() && language != EShLangVertex)
error(loc, "can only use location layout qualifier on a vertex input or fragment output", id->c_str(), "");
if (qualifier.hasLocation()) {
if (profile == EEsProfile)
requireStage(loc, EShLangVertex, "input location layout qualifier");
}
} else if (qualifier.storage == EvqVaryingOut) {
if (qualifier.hasLayout() && language != EShLangFragment)
error(loc, "can only use location layout qualifier on a vertex input or fragment output", id->c_str(), "");
if (qualifier.hasLocation()) {
if (profile == EEsProfile)
requireStage(loc, EShLangFragment, "output location layout qualifier");
}
} else {
if (qualifier.layoutMatrix != ElmNone ||
qualifier.layoutPacking != ElpNone)

View File

@ -126,6 +126,7 @@ public:
void setLayoutQualifier(TSourceLoc, TPublicType&, TString&);
void setLayoutQualifier(TSourceLoc, TPublicType&, TString&, int);
void mergeLayoutQualifiers(TSourceLoc, TQualifier& dest, const TQualifier& src);
void layoutCheck(TSourceLoc, const TSymbol&);
const TFunction* findFunction(TSourceLoc, TFunction* pfnCall, bool *builtIn = 0);
TIntermNode* declareVariable(TSourceLoc, TString& identifier, TPublicType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0);