我一直在使用 Vulkano 来制作一些简单的 3D 图形。通常,我喜欢在文本中编写我的 GLSL 着色器并重新启动我的程序,甚至在程序运行时更改着色器。Vulkano 中给出的示例似乎使用宏将 GLSL 转换为某种形式的基于 SPIR-V 的着色器,并附加了 Rust 函数,但 GLSL 实际上被编译成二进制文件(即使使用文件路径)。
我已经设法让 crate shaderc 即时构建我的 SPIR-V:
let mut f = File::open("src/grafx/vert.glsl")
.expect("Can't find file src/bin/runtime-shader/vert.glsl
This example needs to be run from the root of the example crate.");
let mut source = String::new();
f.read_to_string(&mut source);
//let source = "#version 310 es\n void EP() {}";
let mut compiler = shaderc::Compiler::new().unwrap();
let mut options = shaderc::CompileOptions::new().unwrap();
options.add_macro_definition("EP", Some("main"));
let binary_result = compiler.compile_into_spirv(
&source, shaderc::ShaderKind::Vertex,
"shader.glsl", "main", Some(&options)).unwrap();
assert_eq!(Some(&0x07230203), binary_result.as_binary().first());
let text_result = compiler.compile_into_spirv_assembly(
&source, shaderc::ShaderKind::Vertex,
"shader.glsl", "main", Some(&options)).unwrap();
assert!(text_result.as_text().starts_with("; SPIR-V\n"));
//println!("Compiled Vertex Shader: {}", text_result.as_text());
let vert_spirv = {
unsafe { ShaderModule::new(device.clone(), binary_result.as_binary_u8()) }.unwrap()
};
vert_spirv
到目前为止,一切都很好,我们已经ShaderModule
迈出了第一步。但是,我们实际上需要的是一个GraphicsEntryPoint
,然后我们可以将其放入我们的GraphicsPipeline
. 显然,GraphicsPipeline
这是我们将着色器、三角形和深度图以及所有可爱的东西串在一起的地方。
麻烦的是,我不知道执行此壮举的代码发生了什么:
pub fn shade_vertex <'a, S> (vert_spirv: &'a Arc<ShaderModule>) ->
GraphicsEntryPoint<'a, S, VertInput, VertOutput, VertLayout> {
let tn = unsafe {
vert_spirv.graphics_entry_point(
CStr::from_bytes_with_nul_unchecked(b"main\0"),
VertInput,
VertOutput,
VertLayout(ShaderStages { vertex: true, ..ShaderStages::none() }),
GraphicsShaderType::Vertex
)
};
tn
}
具体来说,什么是VertInput
和VertOutput
?我已经从示例中复制了它们。
这是我能找到的处理动态加载Shader
s 的最接近的示例。它看起来像Input
并且Output
正在寻找进入 SPIR-V 或其他东西的入口点,但我不知道该怎么做。我希望现有宏中的某处有一个函数可以为我解决这个问题。我已经走了这么远,但我似乎有点卡住了。
有没有其他人尝试在运行时加载着色器?