diff --git a/Cargo.toml b/Cargo.toml index 2185154e..70252672 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_hanabi" -version = "0.18.0" +version = "0.19.0-dev" authors = ["Jerome Humbert "] edition = "2021" rust-version = "1.89.0" diff --git a/src/render/aligned_buffer_vec.rs b/src/render/aligned_buffer_vec.rs index b68f9082..d7bd8be5 100644 --- a/src/render/aligned_buffer_vec.rs +++ b/src/render/aligned_buffer_vec.rs @@ -143,11 +143,7 @@ impl AlignedBufferVec { // we wouldn't be calling the xxx_bindings() helpers, we'd have earlied out // before. let buffer = self.buffer()?; - Some(BindingResource::Buffer(BufferBinding { - buffer, - offset: 0, - size: None, // entire buffer - })) + Some(buffer.as_entire_binding()) } /// Get a binding for a subset of the elements of the buffer. @@ -201,6 +197,7 @@ impl AlignedBufferVec { /// /// [`aligned_size()`]: crate::AlignedBufferVec::aligned_size #[inline] + #[must_use] pub fn dynamic_offset(&self, index: usize) -> u32 { let offset = self.aligned_size * index; assert!(offset <= u32::MAX as usize); @@ -208,6 +205,7 @@ impl AlignedBufferVec { } #[inline] + #[must_use] #[allow(dead_code)] pub fn is_empty(&self) -> bool { self.values.is_empty() diff --git a/src/render/effect_cache.rs b/src/render/effect_cache.rs index 7506539a..dedfc6fe 100644 --- a/src/render/effect_cache.rs +++ b/src/render/effect_cache.rs @@ -9,7 +9,14 @@ use bevy::{ ecs::{component::Component, resource::Resource}, log::{trace, warn}, platform::collections::HashMap, - render::{mesh::allocator::MeshBufferSlice, render_resource::*, renderer::RenderDevice}, + render::{ + mesh::allocator::MeshBufferSlice, + render_resource::{ + binding_types::{storage_buffer_read_only, storage_buffer_read_only_sized}, + *, + }, + renderer::RenderDevice, + }, utils::default, }; use bytemuck::cast_slice_mut; @@ -19,7 +26,7 @@ use crate::{ asset::EffectAsset, render::{ calc_hash, event::GpuChildInfo, GpuDrawIndexedIndirectArgs, GpuDrawIndirectArgs, - GpuEffectMetadata, GpuSpawnerParams, StorageType as _, INDIRECT_INDEX_SIZE, + GpuEffectMetadata, GpuIndirectIndex, GpuSpawnerParams, StorageType as _, }, ParticleLayout, }; @@ -318,52 +325,22 @@ impl ParticleSlab { let spawner_params_size = GpuSpawnerParams::aligned_size( render_device.limits().min_storage_buffer_offset_alignment, ); - let entries = [ - // @group(1) @binding(0) var particle_buffer : ParticleBuffer; - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX_FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: Some(particle_layout.min_binding_size()), - }, - count: None, - }, - // @group(1) @binding(1) var indirect_buffer : IndirectBuffer; - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::VERTEX, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: Some(NonZeroU64::new(INDIRECT_INDEX_SIZE as u64).unwrap()), - }, - count: None, - }, - // @group(1) @binding(2) var spawner : Spawner; - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::VERTEX, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: true, - min_binding_size: Some(spawner_params_size), - }, - count: None, - }, - ]; - let label = format!( - "hanabi:bind_group_layout:render:particles@1:slab{}", - slab_id.0 - ); - trace!( - "Creating particles@1 layout '{}' for render pass with {} entries", - label, - entries.len(), + let label = format!("hanabi:bgl:render:particles@1:slab{}", slab_id.0); + let render_particles_buffer_layout = render_device.create_bind_group_layout( + &label[..], + &BindGroupLayoutEntries::sequential( + ShaderStages::VERTEX, + ( + // @group(1) @binding(0) var particle_buffer : ParticleBuffer; + storage_buffer_read_only_sized(false, Some(particle_layout.min_binding_size())) + .visibility(ShaderStages::VERTEX_FRAGMENT), + // @group(1) @binding(1) var indirect_buffer : IndirectBuffer; + storage_buffer_read_only::(false), + // @group(1) @binding(2) var spawner : Spawner; + storage_buffer_read_only_sized(true, Some(spawner_params_size)), + ), + ), ); - let render_particles_buffer_layout = - render_device.create_bind_group_layout(&label[..], &entries[..]); Self { particle_buffer, @@ -445,35 +422,20 @@ impl ParticleSlab { return; } - let label = format!("hanabi:bind_group:sim:particle@1:vfx{}", slab_id.index()); + let label = format!("hanabi:bg:sim:particle@1:vfx{}", slab_id.index()); let entries: &[BindGroupEntry] = if let Some(parent_binding) = parent_binding_source.as_ref().map(|bbs| bbs.as_binding()) { - &[ - BindGroupEntry { - binding: 0, - resource: self.as_entire_binding_particle(), - }, - BindGroupEntry { - binding: 1, - resource: self.as_entire_binding_indirect(), - }, - BindGroupEntry { - binding: 2, - resource: parent_binding, - }, - ] + &BindGroupEntries::sequential(( + self.as_entire_binding_particle(), + self.as_entire_binding_indirect(), + parent_binding, + )) } else { - &[ - BindGroupEntry { - binding: 0, - resource: self.as_entire_binding_particle(), - }, - BindGroupEntry { - binding: 1, - resource: self.as_entire_binding_indirect(), - }, - ] + &BindGroupEntries::sequential(( + self.as_entire_binding_particle(), + self.as_entire_binding_indirect(), + )) }; trace!( @@ -1143,7 +1105,7 @@ fn create_particle_sim_bind_group_layout_desc( ty: BindingType::Buffer { ty: BufferBindingType::Storage { read_only: false }, has_dynamic_offset: false, - min_binding_size: Some(NonZeroU64::new(INDIRECT_INDEX_SIZE as _).unwrap()), + min_binding_size: Some(GpuIndirectIndex::SHADER_SIZE), }, count: None, }); @@ -1164,7 +1126,7 @@ fn create_particle_sim_bind_group_layout_desc( } let hash = calc_hash(&entries); - let label = format!("hanabi:bind_group_layout:sim:particles_{:016X}", hash); + let label = format!("hanabi:bgl:sim:particles_{:016X}", hash); trace!( "Creating particle bind group layout '{}' for init pass with {} entries. (parent_buffer:{})", label, @@ -1227,7 +1189,7 @@ fn create_metadata_init_bind_group_layout_desc( let hash = calc_hash(&entries); let label = format!( - "hanabi:bind_group_layout:init:metadata@3_{}{:016X}", + "hanabi:bgl:init:metadata@3_{}{:016X}", if consume_gpu_spawn_events { "events" } else { @@ -1301,7 +1263,7 @@ fn create_metadata_update_bind_group_layout_desc( } let hash = calc_hash(&entries); - let label = format!("hanabi:bind_group_layout:update:metadata_{:016X}", hash); + let label = format!("hanabi:bgl:update:metadata_{:016X}", hash); trace!( "Creating particle bind group layout '{}' for init update with {} entries. (num_event_buffers:{})", label, diff --git a/src/render/event.rs b/src/render/event.rs index e80ae726..280ff53e 100644 --- a/src/render/event.rs +++ b/src/render/event.rs @@ -10,7 +10,10 @@ use bevy::{ log::{error, trace}, prelude::{Component, Entity, ResMut, Resource}, render::{ - render_resource::{BindGroup, BindGroupLayout, Buffer, ShaderSize as _, ShaderType}, + render_resource::{ + binding_types::storage_buffer, BindGroup, BindGroupEntries, BindGroupLayout, + BindGroupLayoutEntries, Buffer, ShaderSize as _, ShaderType, + }, renderer::{RenderDevice, RenderQueue}, }, }; @@ -20,10 +23,7 @@ use thiserror::Error; use wgpu::util::BufferInitDescriptor; #[cfg(not(debug_assertions))] use wgpu::BufferDescriptor; -use wgpu::{ - BindGroupEntry, BindGroupLayoutEntry, BindingResource, BindingType, BufferBinding, - BufferBindingType, BufferUsages, CommandEncoder, ShaderStages, -}; +use wgpu::{BufferUsages, CommandEncoder, ShaderStages}; use super::{ aligned_buffer_vec::HybridAlignedBufferVec, effect_cache::SlabState, gpu_buffer::GpuBuffer, @@ -345,17 +345,11 @@ impl EventCache { ); let child_infos_bind_group_layout = device.create_bind_group_layout( - "hanabi:bind_group_layout:indirect:child_infos@3", - &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: false, - min_binding_size: Some(GpuChildInfo::min_size()), - }, - count: None, - }], + "hanabi:bgl:indirect:child_infos@3", + &BindGroupLayoutEntries::single( + ShaderStages::COMPUTE, + storage_buffer::(false), + ), ); Self { @@ -641,16 +635,9 @@ impl EventCache { let buffer = self.child_infos_buffer()?; // TODO - stop re-creating each frame... self.indirect_child_info_buffer_bind_group = Some(device.create_bind_group( - "hanabi:bind_group:indirect:child_infos@3", + "hanabi:bg:indirect:child_infos@3", &self.indirect_child_info_buffer_bind_group_layout, - &[BindGroupEntry { - binding: 0, - resource: BindingResource::Buffer(BufferBinding { - buffer, - offset: 0, - size: None, - }), - }], + &BindGroupEntries::single(buffer.as_entire_binding()), )); self.indirect_child_info_buffer_bind_group.as_ref() } diff --git a/src/render/mod.rs b/src/render/mod.rs index e3ea393e..9b30cc01 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -41,7 +41,13 @@ use bevy::{ Draw, DrawError, DrawFunctions, PhaseItemExtraIndex, SortedPhaseItem, TrackedRenderPass, ViewSortedRenderPhases, }, - render_resource::*, + render_resource::{ + binding_types::{ + storage_buffer, storage_buffer_read_only, storage_buffer_read_only_sized, + storage_buffer_sized, uniform_buffer, + }, + *, + }, renderer::{RenderContext, RenderDevice, RenderQueue}, sync_world::{MainEntity, RenderEntity, TemporaryRenderEntity}, texture::GpuImage, @@ -100,9 +106,18 @@ pub(crate) use sort::SortBindGroups; use self::batch::EffectBatch; -// Size of an indirect index (including both parts of the ping-pong buffer) in -// bytes. -const INDIRECT_INDEX_SIZE: u32 = 12; +/// GPU representation of a single entry in the indirect index buffer of +/// particles. +#[repr(C)] +#[derive(Debug, Copy, Clone, Pod, Zeroable, ShaderType)] +struct GpuIndirectIndex { + /// Ping-pong indirection index for particles (ping). + pub ping: u32, + /// Ping-pong indirection index for particles (pong). + pub pong: u32, + /// Indirection index for dead particles, for recycling. + pub dead: u32, +} /// Helper to calculate a hash of a given hashable value. fn calc_hash(value: &H) -> u64 { @@ -709,17 +724,11 @@ impl FromWorld for DispatchIndirectPipeline { // @group(0) @binding(0) var sim_params : SimParams; trace!("GpuSimParams: min_size={}", GpuSimParams::min_size()); let sim_params_bind_group_layout = BindGroupLayoutDescriptor::new( - "hanabi:bind_group_layout:dispatch_indirect:sim_params", - &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: Some(GpuSimParams::min_size()), - }, - count: None, - }], + "hanabi:bgl:dispatch_indirect:sim_params", + &BindGroupLayoutEntries::single( + ShaderStages::COMPUTE, + uniform_buffer::(false), + ), ); trace!( @@ -728,79 +737,41 @@ impl FromWorld for DispatchIndirectPipeline { effect_metadata_size, ); let effect_metadata_bind_group_layout = BindGroupLayoutDescriptor::new( - "hanabi:bind_group_layout:dispatch_indirect:effect_metadata@1", - &[ - // @group(0) @binding(0) var effect_metadata_buffer : - // array; - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: false, - min_binding_size: Some(effect_metadata_size), - }, - count: None, - }, - // @group(0) @binding(1) var dispatch_indirect_buffer : - // array; - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: false, - min_binding_size: Some( - NonZeroU64::new(INDIRECT_INDEX_SIZE as u64).unwrap(), - ), - }, - count: None, - }, - // @group(0) @binding(2) var draw_indirect_buffer : - // array; - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: false, - min_binding_size: Some(GpuDrawIndexedIndirectArgs::SHADER_SIZE), - }, - count: None, - }, - ], + "hanabi:bgl:dispatch_indirect:effect_metadata@1", + &BindGroupLayoutEntries::sequential( + ShaderStages::COMPUTE, + ( + // @group(1) @binding(0) var effect_metadata_buffer : + // array; + storage_buffer_sized(false, Some(effect_metadata_size)), + // @group(1) @binding(1) var dispatch_indirect_buffer : + // array; + storage_buffer::(false), + // @group(1) @binding(2) var draw_indirect_buffer : + // array; + storage_buffer::(false), + ), + ), ); // @group(2) @binding(0) var spawner_buffer : // array; let spawner_bind_group_layout = BindGroupLayoutDescriptor::new( - "hanabi:bind_group_layout:dispatch_indirect:spawner@2", - &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: false, - min_binding_size: Some(spawner_min_binding_size), - }, - count: None, - }], + "hanabi:bgl:dispatch_indirect:spawner@2", + &BindGroupLayoutEntries::single( + ShaderStages::COMPUTE, + storage_buffer_sized(false, Some(spawner_min_binding_size)), + ), ); // @group(3) @binding(0) var child_info_buffer : // ChildInfoBuffer; let child_infos_bind_group_layout = BindGroupLayoutDescriptor::new( - "hanabi:bind_group_layout:dispatch_indirect:child_infos", - &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: false, - min_binding_size: Some(GpuChildInfo::min_size()), - }, - count: None, - }], + "hanabi:bgl:dispatch_indirect:child_infos", + &BindGroupLayoutEntries::single( + ShaderStages::COMPUTE, + storage_buffer::(false), + ), ); Self { @@ -1104,7 +1075,7 @@ impl GpuBufferOperations { self.bind_groups.entry(key).or_insert_with(|| { let src_id: NonZeroU32 = qop.src_buffer.id().into(); let dst_id: NonZeroU32 = qop.dst_buffer.id().into(); - let label = format!("hanabi:bind_group:util_{}_{}", src_id.get(), dst_id.get()); + let label = format!("hanabi:bg:util_{}_{}", src_id.get(), dst_id.get()); let use_dynamic_offset = matches!(qop.op, GpuBufferOperationType::FillDispatchArgs); let bind_group_layout = utils_pipeline.bind_group_layout(qop.op, use_dynamic_offset); @@ -1256,39 +1227,15 @@ impl FromWorld for UtilsPipeline { let render_device = world.get_resource::().unwrap(); let bind_group_layout = render_device.create_bind_group_layout( - "hanabi:bind_group_layout:utils", - &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: Some(GpuBufferOperationArgs::min_size()), - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: NonZeroU64::new(4), - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: false, - min_binding_size: NonZeroU64::new(4), - }, - count: None, - }, - ], + "hanabi:bgl:utils", + &BindGroupLayoutEntries::sequential( + ShaderStages::COMPUTE, + ( + uniform_buffer::(false), + storage_buffer_read_only::(false), + storage_buffer::(false), + ), + ), ); let pipeline_layout = render_device.create_pipeline_layout(&PipelineLayoutDescriptor { @@ -1298,39 +1245,15 @@ impl FromWorld for UtilsPipeline { }); let bind_group_layout_dyn = render_device.create_bind_group_layout( - "hanabi:bind_group_layout:utils_dyn", - &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(GpuBufferOperationArgs::min_size()), - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: true, - min_binding_size: NonZeroU64::new(4), - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: true, - min_binding_size: NonZeroU64::new(4), - }, - count: None, - }, - ], + "hanabi:bgl:utils_dyn", + &BindGroupLayoutEntries::sequential( + ShaderStages::COMPUTE, + ( + uniform_buffer::(true), + storage_buffer_read_only::(true), + storage_buffer::(true), + ), + ), ); let pipeline_layout_dyn = render_device.create_pipeline_layout(&PipelineLayoutDescriptor { @@ -1352,6 +1275,7 @@ impl FromWorld for UtilsPipeline { }, count: None, }, + // (no binding #1) BindGroupLayoutEntry { binding: 2, visibility: ShaderStages::COMPUTE, @@ -1503,18 +1427,12 @@ pub(crate) struct ParticlesInitPipeline { impl Default for ParticlesInitPipeline { fn default() -> Self { let sim_params_layout_desc = BindGroupLayoutDescriptor::new( - "hanabi:bind_group_layout:vfx_init:sim_params@0", + "hanabi:bgl:vfx_init:sim_params@0", // @group(0) @binding(0) var sim_params: SimParams; - &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: Some(GpuSimParams::min_size()), - }, - count: None, - }], + &BindGroupLayoutEntries::single( + ShaderStages::COMPUTE, + uniform_buffer::(false), + ), ); Self { @@ -1621,34 +1539,18 @@ pub(crate) struct ParticlesUpdatePipeline { impl Default for ParticlesUpdatePipeline { fn default() -> Self { - trace!("GpuSimParams: min_size={}", GpuSimParams::min_size()); let sim_params_layout_desc = BindGroupLayoutDescriptor::new( - "hanabi:bind_group_layout:vfx_update:sim_params@0", - &[ - // @group(0) @binding(0) var sim_params : SimParams; - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: Some(GpuSimParams::min_size()), - }, - count: None, - }, - // @group(0) @binding(1) var draw_indirect_buffer : - // array; - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: false, - min_binding_size: Some(GpuDrawIndexedIndirectArgs::SHADER_SIZE), - }, - count: None, - }, - ], + "hanabi:bgl:vfx_update:sim_params@0", + &BindGroupLayoutEntries::sequential( + ShaderStages::COMPUTE, + ( + // @group(0) @binding(0) var sim_params : SimParams; + uniform_buffer::(false), + // @group(0) @binding(1) var draw_indirect_buffer : + // array; + storage_buffer::(false), + ), + ), ); Self { @@ -1802,31 +1704,16 @@ impl FromWorld for ParticlesRenderPipeline { let render_device = world.get_resource::().unwrap(); let view_layout_desc = BindGroupLayoutDescriptor::new( - "hanabi:bind_group_layout:render:view@0", - &[ - // @group(0) @binding(0) var view: View; - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX_FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(ViewUniform::min_size()), - }, - count: None, - }, - // @group(0) @binding(1) var sim_params : SimParams; - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::VERTEX_FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: Some(GpuSimParams::min_size()), - }, - count: None, - }, - ], + "hanabi:bgl:render:view@0", + &BindGroupLayoutEntries::sequential( + ShaderStages::VERTEX_FRAGMENT, + ( + // @group(0) @binding(0) var view: View; + uniform_buffer::(true), + // @group(0) @binding(1) var sim_params : SimParams; + uniform_buffer::(false), + ), + ), ); Self { @@ -1937,44 +1824,23 @@ impl SpecializedRenderPipeline for ParticlesRenderPipeline { .limits() .min_storage_buffer_offset_alignment; let spawner_min_binding_size = GpuSpawnerParams::aligned_size(alignment); - let entries = [ - // @group(1) @binding(0) var particle_buffer : ParticleBuffer; - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX_FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: Some(key.particle_layout.min_binding_size()), - }, - count: None, - }, - // @group(1) @binding(1) var indirect_buffer : IndirectBuffer; - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::VERTEX, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: Some(NonZeroU64::new(INDIRECT_INDEX_SIZE as u64).unwrap()), - }, - count: None, - }, - // @group(1) @binding(2) var spawner : Spawner; - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::VERTEX, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: true, - min_binding_size: Some(spawner_min_binding_size), - }, - count: None, - }, - ]; let particle_bind_group_layout_desc = BindGroupLayoutDescriptor::new( - "hanabi:bind_group_layout:render:particle@1", - &entries[..], + "hanabi:bgl:render:particle@1", + &BindGroupLayoutEntries::sequential( + ShaderStages::VERTEX, + ( + // @group(1) @binding(0) var particle_buffer : ParticleBuffer; + storage_buffer_read_only_sized( + false, + Some(key.particle_layout.min_binding_size()), + ) + .visibility(ShaderStages::VERTEX_FRAGMENT), + // @group(1) @binding(1) var indirect_buffer : IndirectBuffer; + storage_buffer_read_only::(false), + // @group(1) @binding(2) var spawner : Spawner; + storage_buffer_read_only_sized(true, Some(spawner_min_binding_size)), + ), + ), ); let mut layout = vec![ @@ -4903,11 +4769,8 @@ impl EffectBindGroups { ); } - let bind_group = render_device.create_bind_group( - "hanabi:bind_group:init:metadata@3", - layout, - &entries[..], - ); + let bind_group = + render_device.create_bind_group("hanabi:bg:init:metadata@3", layout, &entries[..]); trace!( "Created new metadata@3 bind group for init pass and buffer index {}: effect_metadata=#{}", @@ -5020,7 +4883,7 @@ impl EffectBindGroups { } let bind_group = render_device.create_bind_group( - "hanabi:bind_group:update:metadata@3", + "hanabi:bg:update:metadata@3", layout, &entries[..], ); @@ -5755,18 +5618,12 @@ pub(crate) fn prepare_gpu_resources( // Create the bind group for the camera/view parameters // FIXME - Not here! effects_meta.view_bind_group = Some(render_device.create_bind_group( - "hanabi:bind_group_camera_view", + "hanabi:bg:camera_view", &pipeline_cache.get_bind_group_layout(&render_pipeline.view_layout_desc), - &[ - BindGroupEntry { - binding: 0, - resource: view_binding, - }, - BindGroupEntry { - binding: 1, - resource: effects_meta.sim_params_uniforms.binding().unwrap(), - }, - ], + &BindGroupEntries::sequential(( + view_binding, + effects_meta.sim_params_uniforms.binding().unwrap(), + )), )); // Re-/allocate the draw indirect args buffer if needed @@ -6058,21 +5915,15 @@ pub(crate) fn prepare_bind_groups( if effects_meta.update_sim_params_bind_group.is_none() { if let Some(draw_indirect_buffer) = effects_meta.draw_indirect_buffer.buffer() { effects_meta.update_sim_params_bind_group = Some(render_device.create_bind_group( - "hanabi:bind_group:vfx_update:sim_params@0", + "hanabi:bg:vfx_update:sim_params@0", &pipeline_cache.get_bind_group_layout(&update_pipeline.sim_params_layout_desc), - &[ + &BindGroupEntries::sequential(( // @group(0) @binding(0) var sim_params : SimParams; - BindGroupEntry { - binding: 0, - resource: effects_meta.sim_params_uniforms.binding().unwrap(), - }, + effects_meta.sim_params_uniforms.binding().unwrap(), // @group(0) @binding(1) var draw_indirect_buffer : // array; - BindGroupEntry { - binding: 1, - resource: draw_indirect_buffer.as_entire_binding(), - }, - ], + draw_indirect_buffer.as_entire_binding(), + )), )); } else { debug!("Cannot allocate bind group for vfx_update:sim_params@0 - draw_indirect_buffer not ready"); @@ -6080,15 +5931,10 @@ pub(crate) fn prepare_bind_groups( } if effects_meta.indirect_sim_params_bind_group.is_none() { effects_meta.indirect_sim_params_bind_group = Some(render_device.create_bind_group( - "hanabi:bind_group:vfx_indirect:sim_params@0", + "hanabi:bg:vfx_indirect:sim_params@0", &pipeline_cache.get_bind_group_layout(&init_pipeline.sim_params_layout_desc), // FIXME - Shared with init - &[ - // @group(0) @binding(0) var sim_params : SimParams; - BindGroupEntry { - binding: 0, - resource: effects_meta.sim_params_uniforms.binding().unwrap(), - }, - ], + // @group(0) @binding(0) var sim_params : SimParams; + &BindGroupEntries::single(effects_meta.sim_params_uniforms.binding().unwrap()), )); } @@ -6106,30 +5952,21 @@ pub(crate) fn prepare_bind_groups( ) => { // Base bind group for indirect pass Some(render_device.create_bind_group( - "hanabi:bind_group:vfx_indirect:metadata@1", + "hanabi:bg:vfx_indirect:metadata@1", &pipeline_cache.get_bind_group_layout( &dispatch_indirect_pipeline.effect_metadata_bind_group_layout_desc, ), - &[ + &BindGroupEntries::sequential(( // @group(1) @binding(0) var effect_metadata_buffer : // array; - BindGroupEntry { - binding: 0, - resource: effect_metadata_buffer.as_entire_binding(), - }, + effect_metadata_buffer.as_entire_binding(), // @group(1) @binding(1) var dispatch_indirect_buffer // : array; - BindGroupEntry { - binding: 1, - resource: dispatch_indirect_buffer.as_entire_binding(), - }, + dispatch_indirect_buffer.as_entire_binding(), // @group(1) @binding(2) var draw_indirect_buffer : // array; - BindGroupEntry { - binding: 2, - resource: draw_indirect_buffer.as_entire_binding(), - }, - ], + draw_indirect_buffer.as_entire_binding(), + )), )) } @@ -6141,21 +5978,14 @@ pub(crate) fn prepare_bind_groups( // effects at once if effects_meta.indirect_spawner_bind_group.is_none() { let bind_group = render_device.create_bind_group( - "hanabi:bind_group:vfx_indirect:spawner@2", + "hanabi:bg:vfx_indirect:spawner@2", &pipeline_cache.get_bind_group_layout( &dispatch_indirect_pipeline.spawner_bind_group_layout_desc, ), - &[ + &BindGroupEntries::single( // @group(2) @binding(0) var spawner_buffer : array; - BindGroupEntry { - binding: 0, - resource: BindingResource::Buffer(BufferBinding { - buffer: &spawner_buffer, - offset: 0, - size: None, - }), - }, - ], + spawner_buffer.as_entire_binding(), + ), ); effects_meta.indirect_spawner_bind_group = Some(bind_group); @@ -6189,31 +6019,23 @@ pub(crate) fn prepare_bind_groups( let spawner_min_binding_size = GpuSpawnerParams::aligned_size( render_device.limits().min_storage_buffer_offset_alignment, ); - let entries = [ - // @group(1) @binding(0) var particle_buffer : ParticleBuffer; - BindGroupEntry { - binding: 0, - resource: particle_slab.as_entire_binding_particle(), - }, - // @group(1) @binding(1) var indirect_buffer : IndirectBuffer; - BindGroupEntry { - binding: 1, - resource: particle_slab.as_entire_binding_indirect(), - }, - // @group(1) @binding(2) var spawner : Spawner; - BindGroupEntry { - binding: 2, - resource: BindingResource::Buffer(BufferBinding { + let render = render_device.create_bind_group( + &format!("hanabi:bg:render:particles@1:vfx{slab_index}")[..], + particle_slab.render_particles_buffer_layout(), + &BindGroupEntries::sequential(( + // @group(1) @binding(0) var particle_buffer : + // ParticleBuffer; + particle_slab.as_entire_binding_particle(), + // @group(1) @binding(1) var indirect_buffer : + // IndirectBuffer; + particle_slab.as_entire_binding_indirect(), + // @group(1) @binding(2) var spawner : Spawner; + BindingResource::Buffer(BufferBinding { buffer: &spawner_buffer, offset: 0, size: Some(spawner_min_binding_size), }), - }, - ]; - let render = render_device.create_bind_group( - &format!("hanabi:bind_group:render:particles@1:vfx{slab_index}")[..], - particle_slab.render_particles_buffer_layout(), - &entries[..], + )), ); BufferBindGroups { render } diff --git a/src/render/property.rs b/src/render/property.rs index d072b9f1..a25473b5 100644 --- a/src/render/property.rs +++ b/src/render/property.rs @@ -9,14 +9,14 @@ use bevy::{ platform::collections::HashMap, prelude::{Component, Entity, Query, Res, ResMut, Resource}, render::{ - render_resource::{BindGroup, BindGroupLayoutDescriptor, Buffer, PipelineCache}, + render_resource::{ + binding_types::storage_buffer_read_only_sized, BindGroup, BindGroupEntries, + BindGroupLayoutDescriptor, BindGroupLayoutEntries, Buffer, PipelineCache, + }, renderer::{RenderDevice, RenderQueue}, }, }; -use wgpu::{ - BindGroupEntry, BindGroupLayoutEntry, BindingResource, BindingType, BufferBinding, - BufferBindingType, BufferUsages, ShaderStages, -}; +use wgpu::{BufferBinding, BufferUsages, ShaderStages}; use super::{aligned_buffer_vec::HybridAlignedBufferVec, effect_cache::SlabState}; use crate::{ @@ -157,18 +157,12 @@ impl PropertyCache { let spawner_min_binding_size = GpuSpawnerParams::aligned_size(device.limits().min_storage_buffer_offset_alignment); let bgl = BindGroupLayoutDescriptor::new( - "hanabi:bind_group_layout:no_property", - // @group(2) @binding(0) var spawner: Spawner; - &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: true, - min_binding_size: Some(spawner_min_binding_size), - }, - count: None, - }], + "hanabi:bgl:no_property", + &BindGroupLayoutEntries::single( + ShaderStages::COMPUTE, + // @group(2) @binding(0) var spawner: Spawner; + storage_buffer_read_only_sized(true, Some(spawner_min_binding_size)), + ), ); trace!( "-> created bind group layout desc for no-property variant: {:?}", @@ -217,7 +211,7 @@ impl PropertyCache { .entry(properties_min_binding_size.get() as u32) .or_insert_with(|| { let label = format!( - "hanabi:bind_group_layout:property_size{}", + "hanabi:bgl:property_size{}", properties_min_binding_size.get() ); trace!( @@ -227,30 +221,15 @@ impl PropertyCache { ); let bgl = BindGroupLayoutDescriptor::new( label, - &[ - // @group(2) @binding(0) var spawner: Spawner; - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: true, - min_binding_size: Some(spawner_min_binding_size), - }, - count: None, - }, - // @group(2) @binding(1) var properties : Properties; - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: true, - min_binding_size: Some(properties_min_binding_size), - }, - count: None, - }, - ], + &BindGroupLayoutEntries::sequential( + ShaderStages::COMPUTE, + ( + // @group(2) @binding(0) var spawner: Spawner; + storage_buffer_read_only_sized(true, Some(spawner_min_binding_size)), + // @group(2) @binding(1) var properties : Properties; + storage_buffer_read_only_sized(true, Some(properties_min_binding_size)), + ), + ), ); trace!( "-> created bind group layout desc for size {}: {:?}", @@ -405,29 +384,23 @@ impl PropertyBindGroups { render_device.create_bind_group( Some( &format!( - "hanabi:bind_group:spawner@2:property{}_size{}", + "hanabi:bg:spawner@2:property{}_size{}", property_key.buffer_index, property_key.binding_size )[..], ), &pipeline_cache.get_bind_group_layout(layout_desc), - &[ - BindGroupEntry { - binding: 0, - resource: BindingResource::Buffer(BufferBinding { - buffer: spawner_buffer, - offset: 0, - size: Some(spawner_buffer_binding_size), - }), + &BindGroupEntries::sequential(( + BufferBinding { + buffer: spawner_buffer, + offset: 0, + size: Some(spawner_buffer_binding_size), }, - BindGroupEntry { - binding: 1, - resource: BindingResource::Buffer(BufferBinding { - buffer: property_buffer, - offset: 0, - size: Some(property_binding_size), - }), + BufferBinding { + buffer: property_buffer, + offset: 0, + size: Some(property_binding_size), }, - ], + )), ) }); Ok(()) @@ -452,16 +425,13 @@ impl PropertyBindGroups { if self.no_property_bind_group.is_none() { trace!("Creating new spawner@2 bind group for no-property variant"); self.no_property_bind_group = Some(render_device.create_bind_group( - Some("hanabi:bind_group:spawner@2:no-property"), + Some("hanabi:bg:spawner@2:no-property"), &pipeline_cache.get_bind_group_layout(layout_desc), - &[BindGroupEntry { - binding: 0, - resource: BindingResource::Buffer(BufferBinding { - buffer: spawner_buffer, - offset: 0, - size: Some(spawner_buffer_binding_size), - }), - }], + &BindGroupEntries::single(BufferBinding { + buffer: spawner_buffer, + offset: 0, + size: Some(spawner_buffer_binding_size), + }), )); } diff --git a/src/render/sort.rs b/src/render/sort.rs index d516fd72..03c77a80 100644 --- a/src/render/sort.rs +++ b/src/render/sort.rs @@ -6,21 +6,27 @@ use bevy::{ platform::collections::{hash_map::Entry, HashMap}, render::{ render_resource::{ - BindGroup, BindGroupLayoutDescriptor, Buffer, BufferId, CachedComputePipelineId, - CachedPipelineState, ComputePipelineDescriptor, PipelineCache, + binding_types::{ + storage_buffer, storage_buffer_read_only, storage_buffer_read_only_sized, + storage_buffer_sized, + }, + BindGroup, BindGroupEntries, BindGroupLayoutDescriptor, BindGroupLayoutEntries, Buffer, + BufferId, CachedComputePipelineId, CachedPipelineState, ComputePipelineDescriptor, + PipelineCache, ShaderType, }, renderer::RenderDevice, }, shader::Shader, utils::default, }; -use wgpu::{ - BindGroupEntry, BindGroupLayoutEntry, BindingResource, BindingType, BufferBinding, - BufferBindingType, BufferDescriptor, BufferUsages, CommandEncoder, ShaderStages, -}; +use bytemuck::{Pod, Zeroable}; +use wgpu::{BufferBinding, BufferDescriptor, BufferUsages, CommandEncoder, ShaderStages}; use super::{gpu_buffer::GpuBuffer, GpuDispatchIndirectArgs, GpuEffectMetadata, StorageType}; -use crate::{render::GpuSpawnerParams, Attribute, ParticleLayout}; +use crate::{ + render::{GpuIndirectIndex, GpuSpawnerParams}, + Attribute, ParticleLayout, +}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] struct SortFillBindGroupLayoutKey { @@ -58,6 +64,23 @@ struct SortCopyBindGroupKey { effect_metadata: BufferId, } +/// GPU representation of a single dual-key value pair, with the added buffer +/// count as prefix. This is mainly used for shorcuts in bindings, not directly +/// as a type. +#[repr(C)] +#[derive(Debug, Copy, Clone, Pod, Zeroable, ShaderType)] +struct GpuSortBufferSingleEntry { + /// Number of key-value pairs to sort. This is the first element of the + /// entire buffer. + pub count: u32, + /// Key for the first entry. + pub key: u32, + /// Secondary key for the first entry. + pub key2: u32, + /// Value for the first entry. + pub value: u32, +} + #[derive(Resource)] pub struct SortBindGroups { /// Render device. @@ -121,17 +144,12 @@ impl SortBindGroups { ); let sort_bind_group_layout_desc = BindGroupLayoutDescriptor::new( - "hanabi:bind_group_layout:sort", - &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: false, - min_binding_size: Some(NonZeroU64::new(16).unwrap()), // count + dual kv pair - }, - count: None, - }], + "hanabi:bgl:sort", + &BindGroupLayoutEntries::single( + ShaderStages::COMPUTE, + storage_buffer_sized(false, Some(NonZeroU64::new(16).unwrap())), /* count + dual + * kv pair */ + ), ); let sort_pipeline_id = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { @@ -146,55 +164,25 @@ impl SortBindGroups { let alignment = render_device.limits().min_storage_buffer_offset_alignment; let sort_copy_bind_group_layout_desc = BindGroupLayoutDescriptor::new( - "hanabi:bind_group_layout:sort_copy", - &[ - // @group(0) @binding(0) var indirect_index_buffer : - // IndirectIndexBuffer; - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: false, - min_binding_size: Some(NonZeroU64::new(12).unwrap()), // ping/pong+dead - }, - count: None, - }, - // @group(0) @binding(1) var sort_buffer : SortBuffer; - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: Some(NonZeroU64::new(16).unwrap()), /* count + dual kv - * pair */ - }, - count: None, - }, - // @group(0) @binding(2) var effect_metadata : EffectMetadata; - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: true, - min_binding_size: Some(GpuEffectMetadata::aligned_size(alignment)), - }, - count: None, - }, - // @group(0) @binding(3) var spawner : Spawner; - BindGroupLayoutEntry { - binding: 3, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: true, - min_binding_size: Some(GpuSpawnerParams::aligned_size(alignment)), - }, - count: None, - }, - ], + "hanabi:bgl:sort_copy", + &BindGroupLayoutEntries::sequential( + ShaderStages::COMPUTE, + ( + // @group(0) @binding(0) var indirect_index_buffer : + // IndirectIndexBuffer; + storage_buffer::(false), + // @group(0) @binding(1) var sort_buffer : SortBuffer; + storage_buffer_read_only::(false), + // @group(0) @binding(2) var effect_metadata : + // EffectMetadata; + storage_buffer_sized(true, Some(GpuEffectMetadata::aligned_size(alignment))), + // @group(0) @binding(3) var spawner : Spawner; + storage_buffer_read_only_sized( + true, + Some(GpuSpawnerParams::aligned_size(alignment)), + ), + ), + ), ); let sort_copy_pipeline_id = @@ -337,64 +325,35 @@ impl SortBindGroups { .limits() .min_storage_buffer_offset_alignment; let bind_group_layout_desc = BindGroupLayoutDescriptor::new( - "hanabi:bind_group_layout:sort_fill", - &[ - // @group(0) @binding(0) var sort_buffer : SortBuffer; - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: false, - min_binding_size: Some(NonZeroU64::new(16).unwrap()), // count + dual kv pair - }, - count: None, - }, - // @group(0) @binding(1) var particle_buffer : RawParticleBuffer; - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: Some(key.particle_min_binding_size.into()), - }, - count: None, - }, - // @group(0) @binding(2) var indirect_index_buffer : array; - BindGroupLayoutEntry { - binding: 2, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: Some(NonZeroU64::new(12).unwrap()), // ping/pong+dead - }, - count: None, - }, - // @group(0) @binding(3) var effect_metadata : EffectMetadata; - BindGroupLayoutEntry { - binding: 3, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: false }, - has_dynamic_offset: true, - min_binding_size: Some(GpuEffectMetadata::aligned_size(alignment)), - }, - count: None, - }, - // @group(0) @binding(4) var spawner : Spawner; - BindGroupLayoutEntry { - binding: 4, - visibility: ShaderStages::COMPUTE, - ty: BindingType::Buffer { - ty: BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: true, - min_binding_size: Some(GpuSpawnerParams::aligned_size(alignment)), - }, - count: None, - }, - ], + "hanabi:bgl:sort_fill", + &BindGroupLayoutEntries::sequential( + ShaderStages::COMPUTE, + ( + // @group(0) @binding(0) var sort_buffer : + // SortBuffer; + storage_buffer::(false), + // @group(0) @binding(1) var particle_buffer : + // RawParticleBuffer; + storage_buffer_read_only_sized( + false, + Some(key.particle_min_binding_size.into()), + ), + // @group(0) @binding(2) var indirect_index_buffer : + // array; + storage_buffer_read_only::(false), + // @group(0) @binding(3) var effect_metadata : + // EffectMetadata; + storage_buffer_sized( + true, + Some(GpuEffectMetadata::aligned_size(alignment)), + ), + // @group(0) @binding(4) var spawner : Spawner; + storage_buffer_read_only_sized( + true, + Some(GpuSpawnerParams::aligned_size(alignment)), + ), + ), + ), ); let pipeline_id = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { @@ -468,55 +427,40 @@ impl SortBindGroups { .0; entry.insert( self.render_device.create_bind_group( - "hanabi:bind_group:sort_fill", + "hanabi:bg:sort_fill", &pipeline_cache.get_bind_group_layout(layout_desc), - &[ + &BindGroupEntries::sequential(( // @group(0) @binding(0) var pairs: // array; - BindGroupEntry { - binding: 0, - resource: self.sort_buffer.as_entire_binding(), - }, + self.sort_buffer.as_entire_binding(), // @group(0) @binding(1) var particle_buffer: // ParticleBuffer; - BindGroupEntry { - binding: 1, - resource: particle.as_entire_binding(), - }, + particle.as_entire_binding(), // @group(0) @binding(2) var indirect_index_buffer : // array; - BindGroupEntry { - binding: 2, - resource: indirect_index.as_entire_binding(), - }, + indirect_index.as_entire_binding(), // @group(0) @binding(3) var effect_metadata : // EffectMetadata; - BindGroupEntry { - binding: 3, - resource: BindingResource::Buffer(BufferBinding { - buffer: effect_metadata, - offset: 0, - size: Some(GpuEffectMetadata::aligned_size( - self.render_device - .limits() - .min_storage_buffer_offset_alignment, - )), - }), + BufferBinding { + buffer: effect_metadata, + offset: 0, + size: Some(GpuEffectMetadata::aligned_size( + self.render_device + .limits() + .min_storage_buffer_offset_alignment, + )), }, // @group(0) @binding(4) var spawner : Spawner; - BindGroupEntry { - binding: 4, - resource: BindingResource::Buffer(BufferBinding { - buffer: spawner_buffer, - offset: 0, - size: Some(GpuSpawnerParams::aligned_size( - self.render_device - .limits() - .min_storage_buffer_offset_alignment, - )), - }), + BufferBinding { + buffer: spawner_buffer, + offset: 0, + size: Some(GpuSpawnerParams::aligned_size( + self.render_device + .limits() + .min_storage_buffer_offset_alignment, + )), }, - ], + )), ), ) } @@ -545,15 +489,10 @@ impl SortBindGroups { ) -> Result<&BindGroup, ()> { if self.sort_bind_group.is_none() { let sort_bind_group = self.render_device.create_bind_group( - "hanabi:bind_group:sort", + "hanabi:bg:sort", &pipeline_cache.get_bind_group_layout(&self.sort_bind_group_layout_desc), - &[ - // @group(0) @binding(0) var pairs : array; - BindGroupEntry { - binding: 0, - resource: self.sort_buffer.as_entire_binding(), - }, - ], + // @group(0) @binding(0) var pairs : array; + &BindGroupEntries::single(self.sort_buffer.as_entire_binding()), ); self.sort_bind_group = Some(sort_bind_group); } @@ -583,49 +522,37 @@ impl SortBindGroups { Entry::Vacant(entry) => { entry.insert( self.render_device.create_bind_group( - "hanabi:bind_group:sort_copy", + "hanabi:bg:sort_copy", &pipeline_cache .get_bind_group_layout(&self.sort_copy_bind_group_layout_desc), - &[ + &BindGroupEntries::sequential(( // @group(0) @binding(0) var indirect_index_buffer // : IndirectIndexBuffer; - BindGroupEntry { - binding: 0, - resource: indirect_index_buffer.as_entire_binding(), - }, + indirect_index_buffer.as_entire_binding(), // @group(0) @binding(1) var sort_buffer : SortBuffer; - BindGroupEntry { - binding: 1, - resource: self.sort_buffer.as_entire_binding(), - }, + self.sort_buffer.as_entire_binding(), // @group(0) @binding(2) var effect_metadata : // EffectMetadata; - BindGroupEntry { - binding: 2, - resource: BindingResource::Buffer(BufferBinding { - buffer: effect_metadata_buffer, - offset: 0, - size: Some(GpuEffectMetadata::aligned_size( - self.render_device - .limits() - .min_storage_buffer_offset_alignment, - )), - }), + BufferBinding { + buffer: effect_metadata_buffer, + offset: 0, + size: Some(GpuEffectMetadata::aligned_size( + self.render_device + .limits() + .min_storage_buffer_offset_alignment, + )), }, // @group(0) @binding(3) var spawner : Spawner; - BindGroupEntry { - binding: 3, - resource: BindingResource::Buffer(BufferBinding { - buffer: spawner_buffer, - offset: 0, - size: Some(GpuSpawnerParams::aligned_size( - self.render_device - .limits() - .min_storage_buffer_offset_alignment, - )), - }), + BufferBinding { + buffer: spawner_buffer, + offset: 0, + size: Some(GpuSpawnerParams::aligned_size( + self.render_device + .limits() + .min_storage_buffer_offset_alignment, + )), }, - ], + )), ), ) }