127: Use u8 for buffer mapping r=kvark a=Coder-256

cc @kvark @grovesNL

This is a temporary solution for #119, and a follow-up for #126.

Co-authored-by: Jacob Greenfield <jacob@jacobgreenfield.me>
This commit is contained in:
bors[bot] 2019-11-22 01:41:56 +00:00 committed by GitHub
commit 1968eb81e7
13 changed files with 439 additions and 370 deletions

View File

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

View File

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

View File

@ -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,13 +121,12 @@ 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 {
@ -130,9 +134,7 @@ impl framework::Example for Example {
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,13 +309,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 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 });
@ -324,7 +326,11 @@ impl framework::Example for Example {
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 });
{

View File

@ -7,7 +7,8 @@ fn main() {
power_preference: wgpu::PowerPreference::Default,
},
wgpu::BackendBit::PRIMARY,
).unwrap();
)
.unwrap();
println!("{:?}", adapter.get_info())
}

View File

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

View File

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

View File

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

View File

@ -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,9 +208,8 @@ 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 {
@ -215,9 +217,7 @@ impl framework::Example for Example {
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,13 +386,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 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 });
@ -407,7 +403,11 @@ impl framework::Example for Example {
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 });
{

View File

@ -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,17 +110,26 @@ 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);
@ -115,13 +137,21 @@ impl framework::Example for Example {
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()

View File

@ -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,30 +191,27 @@ 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 {
@ -214,15 +219,14 @@ impl framework::Example for Example {
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,30 +686,42 @@ 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);
let size = mem::size_of::<EntityUniforms>();
let temp_buf_data = device
.create_buffer_mapped(self.entities.len() * size, wgpu::BufferUsage::COPY_SRC);
for (i, entity) in self.entities.iter_mut().enumerate() {
// 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();
@ -717,28 +729,34 @@ impl framework::Example for Example {
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,
);
}

View File

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

View File

@ -1,9 +1,7 @@
//! 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;
@ -11,12 +9,10 @@ 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,22 +637,27 @@ 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 {
@ -678,8 +665,8 @@ impl Device {
_ => 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,
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);
}
}

View File

@ -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,14 +16,18 @@ 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,
},
@ -28,16 +35,15 @@ fn multithreaded_compute() {
});
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()]);
queue.submit(&[encoder.finish()]);
staging_buffer.map_read_async(0, size, |result: wgpu::BufferMapAsyncResult<&[u32]>| {
assert_eq!(result.unwrap().data, [25, 25, 25]);
// 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();
});