rust - 是否可以在运行时编译Vulkano着色器?

标签 rust glsl shader vulkan spir-v

我一直在使用Vulkano来进行一些简单的3D图形处理。通常,我喜欢用文本编写GLSL着色器,然后重新启动程序,甚至在程序运行时更改着色器。 Vulkano中给出的示例似乎使用宏将GLSL转换为某种形式的,附加了Rust函数的基于SPIR-V的着色器,但是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
}

具体来说,VertInputVertOutput是什么?我已将其复制为from the example

这是我能找到的最接近的示例,该示例涉及动态加载Shader。看起来InputOutput正在寻找SPIR-V的入口点,但我不知道该怎么做。我希望现有宏中的某个功能可以为我解决这个问题。我已经走了这么远,但是我似乎有点卡住了。

有没有其他人尝试在运行时加载着色器?

最佳答案

我正在使用wgpu,已将设备render_pipeline设置为多线程,如下所示:

let rx = Arc::new(Mutex::new(rx));
let window = Arc::new(Mutex::new(window));
let fs = Arc::new(Mutex::new(fs));
let fs_module = Arc::new(Mutex::new(fs_module));
let render_pipeline = Arc::new(Mutex::new(render_pipeline));
let device = Arc::new(Mutex::new(device));

使用notify监听更改事件:
notify = "4.0.15"
use notify::{RecommendedWatcher, Watcher, RecursiveMode};
//mainxx
let (tx, rx) = mpsc::channel();
let mut watcher: RecommendedWatcher =
    Watcher::new(tx, Duration::from_millis(500)).unwrap();

log::info!("Starting watcher on {:?}", *FRAG_SHADER_PATH);
watcher.watch((*FRAG_SHADER_PATH).clone(), RecursiveMode::NonRecursive).unwrap();

然后产生一个监听更改的线程:
thread::spawn(move || {
    log::info!("Shader watcher thread spawned");
    loop {
        if let Ok(notify::DebouncedEvent::Write(..)) = rx.lock().unwrap().recv() {
            log::info!("Write event in fragment shader");
            window.lock().unwrap().set_title("Loading shader.frag...");
            *fs.lock().unwrap() = load_fs().unwrap();
            *fs_module.lock().unwrap() = load_fs_module(Arc::clone(&device), &Arc::clone(&fs).lock().unwrap());
            *render_pipeline.lock().unwrap() = create_render_pipeline_multithreaded(Arc::clone(&device), Arc::clone(&fs_module));
            render.lock().unwrap().deref_mut()();
            window.lock().unwrap().set_title(TITLE);
        };
    }
});

其中load_fs是使用glsl_to_spirv的闭包:
let load_fs = move || -> Result<Vec<u32>, std::io::Error> {
    log::info!("Loading fragment shader");
    let mut buffer = String::new();
    let mut f = File::open(&*FRAG_SHADER_PATH)?;
    f.read_to_string(&mut buffer)?;

    // Load fragment shader
    wgpu::read_spirv(
        glsl_to_spirv::compile(
            &buffer,
            glsl_to_spirv::ShaderType::Fragment
        ).expect("Compilation failed")
    )
};

关于rust - 是否可以在运行时编译Vulkano着色器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53092022/

相关文章:

opengl - 具有深度立方体贴图的全向阴影贴图

serialization - 如何使用bincode序列化没有长度的切片?

serialization - 如何使用需要实现者实现 serde::Deserialize 的方法创建特征

opengl - 在 C++ 中使用 GLSL 和 OpenGL 中的 2D PNG 中的 3D 查找表

c# - 通过比较另一个图像的强度来改变图像的强度 - OpenTK

shader - 从瓷砖图集纹理重复瓷砖

opengl - 为什么此Phong着色器起作用?

rust - 跨多个特征借用数据时如何编写适当的通用函数签名

reference - 为什么我可以返回对本地文字的引用,而不是对变量的引用?

ios - 哪些 GLSL ES 扩展可在各种 iOS 设备上使用?