Skip to content

Commit

Permalink
Remove unnecessary bindgroups module
Browse files Browse the repository at this point in the history
  • Loading branch information
sytherax committed Jul 6, 2024
1 parent 7162a51 commit 719a7cd
Show file tree
Hide file tree
Showing 8 changed files with 1,813 additions and 1,902 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ When deriving bytemuck, wgsl_bindgen will use naga's layout calculations to add

wgpu uses resource bindings organized into bind groups to define global shader resources like textures and buffers. Shaders can have many resource bindings organized into up to 4 bind groups. wgsl_bindgen will generate types and functions for initializing and setting these bind groups in a more typesafe way. Adding, removing, or changing bind groups in the WGSl shader will typically result in a compile error instead of a runtime error when compiling the code without updating the code for creating or using these bind groups.

While bind groups can easily be set all at once using the `bind_groups::set_bind_groups` function, it's recommended to organize bindings into bindgroups based on their update frequency. Bind group 0 will change the least frequently like per frame resources with bind group 3 changing most frequently like per draw resources. Bind groups can be set individually using their `set(render_pass)` method. This can provide a small performance improvement for scenes with many draw calls. See [descriptor table frequency (DX12)](https://learn.microsoft.com/en-us/windows/win32/direct3d12/advanced-use-of-descriptor-tables#changing-descriptor-table-entries-between-rendering-calls) and [descriptor set frequency (Vulkan)](https://vkguide.dev/docs/chapter-4/descriptors/#mental-model) for details.
While bind groups can easily be set all at once using the `set_bind_groups` function, it's recommended to organize bindings into bindgroups based on their update frequency. Bind group 0 will change the least frequently like per frame resources with bind group 3 changing most frequently like per draw resources. Bind groups can be set individually using their `set(render_pass)` method. This can provide a small performance improvement for scenes with many draw calls. See [descriptor table frequency (DX12)](https://learn.microsoft.com/en-us/windows/win32/direct3d12/advanced-use-of-descriptor-tables#changing-descriptor-table-entries-between-rendering-calls) and [descriptor set frequency (Vulkan)](https://vkguide.dev/docs/chapter-4/descriptors/#mental-model) for details.

Organizing bind groups in this way can also help to better organize rendering resources in application code instead of redundantly storing all resources with each object. The `bindgroups::BindGroup0` may only need to be stored once while `bindgroups::BindGroup3` may be stored for each mesh in the scene. Note that bind groups store references to their underlying resource bindings, so it is not necessary to recreate a bind group if the only the uniform or storage buffer contents change. Avoid creating new bind groups during rendering if possible for best performance.

Expand Down
987 changes: 480 additions & 507 deletions example/src/shader_bindings.rs

Large diffs are not rendered by default.

1,322 changes: 649 additions & 673 deletions wgsl_bindgen/src/generate/bind_group/mod.rs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion wgsl_bindgen/src/generate/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub fn create_pipeline_layout_fn(
.wgpu_binding_generator
.bind_group_layout
.bind_group_name_ident(*group_no);
quote!(bind_groups::#group::get_bind_group_layout(device))
quote!(#group::get_bind_group_layout(device))
})
.collect();

Expand Down
728 changes: 356 additions & 372 deletions wgsl_bindgen/tests/output/bindgen_bevy.expected.rs

Large diffs are not rendered by default.

378 changes: 184 additions & 194 deletions wgsl_bindgen/tests/output/bindgen_main.expected.rs

Large diffs are not rendered by default.

146 changes: 70 additions & 76 deletions wgsl_bindgen/tests/output/bindgen_minimal.expected.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,92 +79,86 @@ pub mod minimal {
data.build()
}
}
pub mod bind_groups {
use super::{_root, _root::*};
#[derive(Debug)]
pub struct WgpuBindGroup0EntriesParams<'a> {
pub uniform_buf: wgpu::BufferBinding<'a>,
#[derive(Debug)]
pub struct WgpuBindGroup0EntriesParams<'a> {
pub uniform_buf: wgpu::BufferBinding<'a>,
}
#[derive(Clone, Debug)]
pub struct WgpuBindGroup0Entries<'a> {
pub uniform_buf: wgpu::BindGroupEntry<'a>,
}
impl<'a> WgpuBindGroup0Entries<'a> {
pub fn new(params: WgpuBindGroup0EntriesParams<'a>) -> Self {
Self {
uniform_buf: wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(params.uniform_buf),
},
}
}
pub fn as_array(self) -> [wgpu::BindGroupEntry<'a>; 1] {
[self.uniform_buf]
}
#[derive(Clone, Debug)]
pub struct WgpuBindGroup0Entries<'a> {
pub uniform_buf: wgpu::BindGroupEntry<'a>,
pub fn collect<B: FromIterator<wgpu::BindGroupEntry<'a>>>(self) -> B {
self.as_array().into_iter().collect()
}
impl<'a> WgpuBindGroup0Entries<'a> {
pub fn new(params: WgpuBindGroup0EntriesParams<'a>) -> Self {
Self {
uniform_buf: wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(params.uniform_buf),
}
#[derive(Debug)]
pub struct WgpuBindGroup0(wgpu::BindGroup);
impl WgpuBindGroup0 {
pub const LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor<'static> = wgpu::BindGroupLayoutDescriptor {
label: Some("Minimal::BindGroup0::LayoutDescriptor"),
entries: &[
/// @binding(0): "uniform_buf"
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: std::num::NonZeroU64::new(
std::mem::size_of::<_root::minimal::Uniforms>() as _,
),
},
}
}
pub fn as_array(self) -> [wgpu::BindGroupEntry<'a>; 1] {
[self.uniform_buf]
}
pub fn collect<B: FromIterator<wgpu::BindGroupEntry<'a>>>(self) -> B {
self.as_array().into_iter().collect()
}
count: None,
},
],
};
pub fn get_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
device.create_bind_group_layout(&Self::LAYOUT_DESCRIPTOR)
}
#[derive(Debug)]
pub struct WgpuBindGroup0(wgpu::BindGroup);
impl WgpuBindGroup0 {
pub const LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor<'static> = wgpu::BindGroupLayoutDescriptor {
label: Some("Minimal::BindGroup0::LayoutDescriptor"),
entries: &[
/// @binding(0): "uniform_buf"
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: std::num::NonZeroU64::new(
std::mem::size_of::<_root::minimal::Uniforms>() as _,
),
},
count: None,
pub fn from_bindings(
device: &wgpu::Device,
bindings: WgpuBindGroup0Entries,
) -> Self {
let bind_group_layout = Self::get_bind_group_layout(&device);
let entries = bindings.as_array();
let bind_group = device
.create_bind_group(
&wgpu::BindGroupDescriptor {
label: Some("Minimal::BindGroup0"),
layout: &bind_group_layout,
entries: &entries,
},
],
};
pub fn get_bind_group_layout(
device: &wgpu::Device,
) -> wgpu::BindGroupLayout {
device.create_bind_group_layout(&Self::LAYOUT_DESCRIPTOR)
}
pub fn from_bindings(
device: &wgpu::Device,
bindings: WgpuBindGroup0Entries,
) -> Self {
let bind_group_layout = Self::get_bind_group_layout(&device);
let entries = bindings.as_array();
let bind_group = device
.create_bind_group(
&wgpu::BindGroupDescriptor {
label: Some("Minimal::BindGroup0"),
layout: &bind_group_layout,
entries: &entries,
},
);
Self(bind_group)
}
pub fn set<'a>(&'a self, render_pass: &mut wgpu::ComputePass<'a>) {
render_pass.set_bind_group(0, &self.0, &[]);
}
);
Self(bind_group)
}
#[derive(Debug, Copy, Clone)]
pub struct WgpuBindGroups<'a> {
pub bind_group0: &'a WgpuBindGroup0,
pub fn set<'a>(&'a self, render_pass: &mut wgpu::ComputePass<'a>) {
render_pass.set_bind_group(0, &self.0, &[]);
}
impl<'a> WgpuBindGroups<'a> {
pub fn set(&self, pass: &mut wgpu::ComputePass<'a>) {
self.bind_group0.set(pass);
}
}
#[derive(Debug, Copy, Clone)]
pub struct WgpuBindGroups<'a> {
pub bind_group0: &'a WgpuBindGroup0,
}
impl<'a> WgpuBindGroups<'a> {
pub fn set(&self, pass: &mut wgpu::ComputePass<'a>) {
self.bind_group0.set(pass);
}
}
pub use self::bind_groups::*;
pub fn set_bind_groups<'a>(
pass: &mut wgpu::ComputePass<'a>,
bind_group0: &'a bind_groups::WgpuBindGroup0,
bind_group0: &'a WgpuBindGroup0,
) {
bind_group0.set(pass);
}
Expand Down Expand Up @@ -203,7 +197,7 @@ pub mod minimal {
&wgpu::PipelineLayoutDescriptor {
label: Some("Minimal::PipelineLayout"),
bind_group_layouts: &[
&bind_groups::WgpuBindGroup0::get_bind_group_layout(device),
&WgpuBindGroup0::get_bind_group_layout(device),
],
push_constant_ranges: &[],
},
Expand Down
150 changes: 72 additions & 78 deletions wgsl_bindgen/tests/output/bindgen_padding.expected.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,94 +82,88 @@ pub mod padding {
data.build()
}
}
pub mod bind_groups {
use super::{_root, _root::*};
#[derive(Debug)]
pub struct WgpuBindGroup0EntriesParams<'a> {
pub frame: wgpu::BufferBinding<'a>,
#[derive(Debug)]
pub struct WgpuBindGroup0EntriesParams<'a> {
pub frame: wgpu::BufferBinding<'a>,
}
#[derive(Clone, Debug)]
pub struct WgpuBindGroup0Entries<'a> {
pub frame: wgpu::BindGroupEntry<'a>,
}
impl<'a> WgpuBindGroup0Entries<'a> {
pub fn new(params: WgpuBindGroup0EntriesParams<'a>) -> Self {
Self {
frame: wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(params.frame),
},
}
}
#[derive(Clone, Debug)]
pub struct WgpuBindGroup0Entries<'a> {
pub frame: wgpu::BindGroupEntry<'a>,
pub fn as_array(self) -> [wgpu::BindGroupEntry<'a>; 1] {
[self.frame]
}
impl<'a> WgpuBindGroup0Entries<'a> {
pub fn new(params: WgpuBindGroup0EntriesParams<'a>) -> Self {
Self {
frame: wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(params.frame),
},
}
}
pub fn as_array(self) -> [wgpu::BindGroupEntry<'a>; 1] {
[self.frame]
}
pub fn collect<B: FromIterator<wgpu::BindGroupEntry<'a>>>(self) -> B {
self.as_array().into_iter().collect()
}
pub fn collect<B: FromIterator<wgpu::BindGroupEntry<'a>>>(self) -> B {
self.as_array().into_iter().collect()
}
#[derive(Debug)]
pub struct WgpuBindGroup0(wgpu::BindGroup);
impl WgpuBindGroup0 {
pub const LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor<'static> = wgpu::BindGroupLayoutDescriptor {
label: Some("Padding::BindGroup0::LayoutDescriptor"),
entries: &[
/// @binding(0): "frame"
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage {
read_only: true,
},
has_dynamic_offset: false,
min_binding_size: std::num::NonZeroU64::new(
std::mem::size_of::<_root::padding::Style>() as _,
),
}
#[derive(Debug)]
pub struct WgpuBindGroup0(wgpu::BindGroup);
impl WgpuBindGroup0 {
pub const LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor<'static> = wgpu::BindGroupLayoutDescriptor {
label: Some("Padding::BindGroup0::LayoutDescriptor"),
entries: &[
/// @binding(0): "frame"
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage {
read_only: true,
},
count: None,
has_dynamic_offset: false,
min_binding_size: std::num::NonZeroU64::new(
std::mem::size_of::<_root::padding::Style>() as _,
),
},
],
};
pub fn get_bind_group_layout(
device: &wgpu::Device,
) -> wgpu::BindGroupLayout {
device.create_bind_group_layout(&Self::LAYOUT_DESCRIPTOR)
}
pub fn from_bindings(
device: &wgpu::Device,
bindings: WgpuBindGroup0Entries,
) -> Self {
let bind_group_layout = Self::get_bind_group_layout(&device);
let entries = bindings.as_array();
let bind_group = device
.create_bind_group(
&wgpu::BindGroupDescriptor {
label: Some("Padding::BindGroup0"),
layout: &bind_group_layout,
entries: &entries,
},
);
Self(bind_group)
}
pub fn set<'a>(&'a self, render_pass: &mut wgpu::ComputePass<'a>) {
render_pass.set_bind_group(0, &self.0, &[]);
}
count: None,
},
],
};
pub fn get_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
device.create_bind_group_layout(&Self::LAYOUT_DESCRIPTOR)
}
#[derive(Debug, Copy, Clone)]
pub struct WgpuBindGroups<'a> {
pub bind_group0: &'a WgpuBindGroup0,
pub fn from_bindings(
device: &wgpu::Device,
bindings: WgpuBindGroup0Entries,
) -> Self {
let bind_group_layout = Self::get_bind_group_layout(&device);
let entries = bindings.as_array();
let bind_group = device
.create_bind_group(
&wgpu::BindGroupDescriptor {
label: Some("Padding::BindGroup0"),
layout: &bind_group_layout,
entries: &entries,
},
);
Self(bind_group)
}
impl<'a> WgpuBindGroups<'a> {
pub fn set(&self, pass: &mut wgpu::ComputePass<'a>) {
self.bind_group0.set(pass);
}
pub fn set<'a>(&'a self, render_pass: &mut wgpu::ComputePass<'a>) {
render_pass.set_bind_group(0, &self.0, &[]);
}
}
#[derive(Debug, Copy, Clone)]
pub struct WgpuBindGroups<'a> {
pub bind_group0: &'a WgpuBindGroup0,
}
impl<'a> WgpuBindGroups<'a> {
pub fn set(&self, pass: &mut wgpu::ComputePass<'a>) {
self.bind_group0.set(pass);
}
}
pub use self::bind_groups::*;
pub fn set_bind_groups<'a>(
pass: &mut wgpu::ComputePass<'a>,
bind_group0: &'a bind_groups::WgpuBindGroup0,
bind_group0: &'a WgpuBindGroup0,
) {
bind_group0.set(pass);
}
Expand Down Expand Up @@ -208,7 +202,7 @@ pub mod padding {
&wgpu::PipelineLayoutDescriptor {
label: Some("Padding::PipelineLayout"),
bind_group_layouts: &[
&bind_groups::WgpuBindGroup0::get_bind_group_layout(device),
&WgpuBindGroup0::get_bind_group_layout(device),
],
push_constant_ranges: &[],
},
Expand Down

0 comments on commit 719a7cd

Please sign in to comment.