This is the (simplest) instancing shader I can come up with, which basically just transforms a bunch of 2D primitives:
#version 400
#extension GL_ARB_draw_instanced : enable
#extension GL_ARB_shading_language_420pack : enable
layout(std140, binding = 0) uniform VConstants {
vec4 vfuniforms[48];
};
in vec4 pos;
void main() {
gl_Position = vec4(0.0,0,0.0,1);
gl_Position.x = dot(pos, vfuniforms[int(float(gl_InstanceID) * 2.0)]);
gl_Position.y = dot(pos, vfuniforms[int(float(gl_InstanceID) * 2.0 + 1.0)]);
}
If I try to compile this to SPIR-V with the glslangValidator that comes with the Vulkan SDK, I get:
WARNING: 0:2: '#extension' : extension not supported: GL_ARB_draw_instanced
ERROR: 0:14: 'gl_InstanceID' : undeclared identifier
ERROR: 1 compilation errors. No code generated.
If I remove the #extension GL_ARB_draw_instanced
line, I still get the gl_InstanceID
error. Is it possible to write instancing GLSL and compile them to SPIR-V? If so, what I am doing incorrectly?
Vulkan does not directly consume shaders in a human-readable text format, but instead uses SPIR-V as an intermediate representation. This opens the option to use shader languages other than e.g. GLSL, as long as they can target the Vulkan SPIR-V environment.
GLSL. OpenGL Shading Language (GLSL) is the standard shader programming language for Khronos APIs such as Vulkan, OpenGL 4.
Double click the file to run it. Replace the path to glslc with the path to where you installed the Vulkan SDK. Make the script executable with chmod +x compile.sh and run it. These two commands tell the compiler to read the GLSL source file and output a SPIR-V bytecode file using the -o (output) flag.
The GLSL that is referred to herein is compatible with OpenGL ES 2.0; the HLSL is compatible with Direct3D 11.
The form of GLSL that the reference compiler uses to generate SPIR-V for Vulkan doesn't use normal OpenGL extensions. It follows the rules of GLSL 4.50, but it amends/overrides them by the dictates of the implicit pseudo-extension GL_KHR_vulkan_glsl. Note that you don't use #extension to initiate it; it is assumed to be active because you're using the Vulkan GLSL-to-SPIR-V compiler.
In particular, this extension removes gl_InstanceID
(and gl_VertexID
). Instead, it creates its own variable, gl_InstanceIndex
. The reason for this is because OpenGL was... stupid.
See, gl_InstanceID
is the instance starting from the first instance in the instanced drawing command. However, when base-instanced rendering was added (the ability to render an arbitrary range of instances), gl_InstanceID
was not updated to match. So if you start from a base instance of 2 with 5 instances, the first gl_InstanceID
will still be zero (followed by 1, 2, 3, and 4). So the only things the base instance affects are instanced arrays.
Naturally, Vulkan wanted no part of OpenGL's stupidity in this regard, so it uses what most people would expect the instance value to be: the actual instance index the user asked to render. But this required a new variable, so that users wouldn't do what you're attempting: to accidentally use the same variable across both OpenGL and Vulkan without realizing that they have different semantics.
You'll either need two shaders or to check if VULKAN
is defined, which is will be for those using the GL_KHR_vulkan_glsl extension. If it is, you use gl_InstanceIndex
; if not, you use gl_InstanceID
. Also, your #extension declarations should be scoped as well, since the Vulkan GLSL-to-SPIR-V compiler will assume GLSL 4.50, and it won't necessarily offer up extensions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With