Implement 'index' layout qualifier for fragment outputs. Based partly on a submission.
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@27759 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
parent
d1888f83f6
commit
aa657c117e
18 changed files with 135 additions and 58 deletions
|
|
@ -483,6 +483,8 @@ public:
|
|||
layoutLocation = layoutLocationEnd;
|
||||
layoutComponent = layoutComponentEnd;
|
||||
layoutBinding = layoutBindingEnd;
|
||||
layoutIndex = layoutIndexEnd;
|
||||
|
||||
layoutStream = layoutStreamEnd;
|
||||
|
||||
layoutXfbBuffer = layoutXfbBufferEnd;
|
||||
|
|
@ -494,7 +496,7 @@ public:
|
|||
bool hasLayout() const
|
||||
{
|
||||
return hasUniformLayout() ||
|
||||
hasLocation() ||
|
||||
hasAnyLocation() ||
|
||||
hasBinding() ||
|
||||
hasStream() ||
|
||||
hasXfb() ||
|
||||
|
|
@ -514,6 +516,9 @@ public:
|
|||
unsigned int layoutBinding : 8;
|
||||
static const unsigned int layoutBindingEnd = 0xFF;
|
||||
|
||||
unsigned int layoutIndex : 8;
|
||||
static const unsigned int layoutIndexEnd = 0xFF;
|
||||
|
||||
unsigned int layoutStream : 8;
|
||||
static const unsigned int layoutStreamEnd = 0xFF;
|
||||
|
||||
|
|
@ -552,15 +557,24 @@ public:
|
|||
{
|
||||
return layoutAlign != -1;
|
||||
}
|
||||
bool hasAnyLocation() const
|
||||
{
|
||||
return hasLocation() ||
|
||||
hasComponent() ||
|
||||
hasIndex();
|
||||
}
|
||||
bool hasLocation() const
|
||||
{
|
||||
return layoutLocation != layoutLocationEnd ||
|
||||
layoutComponent != layoutComponentEnd;
|
||||
return layoutLocation != layoutLocationEnd;
|
||||
}
|
||||
bool hasComponent() const
|
||||
{
|
||||
return layoutComponent != layoutComponentEnd;
|
||||
}
|
||||
bool hasIndex() const
|
||||
{
|
||||
return layoutIndex != layoutIndexEnd;
|
||||
}
|
||||
bool hasBinding() const
|
||||
{
|
||||
return layoutBinding != layoutBindingEnd;
|
||||
|
|
@ -1167,10 +1181,12 @@ public:
|
|||
noXfbBuffer.layoutXfbBuffer = TQualifier::layoutXfbBufferEnd;
|
||||
if (noXfbBuffer.hasLayout()) {
|
||||
p += snprintf(p, end - p, "layout(");
|
||||
if (qualifier.hasLocation()) {
|
||||
if (qualifier.hasAnyLocation()) {
|
||||
p += snprintf(p, end - p, "location=%d ", qualifier.layoutLocation);
|
||||
if (qualifier.layoutComponent != qualifier.layoutComponentEnd)
|
||||
if (qualifier.hasComponent())
|
||||
p += snprintf(p, end - p, "component=%d ", qualifier.layoutComponent);
|
||||
if (qualifier.hasIndex())
|
||||
p += snprintf(p, end - p, "index=%d ", qualifier.layoutIndex);
|
||||
}
|
||||
if (qualifier.hasBinding())
|
||||
p += snprintf(p, end - p, "binding=%d ", qualifier.layoutBinding);
|
||||
|
|
|
|||
|
|
@ -3266,6 +3266,13 @@ void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType,
|
|||
break;
|
||||
|
||||
case EShLangFragment:
|
||||
if (id == "index") {
|
||||
requireProfile(loc, ECompatibilityProfile | ECoreProfile, "index layout qualifier on fragment output");
|
||||
const char* exts[2] = { GL_ARB_separate_shader_objects, GL_ARB_explicit_attrib_location };
|
||||
profileRequires(loc, ECompatibilityProfile | ECoreProfile, 330, 2, exts, "index layout qualifier on fragment output");
|
||||
publicType.qualifier.layoutIndex = value;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case EShLangCompute:
|
||||
|
|
@ -3325,11 +3332,13 @@ void TParseContext::mergeObjectLayoutQualifiers(TSourceLoc loc, TQualifier& dst,
|
|||
dst.layoutAlign = src.layoutAlign;
|
||||
|
||||
if (! inheritOnly) {
|
||||
if (src.layoutLocation != TQualifier::layoutLocationEnd)
|
||||
if (src.hasLocation())
|
||||
dst.layoutLocation = src.layoutLocation;
|
||||
if (src.layoutComponent != TQualifier::layoutComponentEnd)
|
||||
if (src.hasComponent())
|
||||
dst.layoutComponent = src.layoutComponent;
|
||||
|
||||
if (src.hasIndex())
|
||||
dst.layoutIndex = src.layoutIndex;
|
||||
|
||||
if (src.hasOffset())
|
||||
dst.layoutOffset = src.layoutOffset;
|
||||
|
||||
|
|
@ -3354,7 +3363,7 @@ void TParseContext::layoutObjectCheck(TSourceLoc loc, const TSymbol& symbol)
|
|||
|
||||
// now, any remaining error checking based on the object itself
|
||||
|
||||
if (qualifier.hasLocation()) {
|
||||
if (qualifier.hasAnyLocation()) {
|
||||
switch (qualifier.storage) {
|
||||
case EvqUniform:
|
||||
case EvqBuffer:
|
||||
|
|
@ -3405,8 +3414,14 @@ void TParseContext::layoutTypeCheck(TSourceLoc loc, const TType& type)
|
|||
|
||||
// now, error checking combining type and qualifier
|
||||
|
||||
if (qualifier.hasLocation()) {
|
||||
if (qualifier.layoutComponent != TQualifier::layoutComponentEnd) {
|
||||
if (qualifier.hasAnyLocation()) {
|
||||
if (qualifier.hasLocation()) {
|
||||
if (qualifier.storage == EvqVaryingOut && language == EShLangFragment) {
|
||||
if (qualifier.layoutLocation >= (unsigned int)resources.maxDrawBuffers)
|
||||
error(loc, "too large for fragment output", "location", "");
|
||||
}
|
||||
}
|
||||
if (qualifier.hasComponent()) {
|
||||
// "It is a compile-time error if this sequence of components gets larger than 3."
|
||||
if (qualifier.layoutComponent + type.getVectorSize() > 4)
|
||||
error(loc, "type overflows the available 4 components", "component", "");
|
||||
|
|
@ -3416,11 +3431,6 @@ void TParseContext::layoutTypeCheck(TSourceLoc loc, const TType& type)
|
|||
error(loc, "cannot apply to a matrix, structure, or block", "component", "");
|
||||
}
|
||||
|
||||
if (qualifier.storage == EvqVaryingOut && language == EShLangFragment) {
|
||||
if (qualifier.layoutLocation >= (unsigned int)resources.maxDrawBuffers)
|
||||
error(loc, "too large for fragment output", "location", "");
|
||||
}
|
||||
|
||||
switch (qualifier.storage) {
|
||||
case EvqVaryingIn:
|
||||
case EvqVaryingOut:
|
||||
|
|
@ -3514,10 +3524,10 @@ void TParseContext::layoutQualifierCheck(TSourceLoc loc, const TQualifier& quali
|
|||
error(loc, "cannot apply layout qualifiers to a shared variable", "shared", "");
|
||||
|
||||
// "It is a compile-time error to use *component* without also specifying the location qualifier (order does not matter)."
|
||||
if (qualifier.layoutComponent != TQualifier::layoutComponentEnd && qualifier.layoutLocation == TQualifier::layoutLocationEnd)
|
||||
if (qualifier.hasComponent() && ! qualifier.hasLocation())
|
||||
error(loc, "must specify 'location' to use 'component'", "component", "");
|
||||
|
||||
if (qualifier.hasLocation()) {
|
||||
if (qualifier.hasAnyLocation()) {
|
||||
|
||||
// "As with input layout qualifiers, all shaders except compute shaders
|
||||
// allow *location* layout qualifiers on output variable declarations,
|
||||
|
|
@ -3570,6 +3580,12 @@ void TParseContext::layoutQualifierCheck(TSourceLoc loc, const TQualifier& quali
|
|||
default:
|
||||
break;
|
||||
}
|
||||
if (qualifier.hasIndex()) {
|
||||
if (qualifier.storage != EvqVaryingOut)
|
||||
error(loc, "can only be used on an output", "index", "");
|
||||
if (! qualifier.hasLocation())
|
||||
error(loc, "can only be used with an explicit location", "index", "");
|
||||
}
|
||||
}
|
||||
|
||||
if (qualifier.hasBinding()) {
|
||||
|
|
@ -4240,10 +4256,14 @@ void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TStr
|
|||
case EvqVaryingIn:
|
||||
requireProfile(loc, ~EEsProfile, "input block");
|
||||
profileRequires(loc, ~EEsProfile, 150, GL_ARB_separate_shader_objects, "input block");
|
||||
if (language == EShLangVertex)
|
||||
error(loc, "cannot declare an input block in a vertex shader", "in", "");
|
||||
break;
|
||||
case EvqVaryingOut:
|
||||
requireProfile(loc, ~EEsProfile, "output block");
|
||||
profileRequires(loc, ~EEsProfile, 150, GL_ARB_separate_shader_objects, "output block");
|
||||
if (language == EShLangFragment)
|
||||
error(loc, "cannot declare an output block in a fragment shader", "out", "");
|
||||
break;
|
||||
default:
|
||||
error(loc, "only uniform, buffer, in, or out blocks are supported", blockName->c_str(), "");
|
||||
|
|
@ -4455,13 +4475,16 @@ void TParseContext::fixBlockLocations(TSourceLoc loc, TQualifier& qualifier, TTy
|
|||
if (memberWithLocation) {
|
||||
// remove any block-level location and make it per *every* member
|
||||
int nextLocation; // by the rule above, initial value is not relevant
|
||||
if (qualifier.hasLocation()) {
|
||||
if (qualifier.hasAnyLocation()) {
|
||||
nextLocation = qualifier.layoutLocation;
|
||||
qualifier.layoutLocation = TQualifier::layoutLocationEnd;
|
||||
if (qualifier.layoutComponent != TQualifier::layoutComponentEnd) {
|
||||
if (qualifier.hasComponent()) {
|
||||
// "It is a compile-time error to apply the *component* qualifier to a ... block"
|
||||
error(loc, "cannot apply to a block", "component", "");
|
||||
}
|
||||
if (qualifier.hasIndex()) {
|
||||
error(loc, "cannot apply to a block", "index", "");
|
||||
}
|
||||
}
|
||||
for (unsigned int member = 0; member < typeList.size(); ++member) {
|
||||
TQualifier& memberQualifier = typeList[member].type->getQualifier();
|
||||
|
|
@ -4781,8 +4804,8 @@ void TParseContext::updateStandaloneQualifierDefaults(TSourceLoc loc, const TPub
|
|||
|
||||
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", "");
|
||||
if (qualifier.hasAnyLocation())
|
||||
error(loc, "cannot declare a default, use a full declaration", "location/component/index", "");
|
||||
if (qualifier.hasXfbOffset())
|
||||
error(loc, "cannot declare a default, use a full declaration", "xfb_offset", "");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ void TParseContext::initializeExtensionBehavior()
|
|||
extensionBehavior[GL_ARB_enhanced_layouts] = EBhDisable;
|
||||
extensionBehavior[GL_ARB_texture_cube_map_array] = EBhDisable;
|
||||
extensionBehavior[GL_ARB_shader_texture_lod] = EBhDisable;
|
||||
extensionBehavior[GL_ARB_explicit_attrib_location] = EBhDisablePartial; // "index" for fragment outputs is missing
|
||||
extensionBehavior[GL_ARB_explicit_attrib_location] = EBhDisable;
|
||||
extensionBehavior[GL_ARB_shader_image_load_store] = EBhDisable;
|
||||
extensionBehavior[GL_ARB_shader_atomic_counters] = EBhDisable;
|
||||
extensionBehavior[GL_ARB_derivative_control] = EBhDisable;
|
||||
|
|
|
|||
|
|
@ -313,13 +313,15 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy
|
|||
}
|
||||
|
||||
// Layouts...
|
||||
// TODO: 4.4 enhanced layouts: Generalize to include offset/align: currrent spec
|
||||
// TODO: 4.4 enhanced layouts: Generalize to include offset/align: current spec
|
||||
// requires separate user-supplied offset from actual computed offset, but
|
||||
// current implementation only has one offset.
|
||||
if (symbol.getQualifier().layoutMatrix != unitSymbol.getQualifier().layoutMatrix ||
|
||||
symbol.getQualifier().layoutPacking != unitSymbol.getQualifier().layoutPacking ||
|
||||
symbol.getQualifier().layoutLocation != unitSymbol.getQualifier().layoutLocation ||
|
||||
symbol.getQualifier().layoutBinding != unitSymbol.getQualifier().layoutBinding) {
|
||||
if (symbol.getQualifier().layoutMatrix != unitSymbol.getQualifier().layoutMatrix ||
|
||||
symbol.getQualifier().layoutPacking != unitSymbol.getQualifier().layoutPacking ||
|
||||
symbol.getQualifier().layoutLocation != unitSymbol.getQualifier().layoutLocation ||
|
||||
symbol.getQualifier().layoutComponent != unitSymbol.getQualifier().layoutComponent ||
|
||||
symbol.getQualifier().layoutIndex != unitSymbol.getQualifier().layoutIndex ||
|
||||
symbol.getQualifier().layoutBinding != unitSymbol.getQualifier().layoutBinding) {
|
||||
error(infoSink, "Layout qualification must match:");
|
||||
writeTypeComparison = true;
|
||||
}
|
||||
|
|
@ -547,7 +549,7 @@ void TIntermediate::inOutLocationCheck(TInfoSink& infoSink)
|
|||
if (language == EShLangFragment) {
|
||||
if (qualifier.storage == EvqVaryingOut) {
|
||||
++numFragOut;
|
||||
if (qualifier.hasLocation())
|
||||
if (qualifier.hasAnyLocation())
|
||||
fragOutHasLocation = true;
|
||||
else
|
||||
fragOutWithNoLocation = true;
|
||||
|
|
@ -634,11 +636,11 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ
|
|||
|
||||
TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation + size - 1);
|
||||
TRange componentRange(0, 3);
|
||||
if (qualifier.layoutComponent != TQualifier::layoutComponentEnd) {
|
||||
if (qualifier.hasComponent()) {
|
||||
componentRange.start = qualifier.layoutComponent;
|
||||
componentRange.last = componentRange.start + type.getVectorSize() - 1;
|
||||
}
|
||||
TIoRange range(locationRange, componentRange, type.getBasicType());
|
||||
TIoRange range(locationRange, componentRange, type.getBasicType(), qualifier.hasIndex() ? qualifier.layoutIndex : 0);
|
||||
|
||||
// check for collisions, except for vertex inputs on desktop
|
||||
if (! (profile != EEsProfile && language == EShLangVertex && qualifier.isPipeInput())) {
|
||||
|
|
|
|||
|
|
@ -77,18 +77,20 @@ struct TRange {
|
|||
int last;
|
||||
};
|
||||
|
||||
// A *location* range is a 2-D rectangle; the set of (location, component) pairs all lying
|
||||
// both within the location range and the component range. Locations don't alias unless
|
||||
// both dimensions of their range overlap.
|
||||
// An IO range is a 3-D rectangle; the set of (location, component, index) triples all lying
|
||||
// within the same location range, component range, and index value. Locations don't alias unless
|
||||
// all other dimensions of their range overlap.
|
||||
struct TIoRange {
|
||||
TIoRange(TRange location, TRange component, TBasicType basicType) : location(location), component(component), basicType(basicType) { }
|
||||
TIoRange(TRange location, TRange component, TBasicType basicType, int index)
|
||||
: location(location), component(component), basicType(basicType), index(index) { }
|
||||
bool overlap(const TIoRange& rhs) const
|
||||
{
|
||||
return location.overlap(rhs.location) && component.overlap(rhs.component);
|
||||
return location.overlap(rhs.location) && component.overlap(rhs.component) && index == rhs.index;
|
||||
}
|
||||
TRange location;
|
||||
TRange component;
|
||||
TBasicType basicType;
|
||||
int index;
|
||||
};
|
||||
|
||||
// Things that need to be tracked per xfb buffer.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue