Vulkan 中的实例化 GLSL 着色器?

Instanced GLSL shaders in Vulkan?

这是我能想到的(最简单的)实例化着色器,它基本上只是转换一堆 2D 图元:

#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)]);

}

如果我尝试使用 Vulkan SDK 附带的 glslangValidator 将其编译为 SPIR-V,我得到:

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.

如果删除 #extension GL_ARB_draw_instanced 行,我仍然会收到 gl_InstanceID 错误。是否可以编写实例化 GLSL 并将它们编译为 SPIR-V?如果是这样,我做错了什么?

GL_ARB_draw_instanced 扩展不是必需的,核心 GLSL 1.40 和 vulkan 支持它。 glslang 似乎不使用扩展名:https://github.com/KhronosGroup/glslang/blob/master/glslang/MachineIndependent/Initialize.cpp#L1707

而不是gl_InstanceID,我认为必须使用gl_InstanceIndex。不同之处在于 gl_InstanceID 从 0 开始计数,而 gl_InstanceIndex 从基础实例开始计数。参见

https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/xhtml/vkspec.html#interfaces-builtin-variables

有关内置函数的更多信息。

参考编译器用于为 Vulkan 生成 SPIR-V 的 GLSL 形式不使用普通的 OpenGL 扩展。它遵循 GLSL 4.50 的规则,但它 amends/overrides 由隐式伪扩展 GL_KHR_vulkan_glsl 决定。请注意,您不使用#extension 来启动它; 假定 处于活动状态,因为您使用的是 Vulkan GLSL-to-SPIR-V 编译器。

特别是,此扩展 删除了 gl_InstanceID(和 gl_VertexID)。相反,它会创建自己的变量 gl_InstanceIndex。这样做的原因是因为 OpenGL 是...愚蠢的。

看,gl_InstanceID是从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中第一个实例开始的实例。

当然,Vulkan 不想在这方面出现 OpenGL 的愚蠢行为,因此它使用了大多数人期望的实例值:用户要求渲染的实际实例索引。但这需要一个新变量,这样用户就不会做您正在尝试的事情:意外地在 OpenGL 和 Vulkan 中使用相同的变量,而没有意识到它们具有不同的语义。

您将需要两个着色器或检查是否定义了 VULKAN,这适用于那些使用 GL_KHR_vulkan_glsl 扩展名的人。如果是,则使用 gl_InstanceIndex;如果不是,则使用 gl_InstanceID。此外,您的#extension 声明也应该限定范围,因为 Vulkan GLSL-to-SPIR-V 编译器将采用 GLSL 4.50,并且它不一定会提供扩展。