Description
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.