mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[rs] Change buffer binding to not take a slice.
Also switch the shadow example to use dynamic offsets. Add the relevant feature to our example table.
This commit is contained in:
@@ -15,6 +15,7 @@ All framework-based examples render to the window.
|
||||
| vertex attributes | :star: | :star: | :star: | :star: | :star: | | :star: | :star: |
|
||||
| instancing | :star: | | | | | | | |
|
||||
| lines and points | | | | :star: | | | | |
|
||||
| dynamic buffer offsets | | | | | :star: | | | |
|
||||
| implicit layout | | | | | | | | |
|
||||
| sampled color textures | :star: | :star: | :star: | | | :star: | :star: | :star: |
|
||||
| storage textures | :star: | | | | | | | |
|
||||
|
||||
@@ -205,17 +205,15 @@ impl framework::Example for Example {
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(sim_param_buffer.slice(..)),
|
||||
resource: sim_param_buffer.as_entire_binding(),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Buffer(particle_buffers[i].slice(..)),
|
||||
resource: particle_buffers[i].as_entire_binding(),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 2,
|
||||
resource: wgpu::BindingResource::Buffer(
|
||||
particle_buffers[(i + 1) % 2].slice(..), // bind to opposite buffer
|
||||
),
|
||||
resource: particle_buffers[(i + 1) % 2].as_entire_binding(), // bind to opposite buffer
|
||||
},
|
||||
],
|
||||
label: None,
|
||||
|
||||
@@ -230,7 +230,7 @@ impl framework::Example for Example {
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(uniform_buf.slice(..)),
|
||||
resource: uniform_buf.as_entire_binding(),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
|
||||
@@ -80,7 +80,7 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
|
||||
layout: &bind_group_layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(storage_buffer.slice(..)),
|
||||
resource: storage_buffer.as_entire_binding(),
|
||||
}],
|
||||
});
|
||||
|
||||
|
||||
@@ -327,7 +327,7 @@ impl framework::Example for Example {
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(uniform_buf.slice(..)),
|
||||
resource: uniform_buf.as_entire_binding(),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
|
||||
@@ -90,8 +90,7 @@ struct Entity {
|
||||
vertex_buf: Rc<wgpu::Buffer>,
|
||||
index_buf: Rc<wgpu::Buffer>,
|
||||
index_count: usize,
|
||||
bind_group: wgpu::BindGroup,
|
||||
uniform_buf: wgpu::Buffer,
|
||||
uniform_offset: wgpu::DynamicOffset,
|
||||
}
|
||||
|
||||
struct Light {
|
||||
@@ -178,7 +177,9 @@ struct Example {
|
||||
shadow_pass: Pass,
|
||||
forward_pass: Pass,
|
||||
forward_depth: wgpu::TextureView,
|
||||
entity_bind_group: wgpu::BindGroup,
|
||||
light_uniform_buf: wgpu::Buffer,
|
||||
entity_uniform_buf: wgpu::Buffer,
|
||||
}
|
||||
|
||||
impl Example {
|
||||
@@ -245,53 +246,6 @@ impl framework::Example for Example {
|
||||
usage: wgpu::BufferUsage::INDEX,
|
||||
});
|
||||
|
||||
let entity_uniform_size = mem::size_of::<EntityUniforms>() as wgpu::BufferAddress;
|
||||
let plane_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: entity_uniform_size,
|
||||
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let local_bind_group_layout =
|
||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::UniformBuffer {
|
||||
dynamic: false,
|
||||
min_binding_size: wgpu::BufferSize::new(
|
||||
mem::size_of::<EntityUniforms>() as _
|
||||
),
|
||||
},
|
||||
count: None,
|
||||
}],
|
||||
label: None,
|
||||
});
|
||||
|
||||
let mut entities = vec![{
|
||||
use cgmath::SquareMatrix;
|
||||
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &local_bind_group_layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(plane_uniform_buf.slice(..)),
|
||||
}],
|
||||
label: None,
|
||||
});
|
||||
Entity {
|
||||
mx_world: cgmath::Matrix4::identity(),
|
||||
rotation_speed: 0.0,
|
||||
color: wgpu::Color::WHITE,
|
||||
vertex_buf: Rc::new(plane_vertex_buf),
|
||||
index_buf: Rc::new(plane_index_buf),
|
||||
index_count: plane_index_data.len(),
|
||||
bind_group,
|
||||
uniform_buf: plane_uniform_buf,
|
||||
}
|
||||
}];
|
||||
|
||||
struct CubeDesc {
|
||||
offset: cgmath::Vector3<f32>,
|
||||
angle: f32,
|
||||
@@ -325,7 +279,31 @@ impl framework::Example for Example {
|
||||
},
|
||||
];
|
||||
|
||||
for cube in &cube_descs {
|
||||
let entity_uniform_size = mem::size_of::<EntityUniforms>() as wgpu::BufferAddress;
|
||||
let num_entities = 1 + cube_descs.len() as wgpu::BufferAddress;
|
||||
assert!(entity_uniform_size <= wgpu::BIND_BUFFER_ALIGNMENT);
|
||||
//Note: dynamic offsets also have to be aligned to `BIND_BUFFER_ALIGNMENT`.
|
||||
let entity_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: num_entities * wgpu::BIND_BUFFER_ALIGNMENT,
|
||||
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let mut entities = vec![{
|
||||
use cgmath::SquareMatrix;
|
||||
Entity {
|
||||
mx_world: cgmath::Matrix4::identity(),
|
||||
rotation_speed: 0.0,
|
||||
color: wgpu::Color::WHITE,
|
||||
vertex_buf: Rc::new(plane_vertex_buf),
|
||||
index_buf: Rc::new(plane_index_buf),
|
||||
index_count: plane_index_data.len(),
|
||||
uniform_offset: 0,
|
||||
}
|
||||
}];
|
||||
|
||||
for (i, cube) in cube_descs.iter().enumerate() {
|
||||
use cgmath::{Decomposed, Deg, InnerSpace, Quaternion, Rotation3};
|
||||
|
||||
let transform = Decomposed {
|
||||
@@ -333,12 +311,6 @@ impl framework::Example for Example {
|
||||
rot: Quaternion::from_axis_angle(cube.offset.normalize(), Deg(cube.angle)),
|
||||
scale: cube.scale,
|
||||
};
|
||||
let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: entity_uniform_size,
|
||||
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
entities.push(Entity {
|
||||
mx_world: cgmath::Matrix4::from(transform),
|
||||
rotation_speed: cube.rotation,
|
||||
@@ -346,18 +318,36 @@ impl framework::Example for Example {
|
||||
vertex_buf: Rc::clone(&cube_vertex_buf),
|
||||
index_buf: Rc::clone(&cube_index_buf),
|
||||
index_count: cube_index_data.len(),
|
||||
bind_group: device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &local_bind_group_layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(uniform_buf.slice(..)),
|
||||
}],
|
||||
label: None,
|
||||
}),
|
||||
uniform_buf,
|
||||
uniform_offset: ((i + 1) * wgpu::BIND_BUFFER_ALIGNMENT as usize) as _,
|
||||
});
|
||||
}
|
||||
|
||||
let local_bind_group_layout =
|
||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::UniformBuffer {
|
||||
dynamic: true,
|
||||
min_binding_size: wgpu::BufferSize::new(entity_uniform_size),
|
||||
},
|
||||
count: None,
|
||||
}],
|
||||
label: None,
|
||||
});
|
||||
let entity_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &local_bind_group_layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer {
|
||||
buffer: &entity_uniform_buf,
|
||||
offset: 0,
|
||||
size: wgpu::BufferSize::new(entity_uniform_size),
|
||||
},
|
||||
}],
|
||||
label: None,
|
||||
});
|
||||
|
||||
// Create other resources
|
||||
let shadow_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||
label: Some("shadow"),
|
||||
@@ -474,7 +464,7 @@ impl framework::Example for Example {
|
||||
layout: &bind_group_layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(uniform_buf.slice(..)),
|
||||
resource: uniform_buf.as_entire_binding(),
|
||||
}],
|
||||
label: None,
|
||||
});
|
||||
@@ -595,11 +585,11 @@ impl framework::Example for Example {
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(uniform_buf.slice(..)),
|
||||
resource: uniform_buf.as_entire_binding(),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Buffer(light_uniform_buf.slice(..)),
|
||||
resource: light_uniform_buf.as_entire_binding(),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 2,
|
||||
@@ -679,6 +669,8 @@ impl framework::Example for Example {
|
||||
forward_pass,
|
||||
forward_depth: depth_texture.create_view(&wgpu::TextureViewDescriptor::default()),
|
||||
light_uniform_buf,
|
||||
entity_uniform_buf,
|
||||
entity_bind_group,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -739,7 +731,11 @@ impl framework::Example for Example {
|
||||
entity.color.a as f32,
|
||||
],
|
||||
};
|
||||
queue.write_buffer(&entity.uniform_buf, 0, bytemuck::bytes_of(&data));
|
||||
queue.write_buffer(
|
||||
&self.entity_uniform_buf,
|
||||
entity.uniform_offset as wgpu::BufferAddress,
|
||||
bytemuck::bytes_of(&data),
|
||||
);
|
||||
}
|
||||
|
||||
if self.lights_are_dirty {
|
||||
@@ -782,7 +778,7 @@ impl framework::Example for Example {
|
||||
pass.set_bind_group(0, &self.shadow_pass.bind_group, &[]);
|
||||
|
||||
for entity in &self.entities {
|
||||
pass.set_bind_group(1, &entity.bind_group, &[]);
|
||||
pass.set_bind_group(1, &self.entity_bind_group, &[entity.uniform_offset]);
|
||||
pass.set_index_buffer(entity.index_buf.slice(..));
|
||||
pass.set_vertex_buffer(0, entity.vertex_buf.slice(..));
|
||||
pass.draw_indexed(0..entity.index_count as u32, 0, 0..1);
|
||||
@@ -818,7 +814,7 @@ impl framework::Example for Example {
|
||||
pass.set_bind_group(0, &self.forward_pass.bind_group, &[]);
|
||||
|
||||
for entity in &self.entities {
|
||||
pass.set_bind_group(1, &entity.bind_group, &[]);
|
||||
pass.set_bind_group(1, &self.entity_bind_group, &[entity.uniform_offset]);
|
||||
pass.set_index_buffer(entity.index_buf.slice(..));
|
||||
pass.set_vertex_buffer(0, entity.vertex_buf.slice(..));
|
||||
pass.draw_indexed(0..entity.index_count as u32, 0, 0..1);
|
||||
|
||||
@@ -257,7 +257,7 @@ impl framework::Example for Skybox {
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(uniform_buf.slice(..)),
|
||||
resource: uniform_buf.as_entire_binding(),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
|
||||
@@ -237,7 +237,7 @@ impl Example {
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(water_uniforms.slice(..)),
|
||||
resource: water_uniforms.as_entire_binding(),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
@@ -471,7 +471,7 @@ impl framework::Example for Example {
|
||||
layout: &terrain_bind_group_layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(terrain_normal_uniform_buf.slice(..)),
|
||||
resource: terrain_normal_uniform_buf.as_entire_binding(),
|
||||
}],
|
||||
label: Some("Terrain Normal Bind Group"),
|
||||
});
|
||||
@@ -479,7 +479,7 @@ impl framework::Example for Example {
|
||||
layout: &terrain_bind_group_layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(terrain_flipped_uniform_buf.slice(..)),
|
||||
resource: terrain_flipped_uniform_buf.as_entire_binding(),
|
||||
}],
|
||||
label: Some("Terrain Flipped Bind Group"),
|
||||
});
|
||||
|
||||
@@ -633,17 +633,17 @@ impl crate::Context for Context {
|
||||
.map(|entry| bm::BindGroupEntry {
|
||||
binding: entry.binding,
|
||||
resource: match entry.resource {
|
||||
BindingResource::Buffer(ref buffer_slice) => {
|
||||
bm::BindingResource::Buffer(bm::BufferBinding {
|
||||
buffer_id: buffer_slice.buffer.id,
|
||||
offset: buffer_slice.offset,
|
||||
size: buffer_slice.size,
|
||||
})
|
||||
}
|
||||
BindingResource::Sampler(ref sampler) => {
|
||||
bm::BindingResource::Sampler(sampler.id)
|
||||
}
|
||||
BindingResource::TextureView(ref texture_view) => {
|
||||
BindingResource::Buffer {
|
||||
buffer,
|
||||
offset,
|
||||
size,
|
||||
} => bm::BindingResource::Buffer(bm::BufferBinding {
|
||||
buffer_id: buffer.id,
|
||||
offset,
|
||||
size,
|
||||
}),
|
||||
BindingResource::Sampler(sampler) => bm::BindingResource::Sampler(sampler.id),
|
||||
BindingResource::TextureView(texture_view) => {
|
||||
bm::BindingResource::TextureView(texture_view.id)
|
||||
}
|
||||
BindingResource::TextureViewArray(texture_view_array) => {
|
||||
|
||||
@@ -922,12 +922,16 @@ impl crate::Context for Context {
|
||||
.entries
|
||||
.iter()
|
||||
.map(|binding| {
|
||||
let mapped_resource = match &binding.resource {
|
||||
BindingResource::Buffer(buffer_slice) => {
|
||||
let mapped_resource = match binding.resource {
|
||||
BindingResource::Buffer {
|
||||
ref buffer,
|
||||
offset,
|
||||
size,
|
||||
} => {
|
||||
let mut mapped_buffer_binding =
|
||||
web_sys::GpuBufferBinding::new(&buffer_slice.buffer.id.0);
|
||||
mapped_buffer_binding.offset(buffer_slice.offset as f64);
|
||||
if let Some(s) = buffer_slice.size {
|
||||
web_sys::GpuBufferBinding::new(&buffer.id.0);
|
||||
mapped_buffer_binding.offset(offset as f64);
|
||||
if let Some(s) = size {
|
||||
mapped_buffer_binding.size(s.get() as f64);
|
||||
}
|
||||
JsValue::from(mapped_buffer_binding.clone())
|
||||
|
||||
@@ -842,7 +842,15 @@ pub enum BindingResource<'a> {
|
||||
///
|
||||
/// Corresponds to [`BindingType::UniformBuffer`] and [`BindingType::StorageBuffer`]
|
||||
/// with [`BindGroupLayoutEntry::count`] set to None.
|
||||
Buffer(BufferSlice<'a>),
|
||||
Buffer {
|
||||
/// The buffer to bind.
|
||||
buffer: &'a Buffer,
|
||||
/// Base offset of the buffer. For bindings with `dynamic == true`, this offset
|
||||
/// will be added to the dynamic offset provided in [`RenderPass::set_bind_group`].
|
||||
offset: BufferAddress,
|
||||
/// Size of the binding, or `None` for using the rest of the buffer.
|
||||
size: Option<BufferSize>,
|
||||
},
|
||||
/// Binding is a sampler.
|
||||
///
|
||||
/// Corresponds to [`BindingType::Sampler`] with [`BindGroupLayoutEntry::count`] set to None.
|
||||
@@ -1646,6 +1654,15 @@ impl Drop for BufferViewMut<'_> {
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
/// Return the binding view of the entire buffer.
|
||||
pub fn as_entire_binding(&self) -> BindingResource {
|
||||
BindingResource::Buffer {
|
||||
buffer: self,
|
||||
offset: 0,
|
||||
size: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Use only a portion of this Buffer for a given operation. Choosing a range with no end
|
||||
/// will use the rest of the buffer. Using a totally unbounded range will use the entire buffer.
|
||||
pub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferSlice {
|
||||
|
||||
Reference in New Issue
Block a user