482: Add label parameter to `create_buffer_with_data` r=kvark a=OptimisticPeach

Improves QOL by allowing you to attach a label to a buffer when created with predetermined data:
```
let uniform_buf = device.create_buffer_with_data(
    bytemuck::cast_slice(my_data),
    wgpu::BufferUsage::UNIFORM,
    Some(Cow::Borrowed("My Uniforms")),
);
```

Co-authored-by: OptimisticPeach <patrikbuhring@yahoo.com>
This commit is contained in:
bors[bot]
2020-07-30 02:08:24 +00:00
committed by GitHub
14 changed files with 217 additions and 101 deletions

View File

@@ -2,6 +2,7 @@
// adapted from https://github.com/austinEng/webgpu-samples/blob/master/src/examples/computeBoids.ts
use std::borrow::Cow::Borrowed;
use wgpu::util::DeviceExt;
#[path = "../framework.rs"]
mod framework;
@@ -50,9 +51,12 @@ impl framework::Example for Example {
0.005, // rule3Scale
]
.to_vec();
let sim_param_buffer = device.create_buffer_with_data(
bytemuck::cast_slice(&sim_param_data),
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
let sim_param_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Simulation Parameter Buffer"),
contents: bytemuck::cast_slice(&sim_param_data),
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
}
);
// create compute bind layout group and compute pipeline layout
@@ -159,9 +163,12 @@ impl framework::Example for Example {
// buffer for the three 2d triangle vertices of each instance
let vertex_buffer_data = [-0.01f32, -0.02, 0.01, -0.02, 0.00, 0.02];
let vertices_buffer = device.create_buffer_with_data(
bytemuck::bytes_of(&vertex_buffer_data),
wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST,
let vertices_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: bytemuck::bytes_of(&vertex_buffer_data),
usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST,
}
);
// buffer for all particles data of type [(posx,posy,velx,vely),...]
@@ -180,12 +187,15 @@ impl framework::Example for Example {
let mut particle_buffers = Vec::<wgpu::Buffer>::new();
let mut particle_bind_groups = Vec::<wgpu::BindGroup>::new();
for _i in 0..2 {
particle_buffers.push(device.create_buffer_with_data(
bytemuck::cast_slice(&initial_particle_data),
wgpu::BufferUsage::VERTEX
| wgpu::BufferUsage::STORAGE
| wgpu::BufferUsage::COPY_DST,
for i in 0..2 {
particle_buffers.push(device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some(&format!("Particle Buffer {}", i)),
contents: bytemuck::cast_slice(&initial_particle_data),
usage: wgpu::BufferUsage::VERTEX
| wgpu::BufferUsage::STORAGE
| wgpu::BufferUsage::COPY_DST,
}
));
}

View File

@@ -3,6 +3,7 @@ mod framework;
use bytemuck::{Pod, Zeroable};
use std::borrow::Cow::Borrowed;
use wgpu::util::DeviceExt;
#[repr(C)]
#[derive(Clone, Copy)]
@@ -124,13 +125,21 @@ impl framework::Example for Example {
let vertex_size = mem::size_of::<Vertex>();
let (vertex_data, index_data) = create_vertices();
let vertex_buf = device.create_buffer_with_data(
bytemuck::cast_slice(&vertex_data),
wgpu::BufferUsage::VERTEX,
let vertex_buf = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(&vertex_data),
usage: wgpu::BufferUsage::VERTEX,
}
);
let index_buf = device
.create_buffer_with_data(bytemuck::cast_slice(&index_data), wgpu::BufferUsage::INDEX);
let index_buf = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Index Buffer"),
contents: bytemuck::cast_slice(&index_data),
usage: wgpu::BufferUsage::INDEX,
}
);
// Create pipeline layout
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@@ -210,9 +219,12 @@ impl framework::Example for Example {
});
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
let mx_ref: &[f32; 16] = mx_total.as_ref();
let uniform_buf = device.create_buffer_with_data(
bytemuck::cast_slice(mx_ref),
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
let uniform_buf = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Uniform Buffer"),
contents: bytemuck::cast_slice(mx_ref),
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
}
);
// Create bind group

View File

@@ -1,4 +1,5 @@
use std::{borrow::Cow::Borrowed, convert::TryInto, str::FromStr};
use wgpu::util::DeviceExt;
async fn run() {
let numbers = if std::env::args().len() <= 1 {
@@ -52,9 +53,12 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
mapped_at_creation: false,
});
let storage_buffer = device.create_buffer_with_data(
bytemuck::cast_slice(&numbers),
wgpu::BufferUsage::STORAGE | wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::COPY_SRC,
let storage_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Storage Buffer"),
contents: bytemuck::cast_slice(&numbers),
usage: wgpu::BufferUsage::STORAGE | wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::COPY_SRC,
}
);
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {

View File

@@ -3,6 +3,7 @@ mod framework;
use bytemuck::{Pod, Zeroable};
use std::{borrow::Cow::Borrowed, num::NonZeroU32};
use wgpu::util::DeviceExt;
const TEXTURE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8UnormSrgb;
@@ -214,9 +215,12 @@ impl framework::Example for Example {
// Create the vertex and index buffers
let vertex_size = mem::size_of::<Vertex>();
let vertex_data = create_vertices();
let vertex_buf = device.create_buffer_with_data(
bytemuck::cast_slice(&vertex_data),
wgpu::BufferUsage::VERTEX,
let vertex_buf = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(&vertex_data),
usage: wgpu::BufferUsage::VERTEX,
}
);
// Create pipeline layout
@@ -275,8 +279,13 @@ impl framework::Example for Example {
let texture_view = texture.create_default_view();
//Note: we could use queue.write_texture instead, and this is what other
// examples do, but here we want to show another way to do this.
let temp_buf =
device.create_buffer_with_data(texels.as_slice(), wgpu::BufferUsage::COPY_SRC);
let temp_buf = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Temporary Buffer"),
contents: texels.as_slice(),
usage: wgpu::BufferUsage::COPY_SRC,
}
);
init_encoder.copy_buffer_to_texture(
wgpu::BufferCopyView {
buffer: &temp_buf,
@@ -307,9 +316,12 @@ impl framework::Example for Example {
});
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
let mx_ref: &[f32; 16] = mx_total.as_ref();
let uniform_buf = device.create_buffer_with_data(
bytemuck::cast_slice(mx_ref),
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
let uniform_buf = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Uniform Buffer"),
contents: bytemuck::cast_slice(mx_ref),
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
}
);
// Create bind group

View File

@@ -13,6 +13,7 @@ mod framework;
use std::{borrow::Cow::Borrowed, iter};
use bytemuck::{Pod, Zeroable};
use wgpu::util::DeviceExt;
#[repr(C)]
#[derive(Clone, Copy)]
@@ -161,9 +162,12 @@ impl framework::Example for Example {
});
}
let vertex_buffer = device.create_buffer_with_data(
bytemuck::cast_slice(&vertex_data),
wgpu::BufferUsage::VERTEX,
let vertex_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(&vertex_data),
usage: wgpu::BufferUsage::VERTEX,
}
);
let vertex_count = vertex_data.len() as u32;

View File

@@ -4,6 +4,7 @@ use std::{borrow::Cow::Borrowed, iter, mem, num::NonZeroU32, ops::Range, rc::Rc}
mod framework;
use bytemuck::{Pod, Zeroable};
use wgpu::util::DeviceExt;
#[repr(C)]
#[derive(Clone, Copy)]
@@ -215,25 +216,37 @@ impl framework::Example for Example {
// Create the vertex and index buffers
let vertex_size = mem::size_of::<Vertex>();
let (cube_vertex_data, cube_index_data) = create_cube();
let cube_vertex_buf = Rc::new(device.create_buffer_with_data(
bytemuck::cast_slice(&cube_vertex_data),
wgpu::BufferUsage::VERTEX,
let cube_vertex_buf = Rc::new(device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Cubes Vertex Buffer"),
contents: bytemuck::cast_slice(&cube_vertex_data),
usage: wgpu::BufferUsage::VERTEX,
}
));
let cube_index_buf = Rc::new(device.create_buffer_with_data(
bytemuck::cast_slice(&cube_index_data),
wgpu::BufferUsage::INDEX,
let cube_index_buf = Rc::new(device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Cubes Index Buffer"),
contents: bytemuck::cast_slice(&cube_index_data),
usage: wgpu::BufferUsage::INDEX,
}
));
let (plane_vertex_data, plane_index_data) = create_plane(7);
let plane_vertex_buf = device.create_buffer_with_data(
bytemuck::cast_slice(&plane_vertex_data),
wgpu::BufferUsage::VERTEX,
let plane_vertex_buf = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Plane Vertex Buffer"),
contents: bytemuck::cast_slice(&plane_vertex_data),
usage: wgpu::BufferUsage::VERTEX,
}
);
let plane_index_buf = device.create_buffer_with_data(
bytemuck::cast_slice(&plane_index_data),
wgpu::BufferUsage::INDEX,
let plane_index_buf = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Plane Index Buffer"),
contents: bytemuck::cast_slice(&plane_index_data),
usage: wgpu::BufferUsage::INDEX,
}
);
let entity_uniform_size = mem::size_of::<EntityUniforms>() as wgpu::BufferAddress;
@@ -568,9 +581,12 @@ impl framework::Example for Example {
proj: *mx_total.as_ref(),
num_lights: [lights.len() as u32, 0, 0, 0],
};
let uniform_buf = device.create_buffer_with_data(
bytemuck::bytes_of(&forward_uniforms),
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
let uniform_buf = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Uniform Buffer"),
contents: bytemuck::bytes_of( &forward_uniforms),
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
}
);
// Create bind group

View File

@@ -3,6 +3,7 @@ mod framework;
use futures::task::{LocalSpawn, LocalSpawnExt};
use std::borrow::Cow::Borrowed;
use wgpu::util::DeviceExt;
const SKYBOX_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8Unorm;
@@ -78,9 +79,12 @@ impl framework::Example for Skybox {
let aspect = sc_desc.width as f32 / sc_desc.height as f32;
let uniforms = Self::generate_uniforms(aspect);
let uniform_buf = device.create_buffer_with_data(
bytemuck::cast_slice(&raw_uniforms(&uniforms)),
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
let uniform_buf = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Uniform Buffer"),
contents: bytemuck::cast_slice(&raw_uniforms(&uniforms)),
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
}
);
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {

View File

@@ -3,6 +3,7 @@ mod framework;
use bytemuck::{Pod, Zeroable};
use std::borrow::Cow::Borrowed;
use wgpu::util::DeviceExt;
#[repr(C)]
#[derive(Clone, Copy)]
@@ -122,14 +123,22 @@ impl framework::Example for Example {
let vertex_size = std::mem::size_of::<Vertex>();
let vertex_data = create_vertices();
let vertex_buffer = device.create_buffer_with_data(
bytemuck::cast_slice(&vertex_data),
wgpu::BufferUsage::VERTEX,
let vertex_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(&vertex_data),
usage: wgpu::BufferUsage::VERTEX,
}
);
let index_data = create_indices();
let index_buffer = device
.create_buffer_with_data(bytemuck::cast_slice(&index_data), wgpu::BufferUsage::INDEX);
let index_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Index Buffer"),
contents: bytemuck::cast_slice(&index_data),
usage: wgpu::BufferUsage::INDEX,
}
);
let red_texture_data = create_texture_data(Color::RED);
let green_texture_data = create_texture_data(Color::GREEN);

View File

@@ -5,6 +5,7 @@ mod point_gen;
use cgmath::Point3;
use std::{borrow::Cow::Borrowed, iter, mem};
use wgpu::util::DeviceExt;
///
/// Radius of the terrain.
@@ -337,14 +338,20 @@ impl framework::Example for Example {
let terrain_vertices = terrain.make_buffer_data();
// Create the buffers on the GPU to hold the data.
let water_vertex_buf = device.create_buffer_with_data(
bytemuck::cast_slice(&water_vertices),
wgpu::BufferUsage::VERTEX,
let water_vertex_buf = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Water vertices"),
contents: bytemuck::cast_slice(&water_vertices),
usage: wgpu::BufferUsage::VERTEX,
}
);
let terrain_vertex_buf = device.create_buffer_with_data(
bytemuck::cast_slice(&terrain_vertices),
wgpu::BufferUsage::VERTEX,
let terrain_vertex_buf = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Terrain vertices"),
contents: bytemuck::cast_slice(&terrain_vertices),
usage: wgpu::BufferUsage::VERTEX,
}
);
// Create the bind group layout. This is what our uniforms will look like.

View File

@@ -1,15 +1,23 @@
use crate::{
backend::native_gpu_future, BindGroupDescriptor, BindGroupLayoutDescriptor,
BindingResource, BufferDescriptor, CommandEncoderDescriptor, ComputePipelineDescriptor,
Features, Limits, LoadOp, MapMode, Operations, PipelineLayoutDescriptor,
RenderPipelineDescriptor, SamplerDescriptor, ShaderModuleSource, SwapChainStatus,
TextureDescriptor, TextureViewDescriptor,
backend::native_gpu_future, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource,
CommandEncoderDescriptor, ComputePipelineDescriptor, Features, Limits, LoadOp, MapMode,
Operations, PipelineLayoutDescriptor, RenderPipelineDescriptor, SamplerDescriptor,
ShaderModuleSource, SwapChainStatus, TextureDescriptor, TextureViewDescriptor,
};
use arrayvec::ArrayVec;
use futures::future::{ready, Ready};
use smallvec::SmallVec;
use std::{borrow::Cow::Borrowed, error::Error, ffi::CString, fmt, marker::PhantomData, ops::Range, ptr, slice};
use std::{
borrow::Cow::{self, Borrowed},
ffi::CString,
fmt,
marker::PhantomData,
ops::Range,
ptr,
slice,
error::Error
};
use typed_arena::Arena;
pub struct Context(wgc::hub::Global<wgc::hub::IdentityManagerFactory>);
@@ -769,7 +777,7 @@ impl crate::Context for Context {
fn device_create_buffer(
&self,
device: &Self::DeviceId,
desc: &BufferDescriptor,
desc: &wgt::BufferDescriptor<Option<Cow<'_, str>>>,
) -> Self::BufferId {
let owned_label = OwnedLabel::new(desc.label.as_deref());

View File

@@ -1,5 +1,5 @@
use crate::{
BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource, BindingType, BufferDescriptor,
BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource, BindingType,
CommandEncoderDescriptor, ComputePipelineDescriptor, LoadOp, PipelineLayoutDescriptor,
ProgrammableStageDescriptor, RenderPipelineDescriptor, SamplerDescriptor, ShaderModuleSource,
SwapChainStatus, TextureDescriptor, TextureViewDescriptor, TextureViewDimension,
@@ -7,6 +7,7 @@ use crate::{
use futures::FutureExt;
use std::{
borrow::Cow,
fmt,
future::Future,
marker::PhantomData,
@@ -1048,7 +1049,7 @@ impl crate::Context for Context {
fn device_create_buffer(
&self,
device: &Self::DeviceId,
desc: &BufferDescriptor,
desc: &wgt::BufferDescriptor<Option<Cow<'_, str>>>,
) -> Self::BufferId {
let mut mapped_desc =
web_sys::GpuBufferDescriptor::new(desc.size as f64, desc.usage.bits());

View File

@@ -1241,32 +1241,6 @@ impl Device {
}
}
/// Creates a new buffer, maps it into host-visible memory, copies data from the given slice,
/// and finally unmaps it, returning a [`Buffer`].
pub fn create_buffer_with_data(&self, data: &[u8], usage: BufferUsage) -> Buffer {
let align = COPY_BUFFER_ALIGNMENT;
let unpadded_size = data.len() as u64;
let padding = (align - unpadded_size % align) % align;
let padded_size = unpadded_size + padding;
let buffer = self.create_buffer(&BufferDescriptor {
label: None,
size: padded_size,
usage,
mapped_at_creation: true,
});
let range =
Context::buffer_get_mapped_range_mut(&*self.context, &buffer.id, 0..padded_size);
range[0..unpadded_size as usize].copy_from_slice(&data);
for i in unpadded_size..padded_size {
range[i as usize] = 0;
}
buffer.unmap();
buffer
}
/// Creates a new [`Texture`].
///
/// `desc` specifies the general format of the texture.

View File

@@ -122,13 +122,13 @@ impl StagingBelt {
&mut self.encoder,
device.create_command_encoder(&CommandEncoderDescriptor::default()),
)
.finish()
.finish()
}
/// Recall all of the closed buffers back for re-usal.
///
/// This has to be called after the command buffer produced by `flush` is submitted!
pub fn recall(&mut self) -> impl Future<Output = ()> + Send {
pub fn recall(&mut self) -> impl Future<Output=()> + Send {
while let Ok(mut chunk) = self.receiver.try_recv() {
chunk.offset = 0;
self.free_chunks.push(chunk);
@@ -143,6 +143,6 @@ impl StagingBelt {
.map_async(MapMode::Write)
.inspect(move |_| sender.send(chunk).unwrap())
}))
.map(|_| ())
.map(|_| ())
}
}

View File

@@ -12,6 +12,7 @@ use std::{
pub use wgc::logging::subscriber::{initialize_default_subscriber, ChromeTracingLayer};
pub use belt::StagingBelt;
use std::sync::Arc;
/// Treat the given byte slice as a SPIR-V module.
///
@@ -53,3 +54,57 @@ pub fn make_spirv<'a>(data: &'a [u8]) -> super::ShaderModuleSource<'a> {
);
super::ShaderModuleSource::SpirV(words)
}
/// Utility methods not meant to be in the main API.
pub trait DeviceExt {
/// Creates a [`Buffer`] with data to initialize it.
fn create_buffer_init(&self, desc: &BufferInitDescriptor) -> crate::Buffer;
}
impl DeviceExt for crate::Device {
fn create_buffer_init(&self, descriptor: &BufferInitDescriptor<'_>) -> crate::Buffer {
let unpadded_size = descriptor.contents.len() as crate::BufferAddress;
let padding = crate::COPY_BUFFER_ALIGNMENT - unpadded_size % crate::COPY_BUFFER_ALIGNMENT;
let padded_size = padding + unpadded_size;
let wgt_descriptor = wgt::BufferDescriptor {
label: descriptor.label.as_ref().map(|x| Cow::Borrowed(&**x)),
size: padded_size,
usage: descriptor.usage,
mapped_at_creation: true,
};
let mut map_context = crate::MapContext::new(padded_size);
map_context.initial_range = 0..padded_size;
let buffer = crate::Buffer {
context: Arc::clone(&self.context),
id: crate::Context::device_create_buffer(&*self.context, &self.id, &wgt_descriptor),
map_context: parking_lot::Mutex::new(map_context),
usage: descriptor.usage,
};
let range =
crate::Context::buffer_get_mapped_range_mut(&*self.context, &buffer.id, 0..padded_size);
range[0..unpadded_size as usize].copy_from_slice(descriptor.contents);
for i in unpadded_size..padded_size {
range[i as usize] = 0;
}
buffer.unmap();
buffer
}
}
/// Describes a [`Buffer`] when allocating.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct BufferInitDescriptor<'a> {
/// Debug label of a buffer. This will show up in graphics debuggers for easy identification.
pub label: Option<&'a str>,
/// Contents of a buffer on creation.
pub contents: &'a [u8],
/// Usages of a buffer. If the buffer is used in any way that isn't specified here, the operation
/// will panic.
pub usage: crate::BufferUsage,
}