[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:
Dzmitry Malyshau
2020-08-21 00:58:30 -04:00
parent 945a85f1c0
commit 82866bac4a
11 changed files with 116 additions and 100 deletions

View File

@@ -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: | | | | | | | |

View File

@@ -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,

View File

@@ -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,

View File

@@ -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(),
}],
});

View File

@@ -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,

View File

@@ -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);

View File

@@ -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,

View File

@@ -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"),
});

View File

@@ -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) => {

View File

@@ -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())

View File

@@ -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 {