diff --git a/Test/baseResults/440.vert.out b/Test/baseResults/440.vert.out index 3c0a1200..2e1f5fe6 100644 --- a/Test/baseResults/440.vert.out +++ b/Test/baseResults/440.vert.out @@ -23,7 +23,6 @@ ERROR: 0:66: 'component' : doubles cannot start on an odd-numbered component ERROR: 0:67: 'component' : type overflows the available 4 components ERROR: 0:71: 'location' : overlapping use of location 55 ERROR: 0:75: 'location' : overlapping use of location 57 -ERROR: 0:77: 'location' : overlapping use of location 59 ERROR: 0:78: 'location' : overlapping use of location 59 ERROR: 0:95: 'xfb layout qualifier' : can only be used on an output ERROR: 0:101: 'xfb_offset' : cannot declare a default, use a full declaration @@ -55,7 +54,7 @@ ERROR: 0:187: 'assign' : l-value required "gl_BaseVertexARB" (can't modify shad ERROR: 0:188: 'assign' : l-value required "gl_BaseInstanceARB" (can't modify shader input) ERROR: 0:189: 'assign' : l-value required "gl_DrawIDARB" (can't modify shader input) ERROR: 0:190: 'glBaseInstanceARB' : undeclared identifier -ERROR: 55 compilation errors. No code generated. +ERROR: 54 compilation errors. No code generated. Shader version: 440 diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h index be96c1c1..a3591958 100644 --- a/glslang/Include/revision.h +++ b/glslang/Include/revision.h @@ -2,5 +2,5 @@ // For the version, it uses the latest git tag followed by the number of commits. // For the date, it uses the current date (when then script is run). -#define GLSLANG_REVISION "SPIRV99.1393" +#define GLSLANG_REVISION "SPIRV99.1394" #define GLSLANG_DATE "08-Aug-2016" diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp index 0bc1d918..dbd2f927 100644 --- a/glslang/MachineIndependent/linkValidate.cpp +++ b/glslang/MachineIndependent/linkValidate.cpp @@ -664,37 +664,93 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ size = computeTypeLocationSize(type); } - // locations... - TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation + size - 1); + // Locations, and components within locations. + // + // Almost always, dealing with components means a single location is involved. + // The exception is a dvec3. From the spec: + // + // "A dvec3 will consume all four components of the first location and components 0 and 1 of + // the second location. This leaves components 2 and 3 available for other component-qualified + // declarations." + // + // That means, without ever mentioning a component, a component range + // for a different location gets specified, if it's not a vertex shader input. (!) + // (A vertex shader input will show using only one location, even for a dvec3/4.) + // + // So, for the case of dvec3, we need two independent ioRanges. - // components in this location slot... - TRange componentRange(0, 3); - if (qualifier.hasComponent() || type.getVectorSize() > 0) { - int consumedComponents = type.getVectorSize() * (type.getBasicType() == EbtDouble ? 2 : 1); - if (qualifier.hasComponent()) - componentRange.start = qualifier.layoutComponent; - componentRange.last = componentRange.start + consumedComponents - 1; + int collision = -1; // no collision + if (size == 2 && type.getBasicType() == EbtDouble && type.getVectorSize() == 3 && + (qualifier.isPipeInput() || qualifier.isPipeOutput())) { + // Dealing with dvec3 in/out split across two locations. + // Need two io-ranges. + // The case where the dvec3 doesn't start at component 0 was previously caught as overflow. + + // First range: + TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation); + TRange componentRange(0, 3); + TIoRange range(locationRange, componentRange, type.getBasicType(), 0); + + // check for collisions + collision = checkLocationRange(set, range, type, typeCollision); + if (collision < 0) { + usedIo[set].push_back(range); + + // Second range: + TRange locationRange2(qualifier.layoutLocation + 1, qualifier.layoutLocation + 1); + TRange componentRange2(0, 1); + TIoRange range2(locationRange2, componentRange2, type.getBasicType(), 0); + + // check for collisions + collision = checkLocationRange(set, range2, type, typeCollision); + if (collision < 0) + usedIo[set].push_back(range2); + } + } else { + // Not a dvec3 in/out split across two locations, generic path. + // Need a single IO-range block. + + TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation + size - 1); + TRange componentRange(0, 3); + if (qualifier.hasComponent() || type.getVectorSize() > 0) { + int consumedComponents = type.getVectorSize() * (type.getBasicType() == EbtDouble ? 2 : 1); + if (qualifier.hasComponent()) + componentRange.start = qualifier.layoutComponent; + componentRange.last = componentRange.start + consumedComponents - 1; + } + + // combine location and component ranges + 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())) + collision = checkLocationRange(set, range, type, typeCollision); + + if (collision < 0) + usedIo[set].push_back(range); } - // both... - TIoRange range(locationRange, componentRange, type.getBasicType(), qualifier.hasIndex() ? qualifier.layoutIndex : 0); + return collision; +} - // check for collisions, except for vertex inputs on desktop - if (! (profile != EEsProfile && language == EShLangVertex && qualifier.isPipeInput())) { - for (size_t r = 0; r < usedIo[set].size(); ++r) { - if (range.overlap(usedIo[set][r])) { - // there is a collision; pick one - return std::max(locationRange.start, usedIo[set][r].location.start); - } else if (locationRange.overlap(usedIo[set][r].location) && type.getBasicType() != usedIo[set][r].basicType) { - // aliased-type mismatch - typeCollision = true; - return std::max(locationRange.start, usedIo[set][r].location.start); - } +// Compare a new (the passed in) 'range' against the existing set, and see +// if there are any collisions. +// +// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. +// +int TIntermediate::checkLocationRange(int set, const TIoRange& range, const TType& type, bool& typeCollision) +{ + for (size_t r = 0; r < usedIo[set].size(); ++r) { + if (range.overlap(usedIo[set][r])) { + // there is a collision; pick one + return std::max(range.location.start, usedIo[set][r].location.start); + } else if (range.location.overlap(usedIo[set][r].location) && type.getBasicType() != usedIo[set][r].basicType) { + // aliased-type mismatch + typeCollision = true; + return std::max(range.location.start, usedIo[set][r].location.start); } } - usedIo[set].push_back(range); - return -1; // no collision } diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index 7bd457d1..0b07a29a 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -331,6 +331,7 @@ public: bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); } int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision); + int checkLocationRange(int set, const TIoRange& range, const TType&, bool& typeCollision); int addUsedOffsets(int binding, int offset, int numOffsets); bool addUsedConstantId(int id); int computeTypeLocationSize(const TType&) const;