pub(super) fn create_quad_bind_group_layout(
device: &wgpu::Device,
label: &str,
) -> wgpu::BindGroupLayout {
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some(label),
entries: &[
storage_layout_entry(0, true),
storage_layout_entry(1, true),
storage_layout_entry(2, false),
uniform_layout_entry(3),
],
})
}
const fn storage_layout_entry(binding: u32, read_only: bool) -> wgpu::BindGroupLayoutEntry {
wgpu::BindGroupLayoutEntry {
binding,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}
}
const fn uniform_layout_entry(binding: u32) -> wgpu::BindGroupLayoutEntry {
wgpu::BindGroupLayoutEntry {
binding,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}
}
pub(super) fn readback_buffer<T: bytemuck::Pod>(
device: &wgpu::Device,
staging_buffer: &wgpu::Buffer,
count: usize,
) -> Option<Vec<T>> {
let buffer_slice = staging_buffer.slice(..);
let (tx, rx) = std::sync::mpsc::channel();
buffer_slice.map_async(wgpu::MapMode::Read, move |result| {
let _ = tx.send(result);
});
device.poll(wgpu::Maintain::Wait);
rx.recv().ok().and_then(Result::ok)?;
let data = buffer_slice.get_mapped_range();
let typed: &[T] = bytemuck::cast_slice(&data);
let result = typed[..count].to_vec();
drop(data);
staging_buffer.unmap();
Some(result)
}
pub(super) fn flatten_vecs(vecs: &[Vec<f32>], expected_dim: usize) -> Vec<f32> {
let mut flat = Vec::with_capacity(vecs.len() * expected_dim);
for v in vecs {
flat.extend_from_slice(v);
}
flat
}