Skip to content

Panic / segfault when trying to create a custom bindless material with storage buffers. #18853

Open
@inodentry

Description

@inodentry

Bevy version

Bevy 0.16.0-rc.5

[Optional] Relevant system information

Asahi Linux, Apple M1 Pro

2025-04-15T14:42:33.261113Z  INFO bevy_render::renderer: AdapterInfo { name: "Apple M1 Pro (G13S C0)", vendor: 65541, device: 0, device_type: IntegratedGpu, driver: "Honeykrisp", driver_info: "Mesa 25.1.0-asahi20250221", backend: Vulkan }
2025-04-15T14:42:33.398102Z  INFO bevy_render::batching::gpu_preprocessing: GPU preprocessing is fully supported on this device.

What you did

I tried to create my own bindless material, learning from the docs, the examples, and the StandardMaterial source code.

Here is my material:

#[derive(AsBindGroup, Clone, Asset, TypePath)]
#[data(0, TerrainMaterialUniform, binding_array(10))]
#[bindless]
pub struct TerrainMaterial {
    mask_index: u32,
    #[storage(1, read_only)]
    mat_props: Handle<ShaderStorageBuffer>,
    #[storage(2, read_only)]
    tex_props: Handle<ShaderStorageBuffer>,
    #[texture(3, dimension = "2d_array")]
    #[sampler(4)]
    texmasks: Handle<Image>,
    #[texture(5, dimension = "2d_array")]
    #[sampler(6)]
    propmasks: Handle<Image>,
    #[texture(7, dimension = "2d_array")]
    #[sampler(8)]
    textures_color: Handle<Image>,
    #[texture(9, dimension = "2d_array")]
    #[sampler(10)]
    textures_normal: Handle<Image>,
}

impl Material for TerrainMaterial {
    fn fragment_shader() -> ShaderRef {
        "shaders/terrain.wgsl".into()
    }
}

#[derive(ShaderType, Clone, Copy)]
struct TerrainMaterialUniform {
    mask_index: u32,
}

impl From<&TerrainMaterial> for TerrainMaterialUniform {
    fn from(value: &TerrainMaterial) -> Self {
        Self {
            mask_index: value.mask_index,
        }
    }
}

As you can see, I have the following:

  • Some textures and samplers
  • Global uniform data (like StandardMaterial does)
  • Some custom storage buffers

I have not really written my shader code yet. I just made a simple dummy shader to test if bindless works:

#import bevy_pbr::forward_io::VertexOutput;

@fragment
fn fragment(input: VertexOutput) -> @location(0) vec4<f32> {
    #ifdef BINDLESS
    return vec4(1.0, 0.0, 0.0, 1.0);
    #else
    return vec4(0.0, 0.0, 1.0, 1.0);
    #endif
}

I spawned a simple plane mesh with my custom material to test. I expected to see it either solid red or solid blue, depending on the state of the BINDLESS shader def. Instead, I got a crash.

What went wrong

The code compiles (no error from the AsBindGroup derive), but crashes at runtime with the following:

2025-04-15T14:42:36.203590Z ERROR bevy_pbr::material_bind_groups: Binding array wasn't present for buffer at index BindlessIndex(1)

thread 'Compute Task Pool (5)' panicked at c/bevy/crates/bevy_pbr/src/material_bind_groups.rs:825:13:
An allocation into an empty slab should always succeed
stack backtrace:
   0: __rustc::rust_begin_unwind
             at /rustc/092a284ba0421695f2032c947765429fd7095796/library/std/src/panicking.rs:697:5
   1: core::panicking::panic_fmt
             at /rustc/092a284ba0421695f2032c947765429fd7095796/library/core/src/panicking.rs:75:14
   2: bevy_pbr::material_bind_groups::MaterialBindGroupBindlessAllocator<M>::allocate_unprepared
   3: <bevy_pbr::material::PreparedMaterial<M> as bevy_render::render_asset::RenderAsset>::prepare_asset
   4: bevy_render::render_asset::prepare_assets
   5: <bevy_ecs::system::schedule_system::InfallibleSystemWrapper<S> as bevy_ecs::system::system::System>::run_unsafe
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Encountered a panic in system `bevy_render::render_asset::prepare_assets<bevy_pbr::material::PreparedMaterial<mw_gfx::terrain::TerrainMaterial>>`!

thread 'Compute Task Pool (3)' panicked at c/crates/bevy_pbr/src/material_bind_groups.rs:707:18:
Bindings buffer must exist
stack backtrace:
   0: __rustc::rust_begin_unwind
             at /rustc/092a284ba0421695f2032c947765429fd7095796/library/std/src/panicking.rs:697:5
   1: core::panicking::panic_fmt
             at /rustc/092a284ba0421695f2032c947765429fd7095796/library/core/src/panicking.rs:75:14
   2: core::panicking::panic_display
             at /rustc/092a284ba0421695f2032c947765429fd7095796/library/core/src/panicking.rs:261:5
   3: core::option::expect_failed
             at /rustc/092a284ba0421695f2032c947765429fd7095796/library/core/src/option.rs:2024:5
   4: alloc::vec::Vec<T,A>::extend_trusted
   5: <alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter
   6: bevy_pbr::material_bind_groups::MaterialBindlessSlab<M>::prepare_bind_group
   7: bevy_pbr::material_bind_groups::MaterialBindlessSlab<M>::prepare
   8: <bevy_ecs::system::schedule_system::InfallibleSystemWrapper<S> as bevy_ecs::system::system::System>::run_unsafe
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Encountered a panic in system `bevy_pbr::material::prepare_material_bind_groups<mw_gfx::terrain::TerrainMaterial>`!

[1]    479258 segmentation fault (core dumped)  cargo run

Additional information

If I comment out the storage buffer bindings (but leave everything else as is: the textures, samplers, global data uniform), everything works. The game runs and I get the mesh rendered solid red, indicating that bindless is enabled.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-RenderingDrawing game state to the screenC-BugAn unexpected or incorrect behaviorP-CrashA sudden unexpected crashS-Needs-InvestigationThis issue requires detective work to figure out what's going wrong

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions