[rs] Merge #82

82: Return Queue separately r=grovesNL a=kvark

What problem is this PR trying to solve? We want `Device` to be freely accessible from multiple threads/objects and internally synchronized. `Arc<Device>` seems like a natural choice of such a sharable object, especially since all except one methods are `&self`.

That one method is `get_queue()`, and it returns a temporary object `Queue<'a>`. If we turn it into `&self`, we'd end up with multiple instances of `Queue` created at any time, which contradicts the initial design (of this Rust wrapper). If it stays `&mut` and the user wraps the device into `Arc`, they'll never be able to submit any work...

So this PR solves this by moving the `Queue` completely outside of the device.

Co-authored-by: Dzmitry Malyshau <dmalyshau@mozilla.com>
This commit is contained in:
bors[bot] 2019-09-10 13:27:14 +00:00 committed by GitHub
commit b01a4bb169
9 changed files with 80 additions and 76 deletions

View File

@ -12,7 +12,7 @@ fn main() {
backends: 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,
},
@ -80,7 +80,7 @@ fn main() {
encoder.finish()
};
device.get_queue().submit(&[command_buffer]);
queue.submit(&[command_buffer]);
// Write the buffer as a PNG
output_buffer.map_read_async(

View File

@ -106,7 +106,7 @@ impl Example {
}
impl framework::Example for Example {
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) -> Self {
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device) -> (Self, Option<wgpu::CommandBuffer>) {
use std::mem;
let mut init_encoder =
@ -294,23 +294,22 @@ impl framework::Example for Example {
});
// Done
let init_command_buf = init_encoder.finish();
device.get_queue().submit(&[init_command_buf]);
Example {
let this = Example {
vertex_buf,
index_buf,
index_count: index_data.len(),
bind_group,
uniform_buf,
pipeline,
}
};
(this, Some(init_encoder.finish()))
}
fn update(&mut self, _event: winit::event::WindowEvent) {
//empty
}
fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) {
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();
@ -321,10 +320,10 @@ impl framework::Example for Example {
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
encoder.copy_buffer_to_buffer(&temp_buf, 0, &self.uniform_buf, 0, 64);
device.get_queue().submit(&[encoder.finish()]);
Some(encoder.finish())
}
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device) {
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &wgpu::Device) -> wgpu::CommandBuffer {
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
{
@ -350,7 +349,7 @@ impl framework::Example for Example {
rpass.draw_indexed(0 .. self.index_count as u32, 0, 0 .. 1);
}
device.get_queue().submit(&[encoder.finish()]);
encoder.finish()
}
}

View File

@ -35,11 +35,11 @@ pub fn load_glsl(code: &str, stage: ShaderStage) -> Vec<u32> {
wgpu::read_spirv(glsl_to_spirv::compile(&code, ty).unwrap()).unwrap()
}
pub trait Example: 'static {
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) -> Self;
fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device);
pub trait Example: 'static + Sized {
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device) -> (Self, Option<wgpu::CommandBuffer>);
fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device) -> Option<wgpu::CommandBuffer>;
fn update(&mut self, event: WindowEvent);
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device);
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &wgpu::Device) -> wgpu::CommandBuffer;
}
pub fn run<E: Example>(title: &str) {
@ -89,7 +89,7 @@ pub fn run<E: Example>(title: &str) {
backends: 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,
},
@ -106,7 +106,10 @@ pub fn run<E: Example>(title: &str) {
let mut swap_chain = device.create_swap_chain(&surface, &sc_desc);
info!("Initializing the example...");
let mut example = E::init(&sc_desc, &mut device);
let (mut example, init_command_buf) = E::init(&sc_desc, &device);
if let Some(command_buf) = init_command_buf {
queue.submit(&[command_buf]);
}
info!("Entering render loop...");
event_loop.run(move |event, _, control_flow| {
@ -125,7 +128,10 @@ pub fn run<E: Example>(title: &str) {
sc_desc.width = physical.width.round() as u32;
sc_desc.height = physical.height.round() as u32;
swap_chain = device.create_swap_chain(&surface, &sc_desc);
example.resize(&sc_desc, &mut device);
let command_buf = example.resize(&sc_desc, &device);
if let Some(command_buf) = command_buf {
queue.submit(&[command_buf]);
}
}
event::Event::WindowEvent { event, .. } => match event {
WindowEvent::KeyboardInput {
@ -146,7 +152,8 @@ pub fn run<E: Example>(title: &str) {
},
event::Event::EventsCleared => {
let frame = swap_chain.get_next_texture();
example.render(&frame, &mut device);
let command_buf = example.render(&frame, &device);
queue.submit(&[command_buf]);
}
_ => (),
}

View File

@ -19,7 +19,7 @@ fn main() {
backends: 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,
},
@ -88,7 +88,7 @@ fn main() {
}
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]>| {
if let Ok(mapping) = result {

View File

@ -43,7 +43,7 @@ fn main() {
backends: 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,
},
@ -152,7 +152,7 @@ fn main() {
rpass.draw(0 .. 3, 0 .. 1);
}
device.get_queue().submit(&[encoder.finish()]);
queue.submit(&[encoder.finish()]);
}
_ => (),
}

View File

@ -69,8 +69,11 @@ impl Example {
}
fn generate_mipmaps(
device: &wgpu::Device, texture: &wgpu::Texture, mip_count: u32
) -> wgpu::CommandBuffer {
encoder: &mut wgpu::CommandEncoder,
device: &wgpu::Device,
texture: &wgpu::Texture,
mip_count: u32,
) {
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[
wgpu::BindGroupLayoutBinding {
@ -159,10 +162,6 @@ impl Example {
}))
.collect::<Vec<_>>();
let mut encoder = device.create_command_encoder(
&wgpu::CommandEncoderDescriptor { todo: 0 }
);
for target_mip in 1 .. mip_count as usize {
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &bind_group_layout,
@ -192,13 +191,11 @@ impl Example {
rpass.set_bind_group(0, &bind_group, &[]);
rpass.draw(0 .. 4, 0 .. 1);
}
encoder.finish()
}
}
impl framework::Example for Example {
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) -> Self {
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device) -> (Self, Option<wgpu::CommandBuffer>) {
use std::mem;
let mut init_encoder =
@ -380,22 +377,22 @@ impl framework::Example for Example {
});
// Done
let init_command_buf = init_encoder.finish();
let mipmap_command_buf = Self::generate_mipmaps(&device, &texture, mip_level_count);
device.get_queue().submit(&[init_command_buf, mipmap_command_buf]);
Example {
Self::generate_mipmaps(&mut init_encoder, &device, &texture, mip_level_count);
let this = Example {
vertex_buf,
bind_group,
uniform_buf,
draw_pipeline,
}
};
(this, Some(init_encoder.finish()))
}
fn update(&mut self, _event: winit::event::WindowEvent) {
//empty
}
fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) {
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();
@ -406,10 +403,10 @@ impl framework::Example for Example {
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
encoder.copy_buffer_to_buffer(&temp_buf, 0, &self.uniform_buf, 0, 64);
device.get_queue().submit(&[encoder.finish()]);
Some(encoder.finish())
}
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device) {
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &wgpu::Device) -> wgpu::CommandBuffer {
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
{
@ -434,7 +431,7 @@ impl framework::Example for Example {
rpass.draw(0 .. 4, 0 .. 1);
}
device.get_queue().submit(&[encoder.finish()]);
encoder.finish()
}
}

View File

@ -101,7 +101,7 @@ impl Example {
}
impl framework::Example for Example {
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) -> Self {
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;
@ -138,7 +138,7 @@ impl framework::Example for Example {
.fill_from_slice(&vertex_data);
let vertex_count = vertex_data.len() as u32;
Example {
let this = Example {
vs_module,
fs_module,
pipeline_layout,
@ -149,7 +149,8 @@ impl framework::Example for Example {
rebuild_pipeline: false,
sample_count,
sc_desc: sc_desc.clone(),
}
};
(this, None)
}
fn update(&mut self, event: winit::event::WindowEvent) {
@ -177,12 +178,13 @@ impl framework::Example for Example {
}
}
fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) {
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);
None
}
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device) {
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);
@ -218,7 +220,7 @@ impl framework::Example for Example {
rpass.draw(0..self.vertex_count, 0..1);
}
device.get_queue().submit(&[encoder.finish()]);
encoder.finish()
}
}

View File

@ -181,7 +181,7 @@ impl Example {
}
impl framework::Example for Example {
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) -> Self {
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();
@ -636,7 +636,7 @@ impl framework::Example for Example {
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
});
Example {
let this = Example {
entities,
lights,
lights_are_dirty: true,
@ -644,15 +644,16 @@ impl framework::Example for Example {
forward_pass,
forward_depth: depth_texture.create_default_view(),
light_uniform_buf,
}
};
(this, None)
}
fn update(&mut self, _event: winit::event::WindowEvent) {
//empty
}
fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) {
{
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
@ -662,8 +663,8 @@ impl framework::Example for Example {
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
encoder.copy_buffer_to_buffer(&temp_buf, 0, &self.forward_pass.uniform_buf, 0, 64);
device.get_queue().submit(&[encoder.finish()]);
}
encoder.finish()
};
let depth_texture = device.create_texture(&wgpu::TextureDescriptor {
size: wgpu::Extent3d {
@ -679,9 +680,11 @@ impl framework::Example for Example {
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
});
self.forward_depth = depth_texture.create_default_view();
Some(command_buf)
}
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device) {
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &wgpu::Device) -> wgpu::CommandBuffer {
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
@ -807,7 +810,7 @@ impl framework::Example for Example {
}
}
device.get_queue().submit(&[encoder.finish()]);
encoder.finish()
}
}

View File

@ -73,7 +73,6 @@ pub use wgn::glutin;
struct Temp {
//bind_group_descriptors: Vec<wgn::BindGroupDescriptor>,
//vertex_buffers: Vec<wgn::VertexBufferDescriptor>,
command_buffers: Vec<wgn::CommandBufferId>,
}
/// A handle to a physical graphics and/or compute device.
@ -245,11 +244,11 @@ pub struct ComputePass<'a> {
/// A handle to a command queue on a device.
///
/// A `Queue` executes finished [`CommandBuffer`] objects.
/// A `Queue` executes recorded [`CommandBuffer`] objects.
#[derive(Debug)]
pub struct Queue<'a> {
pub struct Queue {
id: wgn::QueueId,
temp: &'a mut Temp,
temp_command_buffers: Vec<wgn::CommandBufferId>,
}
/// A resource that can be bound to a pipeline.
@ -546,15 +545,21 @@ impl Adapter {
}
/// Requests a connection to a physical device, creating a logical device.
/// Returns the device together with a queue that executes command buffers.
///
/// # Panics
///
/// Panics if the extensions specified by `desc` are not supported by this adapter.
pub fn request_device(&self, desc: &DeviceDescriptor) -> Device {
Device {
pub fn request_device(&self, desc: &DeviceDescriptor) -> (Device, Queue) {
let device = Device {
id: wgn::wgpu_adapter_request_device(self.id, Some(desc)),
temp: Temp::default(),
}
};
let queue = Queue {
id: wgn::wgpu_device_get_queue(device.id),
temp_command_buffers: Vec::new(),
};
(device, queue)
}
}
@ -577,14 +582,6 @@ impl Device {
}
}
/// Obtains a queue which can accept [`CommandBuffer`] submissions.
pub fn get_queue(&mut self) -> Queue {
Queue {
id: wgn::wgpu_device_get_queue(self.id),
temp: &mut self.temp,
}
}
/// Creates an empty [`CommandEncoder`].
pub fn create_command_encoder(&self, desc: &CommandEncoderDescriptor) -> CommandEncoder {
CommandEncoder {
@ -1299,17 +1296,16 @@ impl<'a> Drop for ComputePass<'a> {
}
}
impl<'a> Queue<'a> {
impl Queue {
/// Submits a series of finished command buffers for execution.
pub fn submit(&mut self, command_buffers: &[CommandBuffer]) {
self.temp.command_buffers.clear();
self.temp
.command_buffers
self.temp_command_buffers.clear();
self.temp_command_buffers
.extend(command_buffers.iter().map(|cb| cb.id));
wgn::wgpu_queue_submit(
self.id,
self.temp.command_buffers.as_ptr(),
self.temp_command_buffers.as_ptr(),
command_buffers.len(),
);
}