Vulkan中的实例化GLSL着色器?

时间:2016-02-25 21:16:04

标签: glsl vulkan spir-v

这是我能想出的(最简单的)实例化着色器,它基本上只是转换了一堆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?如果是这样,我做错了什么?

2 个答案:

答案 0 :(得分:13)

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

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

请参阅gl_InstanceID是从instanced drawing command中的第一个实例开始的实例。但是,当添加了基础实例化渲染(呈现任意范围的实例的能力)时,gl_InstanceID未更新为匹配。因此,如果您从具有5个实例的2的基本实例开始,则第一个gl_InstanceID仍为零(后跟1,2,3和4)。因此,基本实例唯一影响的是instanced arrays

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

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

答案 1 :(得分:2)

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

我认为必须使用gl_InstanceIndex而不是gl_InstanceID。区别在于gl_InstanceID从0开始计数,其中gl_InstanceIndex从基本实例计数。见

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

了解有关内置组件的更多信息。