Skip to content
This repository was archived by the owner on Jun 18, 2021. It is now read-only.

Use u8 for buffer mapping #127

Merged
merged 4 commits into from
Nov 22, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -37,7 +37,6 @@ rev = "73b33ea76e2f91b3114aa7640b1d60518d39f915"
[dependencies]
arrayvec = "0.5"
raw-window-handle = "0.3"
zerocopy = "0.2"

[dev-dependencies]
cgmath = "0.17"
@@ -46,3 +45,4 @@ glsl-to-spirv = "0.1"
log = "0.4"
png = "0.15"
winit = "0.20.0-alpha4"
zerocopy = "0.2"
3 changes: 2 additions & 1 deletion examples/capture/main.rs
Original file line number Diff line number Diff line change
@@ -12,7 +12,8 @@ fn main() {
power_preference: wgpu::PowerPreference::Default,
},
wgpu::BackendBit::PRIMARY,
).unwrap();
)
.unwrap();

let (device, mut queue) = adapter.request_device(&wgpu::DeviceDescriptor {
extensions: wgpu::Extensions {
56 changes: 31 additions & 25 deletions examples/cube/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#[path = "../framework.rs"]
mod framework;

use zerocopy::{AsBytes, FromBytes};

#[repr(C)]
#[derive(Clone, Copy, zerocopy::AsBytes, zerocopy::FromBytes)]
#[derive(Clone, Copy, AsBytes, FromBytes)]
struct Vertex {
_pos: [f32; 4],
_tex_coord: [f32; 2],
@@ -107,7 +109,10 @@ impl Example {
}

impl framework::Example for Example {
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device) -> (Self, Option<wgpu::CommandBuffer>) {
fn init(
sc_desc: &wgpu::SwapChainDescriptor,
device: &wgpu::Device,
) -> (Self, Option<wgpu::CommandBuffer>) {
use std::mem;

let mut init_encoder =
@@ -116,23 +121,20 @@ impl framework::Example for Example {
// Create the vertex and index buffers
let vertex_size = mem::size_of::<Vertex>();
let (vertex_data, index_data) = create_vertices();
let vertex_buf = device
.create_buffer_mapped(vertex_data.len(), wgpu::BufferUsage::VERTEX)
.fill_from_slice(&vertex_data);

let index_buf = device
.create_buffer_mapped(index_data.len(), wgpu::BufferUsage::INDEX)
.fill_from_slice(&index_data);
let vertex_buf =
device.create_buffer_with_data(vertex_data.as_bytes(), wgpu::BufferUsage::VERTEX);

let index_buf =
device.create_buffer_with_data(index_data.as_bytes(), wgpu::BufferUsage::INDEX);

// Create pipeline layout
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[
wgpu::BindGroupLayoutBinding {
binding: 0,
visibility: wgpu::ShaderStage::VERTEX,
ty: wgpu::BindingType::UniformBuffer {
dynamic: false,
},
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
},
wgpu::BindGroupLayoutBinding {
binding: 1,
@@ -171,9 +173,8 @@ impl framework::Example for Example {
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
});
let texture_view = texture.create_default_view();
let temp_buf = device
.create_buffer_mapped(texels.len(), wgpu::BufferUsage::COPY_SRC)
.fill_from_slice(&texels);
let temp_buf =
device.create_buffer_with_data(texels.as_slice(), wgpu::BufferUsage::COPY_SRC);
init_encoder.copy_buffer_to_texture(
wgpu::BufferCopyView {
buffer: &temp_buf,
@@ -208,12 +209,10 @@ 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_mapped(
16,
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
)
.fill_from_slice(mx_ref);
let uniform_buf = device.create_buffer_with_data(
mx_ref.as_bytes(),
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
);

// Create bind group
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
@@ -310,21 +309,28 @@ impl framework::Example for Example {
//empty
}

fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device) -> Option<wgpu::CommandBuffer> {
fn resize(
&mut self,
sc_desc: &wgpu::SwapChainDescriptor,
device: &wgpu::Device,
) -> Option<wgpu::CommandBuffer> {
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 temp_buf = device
.create_buffer_mapped(16, wgpu::BufferUsage::COPY_SRC)
.fill_from_slice(mx_ref);
let temp_buf =
device.create_buffer_with_data(mx_ref.as_bytes(), wgpu::BufferUsage::COPY_SRC);

let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
encoder.copy_buffer_to_buffer(&temp_buf, 0, &self.uniform_buf, 0, 64);
Some(encoder.finish())
}

fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &wgpu::Device) -> wgpu::CommandBuffer {
fn render(
&mut self,
frame: &wgpu::SwapChainOutput,
device: &wgpu::Device,
) -> wgpu::CommandBuffer {
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
{
3 changes: 2 additions & 1 deletion examples/describe/main.rs
Original file line number Diff line number Diff line change
@@ -7,7 +7,8 @@ fn main() {
power_preference: wgpu::PowerPreference::Default,
},
wgpu::BackendBit::PRIMARY,
).unwrap();
)
.unwrap();

println!("{:?}", adapter.get_info())
}
6 changes: 4 additions & 2 deletions examples/framework.rs
Original file line number Diff line number Diff line change
@@ -99,7 +99,8 @@ pub fn run<E: Example>(title: &str) {
power_preference: wgpu::PowerPreference::Default,
},
wgpu::BackendBit::PRIMARY,
).unwrap();
)
.unwrap();

let (device, mut queue) = adapter.request_device(&wgpu::DeviceDescriptor {
extensions: wgpu::Extensions {
@@ -163,7 +164,8 @@ pub fn run<E: Example>(title: &str) {
}
},
event::Event::EventsCleared => {
let frame = swap_chain.get_next_texture()
let frame = swap_chain
.get_next_texture()
.expect("Timeout when acquiring next swap chain texture");
let command_buf = example.render(&frame, &device);
queue.submit(&[command_buf]);
47 changes: 27 additions & 20 deletions examples/hello-compute/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::str::FromStr;
use std::{convert::TryInto as _, str::FromStr};
use zerocopy::AsBytes as _;

fn main() {
env_logger::init();
@@ -12,14 +13,16 @@ fn main() {
.map(|s| u32::from_str(&s).expect("You must pass a list of positive integers!"))
.collect();

let size = (numbers.len() * std::mem::size_of::<u32>()) as wgpu::BufferAddress;
let slice_size = numbers.len() * std::mem::size_of::<u32>();
let size = slice_size as wgpu::BufferAddress;

let adapter = wgpu::Adapter::request(
&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::Default,
},
wgpu::BackendBit::PRIMARY,
).unwrap();
)
.unwrap();

let (device, mut queue) = adapter.request_device(&wgpu::DeviceDescriptor {
extensions: wgpu::Extensions {
@@ -29,16 +32,13 @@ fn main() {
});

let cs = include_bytes!("shader.comp.spv");
let cs_module = device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&cs[..])).unwrap());
let cs_module =
device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&cs[..])).unwrap());

let staging_buffer = device
.create_buffer_mapped(
numbers.len(),
wgpu::BufferUsage::MAP_READ
| wgpu::BufferUsage::COPY_DST
| wgpu::BufferUsage::COPY_SRC,
)
.fill_from_slice(&numbers);
let staging_buffer = device.create_buffer_with_data(
numbers.as_slice().as_bytes(),
wgpu::BufferUsage::MAP_READ | wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::COPY_SRC,
);

let storage_buffer = device.create_buffer(&wgpu::BufferDescriptor {
size,
@@ -48,13 +48,14 @@ fn main() {
});

let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[
wgpu::BindGroupLayoutBinding {
binding: 0,
visibility: wgpu::ShaderStage::COMPUTE,
ty: wgpu::BindingType::StorageBuffer { dynamic: false, readonly: false },
bindings: &[wgpu::BindGroupLayoutBinding {
binding: 0,
visibility: wgpu::ShaderStage::COMPUTE,
ty: wgpu::BindingType::StorageBuffer {
dynamic: false,
readonly: false,
},
],
}],
});

let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
@@ -92,9 +93,15 @@ fn main() {

queue.submit(&[encoder.finish()]);

staging_buffer.map_read_async(0, numbers.len(), |result: wgpu::BufferMapAsyncResult<&[u32]>| {
// FIXME: Align and use `LayoutVerified`
staging_buffer.map_read_async(0, slice_size, |result| {
if let Ok(mapping) = result {
println!("Times: {:?}", mapping.data);
let times: Box<[u32]> = mapping
.data
.chunks_exact(4)
.map(|b| u32::from_ne_bytes(b.try_into().unwrap()))
.collect();
println!("Times: {:?}", times);
}
});
}
23 changes: 12 additions & 11 deletions examples/hello-triangle/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
fn main() {
use winit::{
event_loop::{ControlFlow, EventLoop},
event,
event_loop::{ControlFlow, EventLoop},
};

env_logger::init();
@@ -10,9 +10,7 @@ fn main() {
#[cfg(not(feature = "gl"))]
let (_window, size, surface) = {
let window = winit::window::Window::new(&event_loop).unwrap();
let size = window
.inner_size()
.to_physical(window.hidpi_factor());
let size = window.inner_size().to_physical(window.hidpi_factor());

let surface = wgpu::Surface::create(&window);
(window, size, surface)
@@ -43,7 +41,8 @@ fn main() {
power_preference: wgpu::PowerPreference::Default,
},
wgpu::BackendBit::PRIMARY,
).unwrap();
)
.unwrap();

let (device, mut queue) = adapter.request_device(&wgpu::DeviceDescriptor {
extensions: wgpu::Extensions {
@@ -53,14 +52,15 @@ fn main() {
});

let vs = include_bytes!("shader.vert.spv");
let vs_module = device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs[..])).unwrap());
let vs_module =
device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs[..])).unwrap());

let fs = include_bytes!("shader.frag.spv");
let fs_module = device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs[..])).unwrap());
let fs_module =
device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs[..])).unwrap());

let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[],
});
let bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { bindings: &[] });
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &bind_group_layout,
bindings: &[],
@@ -135,7 +135,8 @@ fn main() {
_ => {}
},
event::Event::EventsCleared => {
let frame = swap_chain.get_next_texture()
let frame = swap_chain
.get_next_texture()
.expect("Timeout when acquiring next swap chain texture");
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
110 changes: 55 additions & 55 deletions examples/mipmap/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#[path = "../framework.rs"]
mod framework;

use zerocopy::{AsBytes, FromBytes};

const TEXTURE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8UnormSrgb;

#[repr(C)]
#[derive(Clone, Copy, zerocopy::AsBytes, zerocopy::FromBytes)]
#[derive(Clone, Copy, AsBytes, FromBytes)]
struct Vertex {
#[allow(dead_code)]
pos: [f32; 4],
@@ -96,14 +98,10 @@ impl Example {
bind_group_layouts: &[&bind_group_layout],
});

let vs_bytes = framework::load_glsl(
include_str!("blit.vert"),
framework::ShaderStage::Vertex,
);
let fs_bytes = framework::load_glsl(
include_str!("blit.frag"),
framework::ShaderStage::Fragment,
);
let vs_bytes =
framework::load_glsl(include_str!("blit.vert"), framework::ShaderStage::Vertex);
let fs_bytes =
framework::load_glsl(include_str!("blit.frag"), framework::ShaderStage::Fragment);
let vs_module = device.create_shader_module(&vs_bytes);
let fs_module = device.create_shader_module(&fs_bytes);

@@ -152,15 +150,17 @@ impl Example {
});

let views = (0 .. mip_count)
.map(|mip| texture.create_view(&wgpu::TextureViewDescriptor {
format: TEXTURE_FORMAT,
dimension: wgpu::TextureViewDimension::D2,
aspect: wgpu::TextureAspect::All,
base_mip_level: mip,
level_count: 1,
base_array_layer: 0,
array_layer_count: 1,
}))
.map(|mip| {
texture.create_view(&wgpu::TextureViewDescriptor {
format: TEXTURE_FORMAT,
dimension: wgpu::TextureViewDimension::D2,
aspect: wgpu::TextureAspect::All,
base_mip_level: mip,
level_count: 1,
base_array_layer: 0,
array_layer_count: 1,
})
})
.collect::<Vec<_>>();

for target_mip in 1 .. mip_count as usize {
@@ -196,7 +196,10 @@ impl Example {
}

impl framework::Example for Example {
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device) -> (Self, Option<wgpu::CommandBuffer>) {
fn init(
sc_desc: &wgpu::SwapChainDescriptor,
device: &wgpu::Device,
) -> (Self, Option<wgpu::CommandBuffer>) {
use std::mem;

let mut init_encoder =
@@ -205,19 +208,16 @@ 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_mapped(vertex_data.len(), wgpu::BufferUsage::VERTEX)
.fill_from_slice(&vertex_data);
let vertex_buf =
device.create_buffer_with_data(vertex_data.as_bytes(), wgpu::BufferUsage::VERTEX);

// Create pipeline layout
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[
wgpu::BindGroupLayoutBinding {
binding: 0,
visibility: wgpu::ShaderStage::VERTEX,
ty: wgpu::BindingType::UniformBuffer {
dynamic: false,
},
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
},
wgpu::BindGroupLayoutBinding {
binding: 1,
@@ -254,12 +254,13 @@ impl framework::Example for Example {
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: TEXTURE_FORMAT,
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::OUTPUT_ATTACHMENT | wgpu::TextureUsage::COPY_DST,
usage: wgpu::TextureUsage::SAMPLED
| wgpu::TextureUsage::OUTPUT_ATTACHMENT
| wgpu::TextureUsage::COPY_DST,
});
let texture_view = texture.create_default_view();
let temp_buf = device
.create_buffer_mapped(texels.len(), wgpu::BufferUsage::COPY_SRC)
.fill_from_slice(&texels);
let temp_buf =
device.create_buffer_with_data(texels.as_slice(), wgpu::BufferUsage::COPY_SRC);
init_encoder.copy_buffer_to_texture(
wgpu::BufferCopyView {
buffer: &temp_buf,
@@ -294,12 +295,10 @@ 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_mapped(
16,
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
)
.fill_from_slice(mx_ref);
let uniform_buf = device.create_buffer_with_data(
mx_ref.as_bytes(),
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
);

// Create bind group
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
@@ -324,14 +323,10 @@ impl framework::Example for Example {
});

// Create the render pipeline
let vs_bytes = framework::load_glsl(
include_str!("draw.vert"),
framework::ShaderStage::Vertex,
);
let fs_bytes = framework::load_glsl(
include_str!("draw.frag"),
framework::ShaderStage::Fragment,
);
let vs_bytes =
framework::load_glsl(include_str!("draw.vert"), framework::ShaderStage::Vertex);
let fs_bytes =
framework::load_glsl(include_str!("draw.frag"), framework::ShaderStage::Fragment);
let vs_module = device.create_shader_module(&vs_bytes);
let fs_module = device.create_shader_module(&fs_bytes);

@@ -364,13 +359,11 @@ impl framework::Example for Example {
vertex_buffers: &[wgpu::VertexBufferDescriptor {
stride: vertex_size as wgpu::BufferAddress,
step_mode: wgpu::InputStepMode::Vertex,
attributes: &[
wgpu::VertexAttributeDescriptor {
format: wgpu::VertexFormat::Float4,
offset: 0,
shader_location: 0,
},
],
attributes: &[wgpu::VertexAttributeDescriptor {
format: wgpu::VertexFormat::Float4,
offset: 0,
shader_location: 0,
}],
}],
sample_count: 1,
sample_mask: !0,
@@ -393,21 +386,28 @@ impl framework::Example for Example {
//empty
}

fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device) -> Option<wgpu::CommandBuffer> {
fn resize(
&mut self,
sc_desc: &wgpu::SwapChainDescriptor,
device: &wgpu::Device,
) -> Option<wgpu::CommandBuffer> {
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 temp_buf = device
.create_buffer_mapped(16, wgpu::BufferUsage::COPY_SRC)
.fill_from_slice(mx_ref);
let temp_buf =
device.create_buffer_with_data(mx_ref.as_bytes(), wgpu::BufferUsage::COPY_SRC);

let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
encoder.copy_buffer_to_buffer(&temp_buf, 0, &self.uniform_buf, 0, 64);
Some(encoder.finish())
}

fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &wgpu::Device) -> wgpu::CommandBuffer {
fn render(
&mut self,
frame: &wgpu::SwapChainOutput,
device: &wgpu::Device,
) -> wgpu::CommandBuffer {
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
{
95 changes: 71 additions & 24 deletions examples/msaa-line/main.rs
Original file line number Diff line number Diff line change
@@ -10,10 +10,12 @@
#[path = "../framework.rs"]
mod framework;

use zerocopy::{AsBytes, FromBytes};

#[repr(C)]
#[derive(Clone, Copy, zerocopy::AsBytes, zerocopy::FromBytes)]
#[derive(Clone, Copy, AsBytes, FromBytes)]
struct Vertex {
_pos: [f32; 2],
_pos: [f32; 2],
_color: [f32; 4],
}

@@ -31,7 +33,14 @@ struct Example {
}

impl Example {
fn create_pipeline(device: &wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor, vs_module: &wgpu::ShaderModule, fs_module: &wgpu::ShaderModule, pipeline_layout: &wgpu::PipelineLayout, sample_count: u32) -> wgpu::RenderPipeline {
fn create_pipeline(
device: &wgpu::Device,
sc_desc: &wgpu::SwapChainDescriptor,
vs_module: &wgpu::ShaderModule,
fs_module: &wgpu::ShaderModule,
pipeline_layout: &wgpu::PipelineLayout,
sample_count: u32,
) -> wgpu::RenderPipeline {
println!("sample_count: {}", sample_count);
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
layout: &pipeline_layout,
@@ -81,7 +90,11 @@ impl Example {
})
}

fn create_multisampled_framebuffer(device: &wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor, sample_count: u32) -> wgpu::TextureView {
fn create_multisampled_framebuffer(
device: &wgpu::Device,
sc_desc: &wgpu::SwapChainDescriptor,
sample_count: u32,
) -> wgpu::TextureView {
let multisampled_texture_extent = wgpu::Extent3d {
width: sc_desc.width,
height: sc_desc.height,
@@ -97,31 +110,48 @@ impl Example {
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
};

device.create_texture(multisampled_frame_descriptor).create_default_view()
device
.create_texture(multisampled_frame_descriptor)
.create_default_view()
}
}

impl framework::Example for Example {
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device) -> (Self, Option<wgpu::CommandBuffer>) {
fn init(
sc_desc: &wgpu::SwapChainDescriptor,
device: &wgpu::Device,
) -> (Self, Option<wgpu::CommandBuffer>) {
println!("Press left/right arrow keys to change sample_count.");
let sample_count = 4;

let vs_bytes = framework::load_glsl(include_str!("shader.vert"), framework::ShaderStage::Vertex);
let fs_bytes = framework::load_glsl(include_str!("shader.frag"), framework::ShaderStage::Fragment);
let vs_bytes =
framework::load_glsl(include_str!("shader.vert"), framework::ShaderStage::Vertex);
let fs_bytes = framework::load_glsl(
include_str!("shader.frag"),
framework::ShaderStage::Fragment,
);
let vs_module = device.create_shader_module(&vs_bytes);
let fs_module = device.create_shader_module(&fs_bytes);

let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: &[],
});

let pipeline = Example::create_pipeline(device, &sc_desc, &vs_module, &fs_module, &pipeline_layout, sample_count);
let multisampled_framebuffer = Example::create_multisampled_framebuffer(device, sc_desc, sample_count);
let pipeline = Example::create_pipeline(
device,
&sc_desc,
&vs_module,
&fs_module,
&pipeline_layout,
sample_count,
);
let multisampled_framebuffer =
Example::create_multisampled_framebuffer(device, sc_desc, sample_count);

let mut vertex_data = vec!();
let mut vertex_data = vec![];

let max = 50;
for i in 0..max {
for i in 0 .. max {
let percent = i as f32 / max as f32;
let (sin, cos) = (percent * 2.0 * std::f32::consts::PI).sin_cos();
vertex_data.push(Vertex {
@@ -134,9 +164,8 @@ impl framework::Example for Example {
});
}

let vertex_buffer = device
.create_buffer_mapped(vertex_data.len(), wgpu::BufferUsage::VERTEX)
.fill_from_slice(&vertex_data);
let vertex_buffer =
device.create_buffer_with_data(vertex_data.as_bytes(), wgpu::BufferUsage::VERTEX);
let vertex_count = vertex_data.len() as u32;

let this = Example {
@@ -171,28 +200,46 @@ impl framework::Example for Example {
self.rebuild_pipeline = true;
}
}
_ => { }
_ => {}
}
}
}
_ => { }
_ => {}
}
}

fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device) -> Option<wgpu::CommandBuffer> {
fn resize(
&mut self,
sc_desc: &wgpu::SwapChainDescriptor,
device: &wgpu::Device,
) -> Option<wgpu::CommandBuffer> {
self.sc_desc = sc_desc.clone();
self.multisampled_framebuffer = Example::create_multisampled_framebuffer(device, sc_desc, self.sample_count);
self.multisampled_framebuffer =
Example::create_multisampled_framebuffer(device, sc_desc, self.sample_count);
None
}

fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &wgpu::Device) -> wgpu::CommandBuffer {
fn render(
&mut self,
frame: &wgpu::SwapChainOutput,
device: &wgpu::Device,
) -> wgpu::CommandBuffer {
if self.rebuild_pipeline {
self.pipeline = Example::create_pipeline(device, &self.sc_desc, &self.vs_module, &self.fs_module, &self.pipeline_layout, self.sample_count);
self.multisampled_framebuffer = Example::create_multisampled_framebuffer(device, &self.sc_desc, self.sample_count);
self.pipeline = Example::create_pipeline(
device,
&self.sc_desc,
&self.vs_module,
&self.fs_module,
&self.pipeline_layout,
self.sample_count,
);
self.multisampled_framebuffer =
Example::create_multisampled_framebuffer(device, &self.sc_desc, self.sample_count);
self.rebuild_pipeline = false;
}

let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
{
let rpass_color_attachment = if self.sample_count == 1 {
wgpu::RenderPassColorAttachmentDescriptor {
@@ -218,7 +265,7 @@ impl framework::Example for Example {
});
rpass.set_pipeline(&self.pipeline);
rpass.set_vertex_buffers(0, &[(&self.vertex_buffer, 0)]);
rpass.draw(0..self.vertex_count, 0..1);
rpass.draw(0 .. self.vertex_count, 0 .. 1);
}

encoder.finish()
156 changes: 87 additions & 69 deletions examples/shadow/main.rs
Original file line number Diff line number Diff line change
@@ -3,8 +3,10 @@ use std::{mem, ops::Range, rc::Rc};
#[path = "../framework.rs"]
mod framework;

use zerocopy::{AsBytes, FromBytes};

#[repr(C)]
#[derive(Clone, Copy, zerocopy::AsBytes, zerocopy::FromBytes)]
#[derive(Clone, Copy, AsBytes, FromBytes)]

struct Vertex {
_pos: [i8; 4],
@@ -97,7 +99,7 @@ struct Light {
}

#[repr(C)]
#[derive(Clone, Copy, zerocopy::AsBytes, zerocopy::FromBytes)]
#[derive(Clone, Copy, AsBytes, FromBytes)]
struct LightRaw {
proj: [[f32; 4]; 4],
pos: [f32; 4],
@@ -116,24 +118,30 @@ impl Light {
far: self.depth.end,
};
let mx_correction = framework::OPENGL_TO_WGPU_MATRIX;
let mx_view_proj = mx_correction * cgmath::Matrix4::from(projection.to_perspective()) * mx_view;
let mx_view_proj =
mx_correction * cgmath::Matrix4::from(projection.to_perspective()) * mx_view;
LightRaw {
proj: *mx_view_proj.as_ref(),
pos: [self.pos.x, self.pos.y, self.pos.z, 1.0],
color: [self.color.r as f32, self.color.g as f32, self.color.b as f32, 1.0],
color: [
self.color.r as f32,
self.color.g as f32,
self.color.b as f32,
1.0,
],
}
}
}

#[repr(C)]
#[derive(Clone, Copy, zerocopy::AsBytes, zerocopy::FromBytes)]
#[derive(Clone, Copy, AsBytes, FromBytes)]
struct ForwardUniforms {
proj: [[f32; 4]; 4],
num_lights: [u32; 4],
}

#[repr(C)]
#[derive(Clone, Copy, zerocopy::AsBytes, zerocopy::FromBytes)]
#[derive(Clone, Copy, AsBytes, FromBytes)]
struct EntityUniforms {
model: [[f32; 4]; 4],
color: [f32; 4],
@@ -183,46 +191,42 @@ impl Example {
}

impl framework::Example for Example {
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device) -> (Self, Option<wgpu::CommandBuffer>) {
fn init(
sc_desc: &wgpu::SwapChainDescriptor,
device: &wgpu::Device,
) -> (Self, Option<wgpu::CommandBuffer>) {
// 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_mapped(cube_vertex_data.len(), wgpu::BufferUsage::VERTEX)
.fill_from_slice(&cube_vertex_data),
device.create_buffer_with_data(cube_vertex_data.as_bytes(), wgpu::BufferUsage::VERTEX),
);

let cube_index_buf = Rc::new(
device
.create_buffer_mapped(cube_index_data.len(), wgpu::BufferUsage::INDEX)
.fill_from_slice(&cube_index_data),
device.create_buffer_with_data(cube_index_data.as_bytes(), wgpu::BufferUsage::INDEX),
);

let (plane_vertex_data, plane_index_data) = create_plane(7);
let plane_vertex_buf = device
.create_buffer_mapped(plane_vertex_data.len(), wgpu::BufferUsage::VERTEX)
.fill_from_slice(&plane_vertex_data);
let plane_vertex_buf =
device.create_buffer_with_data(plane_vertex_data.as_bytes(), wgpu::BufferUsage::VERTEX);

let plane_index_buf = device
.create_buffer_mapped(plane_index_data.len(), wgpu::BufferUsage::INDEX)
.fill_from_slice(&plane_index_data);
let plane_index_buf =
device.create_buffer_with_data(plane_index_data.as_bytes(), wgpu::BufferUsage::INDEX);

let entity_uniform_size = mem::size_of::<EntityUniforms>() as wgpu::BufferAddress;
let plane_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
size: entity_uniform_size,
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
});

let local_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[
wgpu::BindGroupLayoutBinding {
let local_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[wgpu::BindGroupLayoutBinding {
binding: 0,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
},
],
});
}],
});

let mut entities = vec![{
use cgmath::SquareMatrix;
@@ -406,15 +410,14 @@ impl framework::Example for Example {

let shadow_pass = {
// Create pipeline layout
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[
wgpu::BindGroupLayoutBinding {
let bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[wgpu::BindGroupLayoutBinding {
binding: 0, // global
visibility: wgpu::ShaderStage::VERTEX,
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
},
],
});
}],
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: &[&bind_group_layout, &local_bind_group_layout],
});
@@ -495,16 +498,12 @@ impl framework::Example for Example {
wgpu::BindGroupLayoutBinding {
binding: 0, // global
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::UniformBuffer {
dynamic: false,
},
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
},
wgpu::BindGroupLayoutBinding {
binding: 1, // lights
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::UniformBuffer {
dynamic: false,
},
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
},
wgpu::BindGroupLayoutBinding {
binding: 2,
@@ -531,12 +530,10 @@ impl framework::Example for Example {
num_lights: [lights.len() as u32, 0, 0, 0],
};
let uniform_size = mem::size_of::<ForwardUniforms>() as wgpu::BufferAddress;
let uniform_buf = device
.create_buffer_mapped(
1,
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
)
.fill_from_slice(&[forward_uniforms]);
let uniform_buf = device.create_buffer_with_data(
forward_uniforms.as_bytes(),
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
);

// Create bind group
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
@@ -654,13 +651,16 @@ impl framework::Example for Example {
//empty
}

fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device) -> Option<wgpu::CommandBuffer> {
fn resize(
&mut self,
sc_desc: &wgpu::SwapChainDescriptor,
device: &wgpu::Device,
) -> Option<wgpu::CommandBuffer> {
let command_buf = {
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 temp_buf = device
.create_buffer_mapped(16, wgpu::BufferUsage::COPY_SRC)
.fill_from_slice(mx_ref);
let temp_buf =
device.create_buffer_with_data(mx_ref.as_bytes(), wgpu::BufferUsage::COPY_SRC);

let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
@@ -686,59 +686,77 @@ impl framework::Example for Example {
Some(command_buf)
}

fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &wgpu::Device) -> wgpu::CommandBuffer {
fn render(
&mut self,
frame: &wgpu::SwapChainOutput,
device: &wgpu::Device,
) -> wgpu::CommandBuffer {
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });

{
let size = mem::size_of::<EntityUniforms>() as wgpu::BufferAddress;
let temp_buf_data =
device.create_buffer_mapped(self.entities.len(), wgpu::BufferUsage::COPY_SRC);

for (i, entity) in self.entities.iter_mut().enumerate() {
let size = mem::size_of::<EntityUniforms>();
let temp_buf_data = device
.create_buffer_mapped(self.entities.len() * size, wgpu::BufferUsage::COPY_SRC);

// FIXME: Align and use `LayoutVerified`
for (entity, slot) in self
.entities
.iter_mut()
.zip(temp_buf_data.data.chunks_exact_mut(size))
{
if entity.rotation_speed != 0.0 {
let rotation =
cgmath::Matrix4::from_angle_x(cgmath::Deg(entity.rotation_speed));
entity.mx_world = entity.mx_world * rotation;
}
temp_buf_data.data[i] = EntityUniforms {
model: entity.mx_world.into(),
color: [
entity.color.r as f32,
entity.color.g as f32,
entity.color.b as f32,
entity.color.a as f32,
],
};
slot.copy_from_slice(
EntityUniforms {
model: entity.mx_world.into(),
color: [
entity.color.r as f32,
entity.color.g as f32,
entity.color.b as f32,
entity.color.a as f32,
],
}
.as_bytes(),
);
}

let temp_buf = temp_buf_data.finish();

for (i, entity) in self.entities.iter().enumerate() {
encoder.copy_buffer_to_buffer(
&temp_buf,
i as wgpu::BufferAddress * size,
(i * size) as wgpu::BufferAddress,
&entity.uniform_buf,
0,
size,
size as wgpu::BufferAddress,
);
}
}

if self.lights_are_dirty {
self.lights_are_dirty = false;
let size = (self.lights.len() * mem::size_of::<LightRaw>()) as wgpu::BufferAddress;
let size = mem::size_of::<LightRaw>();
let total_size = size * self.lights.len();
let temp_buf_data =
device.create_buffer_mapped(self.lights.len(), wgpu::BufferUsage::COPY_SRC);
for (i, light) in self.lights.iter().enumerate() {
temp_buf_data.data[i] = light.to_raw();
device.create_buffer_mapped(total_size, wgpu::BufferUsage::COPY_SRC);
// FIXME: Align and use `LayoutVerified`
for (light, slot) in self
.lights
.iter()
.zip(temp_buf_data.data.chunks_exact_mut(size))
{
slot.copy_from_slice(light.to_raw().as_bytes());
}
encoder.copy_buffer_to_buffer(
&temp_buf_data.finish(),
0,
&self.light_uniform_buf,
0,
size,
total_size as wgpu::BufferAddress,
);
}

63 changes: 35 additions & 28 deletions examples/skybox/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#[path = "../framework.rs"]
mod framework;

use zerocopy::AsBytes as _;

const SKYBOX_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8Unorm;

type Uniforms = [cgmath::Matrix4<f32>; 2];
type Uniform = cgmath::Matrix4<f32>;
type Uniforms = [Uniform; 2];

pub struct Skybox {
aspect: f32,
@@ -26,6 +29,23 @@ impl Skybox {
}
}

fn buffer_from_uniforms(
device: &wgpu::Device,
uniforms: &Uniforms,
usage: wgpu::BufferUsage,
) -> wgpu::Buffer {
let uniform_buf = device.create_buffer_mapped(std::mem::size_of::<Uniforms>(), usage);
// FIXME: Align and use `LayoutVerified`
for (u, slot) in uniforms.iter().zip(
uniform_buf
.data
.chunks_exact_mut(std::mem::size_of::<Uniform>()),
) {
slot.copy_from_slice(AsRef::<[[f32; 4]; 4]>::as_ref(u).as_bytes());
}
uniform_buf.finish()
}

impl framework::Example for Skybox {
fn init(
sc_desc: &wgpu::SwapChainDescriptor,
@@ -71,15 +91,11 @@ 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_mapped::<[[f32; 4]; 4]>(
uniforms.len(),
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
)
.fill_from_slice(&[
uniforms[0].into(),
uniforms[1].into(),
]);
let uniform_buf = buffer_from_uniforms(
&device,
&uniforms,
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
);
let uniform_buf_size = std::mem::size_of::<Uniforms>();

let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
@@ -175,11 +191,11 @@ impl framework::Example for Skybox {
for (i, image) in faces.iter().enumerate() {
log::debug!(
"Copying skybox image {} of size {},{} to gpu",
i, image_width, image_height,
i,
image_width,
image_height,
);
let image_buf = device
.create_buffer_mapped(image.len(), wgpu::BufferUsage::COPY_SRC)
.fill_from_slice(&image);
let image_buf = device.create_buffer_with_data(image, wgpu::BufferUsage::COPY_SRC);

init_encoder.copy_buffer_to_texture(
wgpu::BufferCopyView {
@@ -218,7 +234,7 @@ impl framework::Example for Skybox {
binding: 0,
resource: wgpu::BindingResource::Buffer {
buffer: &uniform_buf,
range: 0..uniform_buf_size as wgpu::BufferAddress,
range: 0 .. uniform_buf_size as wgpu::BufferAddress,
},
},
wgpu::Binding {
@@ -257,9 +273,8 @@ impl framework::Example for Skybox {
let mx_total = uniforms[0] * uniforms[1];
let mx_ref: &[f32; 16] = mx_total.as_ref();

let temp_buf = device
.create_buffer_mapped(16, wgpu::BufferUsage::COPY_SRC)
.fill_from_slice(mx_ref);
let temp_buf =
device.create_buffer_with_data(mx_ref.as_bytes(), wgpu::BufferUsage::COPY_SRC);

let mut init_encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
@@ -278,15 +293,7 @@ impl framework::Example for Skybox {
let rotation = cgmath::Matrix4::<f32>::from_angle_x(cgmath::Deg(0.25));
self.uniforms[1] = self.uniforms[1] * rotation;
let uniform_buf_size = std::mem::size_of::<Uniforms>();
let temp_buf = device
.create_buffer_mapped::<[[f32; 4]; 4]>(
self.uniforms.len(),
wgpu::BufferUsage::COPY_SRC,
)
.fill_from_slice(&[
self.uniforms[0].into(),
self.uniforms[1].into(),
]);
let temp_buf = buffer_from_uniforms(&device, &self.uniforms, wgpu::BufferUsage::COPY_SRC);

init_encoder.copy_buffer_to_buffer(
&temp_buf,
@@ -315,7 +322,7 @@ impl framework::Example for Skybox {

rpass.set_pipeline(&self.pipeline);
rpass.set_bind_group(0, &self.bind_group, &[]);
rpass.draw(0..3 as u32, 0..1);
rpass.draw(0 .. 3 as u32, 0 .. 1);
}
init_encoder.finish()
}
182 changes: 75 additions & 107 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
//! A cross-platform graphics and compute library based on WebGPU.
use arrayvec::ArrayVec;
use zerocopy::{AsBytes, FromBytes, LayoutVerified};

use std::convert::TryFrom;
use std::ffi::CString;
use std::ops::Range;
use std::ptr;
use std::slice;
use std::thread;

pub use wgc::{
binding_model::{
ShaderStage,
},
binding_model::ShaderStage,
command::{
CommandEncoderDescriptor,
CommandBufferDescriptor,
CommandEncoderDescriptor,
LoadOp,
RenderPassDepthStencilAttachmentDescriptor,
StoreOp,
@@ -50,6 +46,7 @@ pub use wgc::{
VertexAttributeDescriptor,
VertexFormat,
},
read_spirv,
resource::{
AddressMode,
BufferDescriptor,
@@ -66,24 +63,18 @@ pub use wgc::{
TextureViewDescriptor,
TextureViewDimension,
},
swap_chain::{
PresentMode,
SwapChainDescriptor,
},
swap_chain::{PresentMode, SwapChainDescriptor},
BufferAddress,
Color,
Extent3d,
Origin3d,
read_spirv,
};


//TODO: avoid heap allocating vectors during resource creation.
#[derive(Default)]
#[derive(Debug)]
#[derive(Default, Debug)]
struct Temp {
//bind_group_descriptors: Vec<wgn::BindGroupDescriptor>,
//vertex_buffers: Vec<wgn::VertexBufferDescriptor>,
//vertex_buffers: Vec<wgn::VertexBufferDescriptor>,
}

/// A handle to a physical graphics and/or compute device.
@@ -500,27 +491,12 @@ impl<'a> TextureCopyView<'a> {
}

/// A buffer being created, mapped in host memory.
pub struct CreateBufferMapped<'a, T> {
pub struct CreateBufferMapped<'a> {
id: wgc::id::BufferId,
pub data: &'a mut [T],
pub data: &'a mut [u8],
}

impl<'a, T> CreateBufferMapped<'a, T>
where
T: Copy,
{
/// Copies a slice into the mapped buffer and unmaps it, returning a [`Buffer`].
///
/// `slice` and `self.data` must have the same length.
///
/// # Panics
///
/// Panics if the slices have different lengths.
pub fn fill_from_slice(self, slice: &[T]) -> Buffer {
self.data.copy_from_slice(slice);
self.finish()
}

impl CreateBufferMapped<'_> {
/// Unmaps the buffer from host memory and returns a [`Buffer`].
pub fn finish(self) -> Buffer {
wgn::wgpu_buffer_unmap(self.id);
@@ -551,15 +527,21 @@ impl Adapter {
///
/// If no adapters are found that suffice all the "hard" options, `None` is returned.
pub fn request(options: &RequestAdapterOptions, backends: BackendBit) -> Option<Self> {
unsafe extern "C" fn adapter_callback(id: wgc::id::AdapterId, user_data: *mut std::ffi::c_void) {
unsafe extern "C" fn adapter_callback(
id: wgc::id::AdapterId,
user_data: *mut std::ffi::c_void,
) {
*(user_data as *mut wgc::id::AdapterId) = id;
}

let mut id = wgc::id::AdapterId::ERROR;
wgn::wgpu_request_adapter_async(Some(options), backends, adapter_callback, &mut id as *mut _ as *mut std::ffi::c_void);
Some(Adapter {
id,
})
wgn::wgpu_request_adapter_async(
Some(options),
backends,
adapter_callback,
&mut id as *mut _ as *mut std::ffi::c_void,
);
Some(Adapter { id })
}

/// Requests a connection to a physical device, creating a logical device.
@@ -617,7 +599,7 @@ impl Device {

let bindings = desc
.bindings
.into_iter()
.iter()
.map(|binding| bm::BindGroupBinding {
binding: binding.binding,
resource: match binding.resource {
@@ -655,31 +637,36 @@ impl Device {
pub fn create_bind_group_layout(&self, desc: &BindGroupLayoutDescriptor) -> BindGroupLayout {
use wgc::binding_model as bm;

let temp_layouts = desc.bindings
let temp_layouts = desc
.bindings
.iter()
.map(|bind| bm::BindGroupLayoutBinding {
binding: bind.binding,
visibility: bind.visibility,
ty: match bind.ty {
BindingType::UniformBuffer { .. } => bm::BindingType::UniformBuffer,
BindingType::StorageBuffer { readonly: false, .. } => bm::BindingType::StorageBuffer,
BindingType::StorageBuffer { readonly: true, .. } => bm::BindingType::ReadonlyStorageBuffer,
BindingType::StorageBuffer {
readonly: false, ..
} => bm::BindingType::StorageBuffer,
BindingType::StorageBuffer { readonly: true, .. } => {
bm::BindingType::ReadonlyStorageBuffer
}
BindingType::Sampler => bm::BindingType::Sampler,
BindingType::SampledTexture { .. } => bm::BindingType::SampledTexture,
BindingType::StorageTexture { .. } => bm::BindingType::StorageTexture,
},
dynamic: match bind.ty {
BindingType::UniformBuffer { dynamic } |
BindingType::StorageBuffer { dynamic, .. } => dynamic,
BindingType::UniformBuffer { dynamic }
| BindingType::StorageBuffer { dynamic, .. } => dynamic,
_ => false,
},
multisampled: match bind.ty {
BindingType::SampledTexture { multisampled, .. } => multisampled,
_ => false,
},
texture_dimension: match bind.ty {
BindingType::SampledTexture { dimension, .. } |
BindingType::StorageTexture { dimension } => dimension,
BindingType::SampledTexture { dimension, .. }
| BindingType::StorageTexture { dimension } => dimension,
_ => TextureViewDimension::D2,
},
})
@@ -756,7 +743,8 @@ impl Device {
fragment_stage: fragment_stage
.as_ref()
.map_or(ptr::null(), |fs| fs as *const _),
rasterization_state: desc.rasterization_state
rasterization_state: desc
.rasterization_state
.as_ref()
.map_or(ptr::null(), |p| p as *const _),
primitive_topology: desc.primitive_topology,
@@ -808,32 +796,32 @@ impl Device {

/// Creates a new buffer and maps it into host-visible memory.
///
/// This returns a [`CreateBufferMapped<T>`], which exposes a `&mut [T]`. The actual [`Buffer`]
/// This returns a [`CreateBufferMapped`], which exposes a `&mut [u8]`. The actual [`Buffer`]
/// will not be created until calling [`CreateBufferMapped::finish`].
pub fn create_buffer_mapped<'a, T>(
&'a self,
count: usize,
usage: BufferUsage,
) -> CreateBufferMapped<'a, T>
where
T: 'static + Copy + AsBytes + FromBytes,
{
let type_size = std::mem::size_of::<T>() as BufferAddress;
assert_ne!(type_size, 0);
pub fn create_buffer_mapped(&self, size: usize, usage: BufferUsage) -> CreateBufferMapped<'_> {
assert_ne!(size, 0);

let desc = BufferDescriptor {
size: (type_size * count as BufferAddress).max(1),
size: size as BufferAddress,
usage,
};
let mut ptr: *mut u8 = std::ptr::null_mut();

let id = wgn::wgpu_device_create_buffer_mapped(self.id, &desc, &mut ptr as *mut *mut u8);

let data = unsafe { std::slice::from_raw_parts_mut(ptr as *mut T, count) };
let data = unsafe { std::slice::from_raw_parts_mut(ptr as *mut u8, size) };

CreateBufferMapped { id, data }
}

/// 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 mapped = self.create_buffer_mapped(data.len(), usage);
mapped.data.copy_from_slice(data);
mapped.finish()
}

/// Creates a new [`Texture`].
///
/// `desc` specifies the general format of the texture.
@@ -883,50 +871,39 @@ impl<T> Drop for BufferAsyncMapping<T> {
}
}

struct BufferMapReadAsyncUserData<T, F>
struct BufferMapReadAsyncUserData<F>
where
T: FromBytes,
F: FnOnce(BufferMapAsyncResult<&[T]>),
F: FnOnce(BufferMapAsyncResult<&[u8]>),
{
size: BufferAddress,
size: usize,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this type changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To get rid of this:

slice::from_raw_parts(data as *const u8, usize::try_from(user_data.size).unwrap())

BufferMapXxxAsyncUserData is only used to pass info to the C callback in the respective map_xxx_async, and the input to those functions is already a usize. The current code converts to BufferAddress and back to usize.

callback: F,
buffer_id: wgc::id::BufferId,
phantom: std::marker::PhantomData<T>,
}

struct BufferMapWriteAsyncUserData<T, F>
struct BufferMapWriteAsyncUserData<F>
where
T: AsBytes + FromBytes,
F: FnOnce(BufferMapAsyncResult<&mut [T]>),
F: FnOnce(BufferMapAsyncResult<&mut [u8]>),
{
size: BufferAddress,
size: usize,
callback: F,
buffer_id: wgc::id::BufferId,
phantom: std::marker::PhantomData<T>,
}

impl Buffer {
pub fn map_read_async<T, F>(&self, start: BufferAddress, count: usize, callback: F)
pub fn map_read_async<F>(&self, start: BufferAddress, size: usize, callback: F)
where
T: 'static + FromBytes,
F: FnOnce(BufferMapAsyncResult<&[T]>),
F: FnOnce(BufferMapAsyncResult<&[u8]>),
{
extern "C" fn buffer_map_read_callback_wrapper<T, F>(
extern "C" fn buffer_map_read_callback_wrapper<F>(
status: BufferMapAsyncStatus,
data: *const u8,
user_data: *mut u8,
) where
T: FromBytes,
F: FnOnce(BufferMapAsyncResult<&[T]>),
F: FnOnce(BufferMapAsyncResult<&[u8]>),
{
let user_data =
unsafe { Box::from_raw(user_data as *mut BufferMapReadAsyncUserData<T, F>) };
let data: &[u8] = unsafe {
slice::from_raw_parts(data as *const u8, usize::try_from(user_data.size).unwrap())
};
let data = LayoutVerified::new_slice(data)
.expect("could not interpret bytes as &[T]")
.into_slice();
unsafe { Box::from_raw(user_data as *mut BufferMapReadAsyncUserData<F>) };
let data: &[u8] = unsafe { slice::from_raw_parts(data as *const u8, user_data.size) };
match status {
BufferMapAsyncStatus::Success => (user_data.callback)(Ok(BufferAsyncMapping {
data,
@@ -936,44 +913,34 @@ impl Buffer {
}
}

let size = (count * std::mem::size_of::<T>()) as BufferAddress;

let user_data = Box::new(BufferMapReadAsyncUserData {
size,
callback,
buffer_id: self.id,
phantom: std::marker::PhantomData,
});
wgn::wgpu_buffer_map_read_async(
self.id,
start,
size,
buffer_map_read_callback_wrapper::<T, F>,
size as BufferAddress,
buffer_map_read_callback_wrapper::<F>,
Box::into_raw(user_data) as *mut u8,
);
}

pub fn map_write_async<T, F>(&self, start: BufferAddress, count: usize, callback: F)
pub fn map_write_async<F>(&self, start: BufferAddress, size: usize, callback: F)
where
T: 'static + AsBytes + FromBytes,
F: FnOnce(BufferMapAsyncResult<&mut [T]>),
F: FnOnce(BufferMapAsyncResult<&mut [u8]>),
{
extern "C" fn buffer_map_write_callback_wrapper<T, F>(
extern "C" fn buffer_map_write_callback_wrapper<F>(
status: BufferMapAsyncStatus,
data: *mut u8,
user_data: *mut u8,
) where
T: AsBytes + FromBytes,
F: FnOnce(BufferMapAsyncResult<&mut [T]>),
F: FnOnce(BufferMapAsyncResult<&mut [u8]>),
{
let user_data =
unsafe { Box::from_raw(user_data as *mut BufferMapWriteAsyncUserData<T, F>) };
let data = unsafe {
slice::from_raw_parts_mut(data as *mut u8, usize::try_from(user_data.size).unwrap())
};
let data = LayoutVerified::new_slice(data)
.expect("could not interpret bytes as &mut [T]")
.into_mut_slice();
unsafe { Box::from_raw(user_data as *mut BufferMapWriteAsyncUserData<F>) };
let data = unsafe { slice::from_raw_parts_mut(data as *mut u8, user_data.size) };
match status {
BufferMapAsyncStatus::Success => (user_data.callback)(Ok(BufferAsyncMapping {
data,
@@ -983,19 +950,16 @@ impl Buffer {
}
}

let size = (count * std::mem::size_of::<T>()) as BufferAddress;

let user_data = Box::new(BufferMapWriteAsyncUserData {
size,
callback,
buffer_id: self.id,
phantom: std::marker::PhantomData,
});
wgn::wgpu_buffer_map_write_async(
self.id,
start,
size,
buffer_map_write_callback_wrapper::<T, F>,
size as BufferAddress,
buffer_map_write_callback_wrapper::<F>,
Box::into_raw(user_data) as *mut u8,
);
}
@@ -1294,7 +1258,11 @@ impl<'a> RenderPass<'a> {
///
/// The active index buffer can be set with [`RenderPass::set_index_buffer`], while the active
/// vertex buffers can be set with [`RenderPass::set_vertex_buffers`].
pub fn draw_indexed_indirect(&mut self, indirect_buffer: &Buffer, indirect_offset: BufferAddress) {
pub fn draw_indexed_indirect(
&mut self,
indirect_buffer: &Buffer,
indirect_offset: BufferAddress,
) {
wgn::wgpu_render_pass_draw_indexed_indirect(self.id, indirect_buffer.id, indirect_offset);
}
}
67 changes: 39 additions & 28 deletions tests/multithreaded_compute.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#[cfg(any(feature = "vulkan", feature = "metal", feature = "dx12"))]
use std::convert::TryInto as _;

#[test]
#[cfg(any(feature = "vulkan", feature = "metal", feature = "dx12"))]
fn multithreaded_compute() {
@@ -13,31 +16,34 @@ fn multithreaded_compute() {
thread::spawn(move || {
let numbers = vec![100, 100, 100];

let size = (numbers.len() * std::mem::size_of::<u32>()) as wgpu::BufferAddress;
let slice_size = numbers.len() * std::mem::size_of::<u32>();
let size = slice_size as wgpu::BufferAddress;

let instance = wgpu::Instance::new();
let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::Default,
});
let adapter = wgpu::Adapter::request(
&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::Default,
},
wgpu::BackendBit::PRIMARY,
)
.unwrap();

let mut device = adapter.request_device(&wgpu::DeviceDescriptor {
let (device, mut queue) = adapter.request_device(&wgpu::DeviceDescriptor {
extensions: wgpu::Extensions {
anisotropic_filtering: false,
},
limits: wgpu::Limits::default(),
});

let cs = include_bytes!("../examples/hello-compute/shader.comp.spv");
let cs_module = device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&cs[..])).unwrap());
let cs_module = device
.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&cs[..])).unwrap());

let staging_buffer = device
.create_buffer_mapped(
numbers.len(),
wgpu::BufferUsage::MAP_READ
| wgpu::BufferUsage::COPY_DST
| wgpu::BufferUsage::COPY_SRC,
)
.fill_from_slice(&numbers);
let staging_buffer = device.create_buffer_with_data(
numbers.as_slice(),
wgpu::BufferUsage::MAP_READ
| wgpu::BufferUsage::COPY_DST
| wgpu::BufferUsage::COPY_SRC,
);

let storage_buffer = device.create_buffer(&wgpu::BufferDescriptor {
size,
@@ -48,16 +54,14 @@ fn multithreaded_compute() {

let bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[
wgpu::BindGroupLayoutBinding {
binding: 0,
visibility: wgpu::ShaderStage::COMPUTE,
ty: wgpu::BindingType::StorageBuffer {
dynamic: false,
readonly: false,
},
bindings: &[wgpu::BindGroupLayoutBinding {
binding: 0,
visibility: wgpu::ShaderStage::COMPUTE,
ty: wgpu::BindingType::StorageBuffer {
dynamic: false,
readonly: false,
},
],
}],
});

let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
@@ -95,10 +99,17 @@ fn multithreaded_compute() {
}
encoder.copy_buffer_to_buffer(&storage_buffer, 0, &staging_buffer, 0, size);

device.get_queue().submit(&[encoder.finish()]);

staging_buffer.map_read_async(0, size, |result: wgpu::BufferMapAsyncResult<&[u32]>| {
assert_eq!(result.unwrap().data, [25, 25, 25]);
queue.submit(&[encoder.finish()]);

// FIXME: Align and use `LayoutVerified`
staging_buffer.map_read_async(0, slice_size, |result| {
let result_data: Box<[u32]> = result
.unwrap()
.data
.chunks_exact(std::mem::size_of::<u32>())
.map(|c| u32::from_ne_bytes(c.try_into().unwrap()))
.collect();
assert_eq!(&*result_data, &[25, 25, 25]);
});
tx.send(true).unwrap();
});