vulkano-rs / vulkano

Safe and rich Rust wrapper around the Vulkan API
Apache License 2.0
4.48k stars 433 forks source link

vulkano panicked when using with rust-gpu #2550

Closed SSSxCCC closed 1 month ago

SSSxCCC commented 1 month ago

rust-gpu shader:

#![no_std]

use spirv_std::{glam::{vec4, Vec2, Vec4}, spirv};

#[spirv(vertex)]
pub fn main_vs(
    #[spirv(position, invariant)] out_pos: &mut Vec4,
    position: Vec2,
) {
    *out_pos = position.extend(0.0).extend(1.0);
}

#[spirv(fragment)]
pub fn main_fs(output: &mut Vec4) {
    *output = vec4(1.0, 0.0, 0.0, 1.0);
}

vulkano code:

        const SHADER: &[u8] = include_bytes!(env!("minimal_shader.spv"));
        let shader_code = SHADER
            .chunks(4)
            .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
            .collect::<Vec<_>>();

        let shader_module = unsafe {
            ShaderModule::new(
                context.device().clone(),
                ShaderModuleCreateInfo::new(&shader_code),
            )
        }
        .unwrap();

        let vs = shader_module.entry_point("main_vs").unwrap();
        let fs = shader_module.entry_point("main_fs").unwrap();

        let vertex_input_state = MyVertex::per_vertex()
            .definition(&vs.info().input_interface) // panicked here
            .unwrap();

MyVertex:

#[derive(BufferContents, Vertex)]
#[repr(C)]
struct MyVertex {
    #[format(R32G32_SFLOAT)]
    position: [f32; 2],
}

Issue

thread 'main' panicked at 'called Option::unwrap() on a None value', C:\Users\SxC.cargo\registry\src\index.crates.io-6f17d22bba15001f\vulkano-0.34.1\src\pipeline\graphics\vertex_input\definition.rs:45:46

marc0246 commented 1 month ago

The unwrap was fixed in #2487. If you want to use vulkano's reflection capabilities, such as creating a matching vertex input state or generating structs using vulkano-shaders, you have to provide the necessary reflection information, that is, SpirvMetadata::NameVariables. You haven't provided the compilation code but I assume you haven't done this. As such, this working as inteded even in your version, minus the panic.

SSSxCCC commented 1 month ago

I add SpirvMetadata::NameVariables in build.rs and this issue is fixed. Thank you so much!

use spirv_builder::{MetadataPrintout, SpirvBuilder, SpirvMetadata};
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    SpirvBuilder::new("minimal-shader", "spirv-unknown-vulkan1.2")
        .spirv_metadata(SpirvMetadata::NameVariables) // this fix this issue
        .print_metadata(MetadataPrintout::Full)
        .build()?;

    Ok(())
}
marc0246 commented 1 month ago

No problem! (Though I think full is excessive?)

SSSxCCC commented 1 month ago

I just started to learn to use rust-gpu, MetadataPrintout::Full is copied from somewhere else. I just delete '.print_metadata(MetadataPrintout::Full)' and the code also works fine, thanks again!

marc0246 commented 1 month ago

I'm not 100% sure either because I don't actively use Rust-GPU, but I think you need MetadataPrintout::DependencyOnly. @Firestar99 could you be a darling and jump in here?

SSSxCCC commented 1 month ago

I just found that print_metadata is set to MetadataPrintout::Full in SpirvBuilder::new. So deleting '.print_metadata(MetadataPrintout::Full)' changes nothing.

I tried to change MetadataPrintout::Full to MetadataPrintout::DependencyOnly, but this resulted in a compilation error:

error: environment variable `minimal_shader.spv` not defined at compile time
   --> minimal\src\triangle_renderer.rs:132:46
    |
132 |         const SHADER: &[u8] = include_bytes!(env!("minimal_shader.spv"));
    |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use `std::env::var("minimal_shader.spv")` to read the variable at run time
    = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
Firestar99 commented 1 month ago

I've made a small sample project on how to integrate vulkano and rust-gpu, feel free to reference: https://github.com/Firestar99/rust-gpu-vulkano-example

The build script I'm using configures spirv-builder like this:

SpirvBuilder::new(crate_path, TARGET)
        .multimodule(true)
        // this needs at least NameVariables for vulkano to like the spv, but may also be Full
        .spirv_metadata(SpirvMetadata::NameVariables)
        .print_metadata(MetadataPrintout::DependencyOnly)
        .build()?;

Unfortunately the rust-gpu docs are a bit lacking, especially when you're trying to get started.

Firestar99 commented 1 month ago

Also feel free to steal the codegen of my main project, which generates a single .rs file containing each shader entry point as a separate shader! macro invocation with the correct *.spv path, all of them organized in the same mod structure as your shader crate. But I haven't gotten around to clean it up enough to release it publicly, though that may happen in a few months as I want to publish a bindless API for rust-gpu and vulkano (potentially wgpu as well?). https://gitlab.com/spacegamedev/space-rust/-/tree/master/vulkano-bindless/vulkano-bindless-shader-builder?ref_type=heads