Fix #1019.
glspv.frag
ERROR: 0:4: '#error' : GL_SPIRV is set ( correct , not an error )
ERROR: 0:6: '#error' : GL_SPIR is 100
-ERROR: 0:14: 'f' : non-opaque uniform variables need a layout(location=L)
ERROR: 0:19: 'input_attachment_index' : only allowed when using GLSL for Vulkan
ERROR: 0:19: '' : syntax error, unexpected IDENTIFIER, expecting LEFT_BRACE or COMMA or SEMICOLON
-ERROR: 5 compilation errors. No code generated.
+ERROR: 4 compilation errors. No code generated.
SPIR-V is not generated for failed compile or link
--- /dev/null
+spv.looseUniformNoLoc.vert
+ERROR: spv.looseUniformNoLoc.vert:9: 'uv' : non-opaque uniform variables need a layout(location=L)
+ERROR: 1 compilation errors. No code generated.
+
+
+ERROR: Linking vertex stage: Missing entry point: Each stage requires one entry point
+
+SPIR-V is not generated for failed compile or link
spv.noBuiltInLoc.vert
// Module Version 10000
// Generated by (magic number): 80001
-// Id's are bound by 23
+// Id's are bound by 33
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
- EntryPoint Vertex 4 "main" 9 11 18
+ EntryPoint Vertex 4 "main" 9 11 18 31 32
Source GLSL 450
Name 4 "main"
Name 9 "bar"
MemberName 16(gl_PerVertex) 2 "gl_ClipDistance"
MemberName 16(gl_PerVertex) 3 "gl_CullDistance"
Name 18 ""
+ Name 24 "uv1"
+ Name 26 "uv2"
+ Name 29 "uv3"
+ Name 31 "gl_VertexID"
+ Name 32 "gl_InstanceID"
Decorate 9(bar) Location 0
Decorate 11(foo) Location 0
MemberDecorate 16(gl_PerVertex) 0 BuiltIn Position
MemberDecorate 16(gl_PerVertex) 2 BuiltIn ClipDistance
MemberDecorate 16(gl_PerVertex) 3 BuiltIn CullDistance
Decorate 16(gl_PerVertex) Block
+ Decorate 24(uv1) Location 0
+ Decorate 24(uv1) DescriptorSet 0
+ Decorate 26(uv2) Location 1
+ Decorate 26(uv2) DescriptorSet 0
+ Decorate 29(uv3) Location 2
+ Decorate 29(uv3) DescriptorSet 0
+ Decorate 31(gl_VertexID) BuiltIn VertexId
+ Decorate 32(gl_InstanceID) BuiltIn InstanceId
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
18: 17(ptr) Variable Output
19: TypeInt 32 1
20: 19(int) Constant 0
+ 23: TypePointer UniformConstant 7(fvec4)
+ 24(uv1): 23(ptr) Variable UniformConstant
+ 25: TypePointer UniformConstant 6(float)
+ 26(uv2): 25(ptr) Variable UniformConstant
+ 27: TypeVector 6(float) 3
+ 28: TypePointer UniformConstant 27(fvec3)
+ 29(uv3): 28(ptr) Variable UniformConstant
+ 30: TypePointer Input 19(int)
+ 31(gl_VertexID): 30(ptr) Variable Input
+32(gl_InstanceID): 30(ptr) Variable Input
4(main): 2 Function None 3
5: Label
12: 7(fvec4) Load 11(foo)
echo Testing SPV no location
$EXE -V -C spv.noLocation.vert > $TARGETDIR/spv.noLocation.vert.out
diff -b $BASEDIR/spv.noLocation.vert.out $TARGETDIR/spv.noLocation.vert.out || HASERROR=1
-$EXE -H --aml spv.noBuiltInLoc.vert > $TARGETDIR/spv.noBuiltInLoc.vert.out
+$EXE -G -H --aml spv.noBuiltInLoc.vert > $TARGETDIR/spv.noBuiltInLoc.vert.out
diff -b $BASEDIR/spv.noBuiltInLoc.vert.out $TARGETDIR/spv.noBuiltInLoc.vert.out || HASERROR=1
+$EXE -G spv.looseUniformNoLoc.vert > $TARGETDIR/spv.looseUniformNoLoc.vert.out
+diff -b $BASEDIR/spv.looseUniformNoLoc.vert.out $TARGETDIR/spv.looseUniformNoLoc.vert.out || HASERROR=1
#
# Testing debug information
--- /dev/null
+#version 450 core\r
+\r
+layout(location = 0)\r
+in vec4 foo;\r
+\r
+layout(location = 0)\r
+out vec4 bar;\r
+\r
+uniform vec4 uv;\r
+\r
+void main()\r
+{\r
+ bar = foo;\r
+ gl_Position = foo;\r
+}
\ No newline at end of file
layout(location = 0)\r
out vec4 bar;\r
\r
+uniform vec4 uv1;\r
+uniform float uv2;\r
+uniform vec3 uv3;\r
+\r
void main()\r
{\r
bar = foo;\r
// Vulkan doesn't allow transparent uniforms outside of blocks
if (spvVersion.vulkan > 0)
vulkanRemoved(loc, "non-opaque uniforms outside a block");
- // OpenGL wants locations on these
- if (spvVersion.openGl > 0 && !type.getQualifier().hasLocation())
+ // OpenGL wants locations on these (unless they are getting automapped)
+ if (spvVersion.openGl > 0 && !type.getQualifier().hasLocation() && !intermediate.getAutoMapLocations())
error(loc, "non-opaque uniform variables need a layout(location=L)", identifier.c_str(), "");
}
}
ent.newBinding = -1;
ent.newSet = -1;
ent.newIndex = -1;
- const bool isValid = resolver.validateBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live);
+ const bool isValid = resolver.validateBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(),
+ ent.live);
if (isValid) {
- ent.newBinding = resolver.resolveBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live);
+ ent.newBinding = resolver.resolveBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(),
+ ent.live);
ent.newSet = resolver.resolveSet(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live);
+ ent.newLocation = resolver.resolveUniformLocation(stage, ent.symbol->getName().c_str(),
+ ent.symbol->getType(), ent.live);
if (ent.newBinding != -1) {
if (ent.newBinding >= int(TQualifier::layoutBindingEnd)) {
std::vector<std::string> baseResourceSetBinding;
bool doAutoBindingMapping;
bool doAutoLocationMapping;
+ int nextUniformLocation;
typedef std::vector<int> TSlotSet;
typedef std::unordered_map<int, TSlotSet> TSlotSetMap;
TSlotSetMap slots;
return 0;
}
+ int resolveUniformLocation(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool is_live) override
+ {
+ // kick out of not doing this
+ if (!doAutoLocationMapping)
+ return -1;
+
+ // no locations added if already present, a built-in variable, a block, or an opaque
+ if (type.getQualifier().hasLocation() || type.isBuiltIn() ||
+ type.getBasicType() == EbtBlock || type.containsOpaque())
+ return -1;
+
+ // no locations on blocks of built-in variables
+ if (type.isStruct()) {
+ if (type.getStruct()->size() < 1)
+ return -1;
+ if ((*type.getStruct())[0].type->isBuiltIn())
+ return -1;
+ }
+ return nextUniformLocation++;
+ }
bool validateInOut(EShLanguage /*stage*/, const char* /*name*/, const TType& /*type*/, bool /*is_live*/) override
{
return true;
resolverBase->baseResourceSetBinding = intermediate.getResourceSetBinding();
resolverBase->doAutoBindingMapping = intermediate.getAutoMapBindings();
resolverBase->doAutoLocationMapping = intermediate.getAutoMapLocations();
+ resolverBase->nextUniformLocation = 0;
resolver = resolverBase;
}
// Allows to customize the binding layout after linking.
// All used uniform variables will invoke at least validateBinding.
-// If validateBinding returned true then the other resolveBinding
-// and resolveSet are invoked to resolve the binding and descriptor
-// set index respectively.
+// If validateBinding returned true then the other resolveBinding,
+// resolveSet, and resolveLocation are invoked to resolve the binding
+// and descriptor set index respectively.
+//
// Invocations happen in a particular order:
// 1) all shader inputs
// 2) all shader outputs
// Should return a value >= 0 if the current set should be overridden.
// Return -1 if the current set (including no set) should be kept.
virtual int resolveSet(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
+ // Should return a value >= 0 if the current location should be overridden.
+ // Return -1 if the current location (including no location) should be kept.
+ virtual int resolveUniformLocation(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
// Should return true if the resulting/current setup would be okay.
// Basic idea is to do aliasing checks and reject invalid semantic names.
virtual bool validateInOut(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;