204: Return futures from request adapter/request device r=kvark a=grovesNL

Relevant to #175

Backporting some parts of #193 for async request adapter and async request device.

Co-authored-by: Joshua Groves <josh@joshgroves.com>
This commit is contained in:
bors[bot]
2020-03-16 22:56:43 +00:00
committed by GitHub
8 changed files with 64 additions and 67 deletions

View File

@@ -13,6 +13,7 @@ async fn run() {
},
wgpu::BackendBit::PRIMARY,
)
.await
.unwrap();
let (device, queue) = adapter.request_device(&wgpu::DeviceDescriptor {
@@ -20,7 +21,8 @@ async fn run() {
anisotropic_filtering: false,
},
limits: wgpu::Limits::default(),
});
})
.await;
// Rendered image is 256×256 with 32-bit RGBA color
let size = 256u32;

View File

@@ -1,13 +1,17 @@
/// This example shows how to describe the adapter in use.
fn main() {
env_logger::init();
futures::executor::block_on(run());
}
async fn run() {
let adapter = wgpu::Adapter::request(
&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::Default,
},
wgpu::BackendBit::PRIMARY,
)
.await
.unwrap();
println!("{:?}", adapter.get_info())

View File

@@ -52,7 +52,7 @@ pub trait Example: 'static + Sized {
) -> wgpu::CommandBuffer;
}
pub fn run<E: Example>(title: &str) {
async fn run_async<E: Example>(title: &str) {
use winit::{
event,
event_loop::{ControlFlow, EventLoop},
@@ -105,6 +105,7 @@ pub fn run<E: Example>(title: &str) {
},
wgpu::BackendBit::PRIMARY,
)
.await
.unwrap();
let (device, queue) = adapter.request_device(&wgpu::DeviceDescriptor {
@@ -112,7 +113,8 @@ pub fn run<E: Example>(title: &str) {
anisotropic_filtering: false,
},
limits: wgpu::Limits::default(),
});
})
.await;
let mut sc_desc = wgpu::SwapChainDescriptor {
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
@@ -180,6 +182,10 @@ pub fn run<E: Example>(title: &str) {
});
}
pub fn run<E: Example>(title: &str) {
futures::executor::block_on(run_async::<E>(title));
}
// This allows treating the framework as a standalone example,
// thus avoiding listing the example names in `Cargo.toml`.
#[allow(dead_code)]

View File

@@ -2,18 +2,18 @@ use std::{convert::TryInto as _, str::FromStr};
use zerocopy::AsBytes as _;
async fn run() {
env_logger::init();
let numbers = if std::env::args().len() == 1 {
let default = vec![1, 2, 3, 4];
log::info!("No numbers were provided, defaulting to {:?}", default);
default
} else {
std::env::args()
.skip(1)
.map(|s| u32::from_str(&s).expect("You must pass a list of positive integers!"))
.collect()
};
// For now this just panics if you didn't pass numbers. Could add proper error handling.
if std::env::args().len() == 1 {
panic!("You must pass a list of positive integers!")
}
let numbers: Vec<u32> = std::env::args()
.skip(1)
.map(|s| u32::from_str(&s).expect("You must pass a list of positive integers!"))
.collect();
println!("Times: {:?}", execute_gpu(numbers).await);
log::info!("Times: {:?}", execute_gpu(numbers).await);
}
async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
@@ -26,6 +26,7 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
},
wgpu::BackendBit::PRIMARY,
)
.await
.unwrap();
let (device, queue) = adapter.request_device(&wgpu::DeviceDescriptor {
@@ -33,7 +34,8 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
anisotropic_filtering: false,
},
limits: wgpu::Limits::default(),
});
})
.await;
let cs = include_bytes!("shader.comp.spv");
let cs_module =
@@ -108,6 +110,7 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
}
fn main() {
env_logger::init();
futures::executor::block_on(run());
}

View File

@@ -1,39 +1,12 @@
fn main() {
use winit::{
event,
event_loop::{ControlFlow, EventLoop},
};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::Window
};
env_logger::init();
let event_loop = EventLoop::new();
#[cfg(not(feature = "gl"))]
let (window, size, surface) = {
let window = winit::window::Window::new(&event_loop).unwrap();
let size = window.inner_size();
let surface = wgpu::Surface::create(&window);
(window, size, surface)
};
#[cfg(feature = "gl")]
let (window, instance, size, surface) = {
let wb = winit::WindowBuilder::new();
let cb = wgpu::glutin::ContextBuilder::new().with_vsync(true);
let context = cb.build_windowed(wb, &event_loop).unwrap();
let size = context
.window()
.get_inner_size()
.unwrap()
.to_physical(context.window().get_hidpi_factor());
let (context, window) = unsafe { context.make_current().unwrap().split() };
let instance = wgpu::Instance::new(context);
let surface = instance.get_surface();
(window, instance, size, surface)
};
async fn run(event_loop: EventLoop<()>, window: Window) {
let size = window.inner_size();
let surface = wgpu::Surface::create(&window);
let adapter = wgpu::Adapter::request(
&wgpu::RequestAdapterOptions {
@@ -41,6 +14,7 @@ fn main() {
},
wgpu::BackendBit::PRIMARY,
)
.await
.unwrap();
let (device, queue) = adapter.request_device(&wgpu::DeviceDescriptor {
@@ -48,7 +22,8 @@ fn main() {
anisotropic_filtering: false,
},
limits: wgpu::Limits::default(),
});
})
.await;
let vs = include_bytes!("shader.vert.spv");
let vs_module =
@@ -113,13 +88,13 @@ fn main() {
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Poll;
match event {
event::Event::MainEventsCleared => window.request_redraw(),
event::Event::WindowEvent { event: event::WindowEvent::Resized(size), .. } => {
Event::MainEventsCleared => window.request_redraw(),
Event::WindowEvent { event: WindowEvent::Resized(size), .. } => {
sc_desc.width = size.width;
sc_desc.height = size.height;
swap_chain = device.create_swap_chain(&surface, &sc_desc);
}
event::Event::RedrawRequested(_) => {
Event::RedrawRequested(_) => {
let frame = swap_chain
.get_next_texture()
.expect("Timeout when acquiring next swap chain texture");
@@ -143,11 +118,17 @@ fn main() {
queue.submit(&[encoder.finish()]);
}
event::Event::WindowEvent {
event: event::WindowEvent::CloseRequested,
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => *control_flow = ControlFlow::Exit,
_ => {}
}
});
}
fn main() {
let event_loop = EventLoop::new();
let window = winit::window::Window::new(&event_loop).unwrap();
env_logger::init();
futures::executor::block_on(run(event_loop, window));
}

1
src/backend/mod.rs Normal file
View File

@@ -0,0 +1 @@
pub(crate) mod native_gpu_future;

View File

@@ -1,8 +1,7 @@
//! A cross-platform graphics and compute library based on WebGPU.
mod future;
use future::GpuFutureCompletion;
pub use future::GpuFuture;
mod backend;
use crate::backend::native_gpu_future;
#[macro_use]
mod macros;
@@ -12,6 +11,7 @@ use smallvec::SmallVec;
use std::{
ffi::CString,
future::Future,
ops::Range,
ptr,
slice,
@@ -501,7 +501,7 @@ impl Adapter {
/// Some options are "soft", so treated as non-mandatory. Others are "hard".
///
/// If no adapters are found that suffice all the "hard" options, `None` is returned.
pub fn request(options: &RequestAdapterOptions, backends: BackendBit) -> Option<Self> {
pub async 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,
@@ -527,7 +527,7 @@ impl Adapter {
/// # Panics
///
/// Panics if the extensions specified by `desc` are not supported by this adapter.
pub fn request_device(&self, desc: &DeviceDescriptor) -> (Device, Queue) {
pub async fn request_device(&self, desc: &DeviceDescriptor) -> (Device, Queue) {
let device = Device {
id: wgn::wgpu_adapter_request_device(self.id, Some(desc)),
temp: Temp::default(),
@@ -910,22 +910,22 @@ impl<T> Drop for BufferAsyncMapping<T> {
struct BufferMapReadFutureUserData
{
size: BufferAddress,
completion: GpuFutureCompletion<BufferMapReadResult>,
completion: native_gpu_future::GpuFutureCompletion<BufferMapReadResult>,
buffer_id: wgc::id::BufferId,
}
struct BufferMapWriteFutureUserData
{
size: BufferAddress,
completion: GpuFutureCompletion<BufferMapWriteResult>,
completion: native_gpu_future::GpuFutureCompletion<BufferMapWriteResult>,
buffer_id: wgc::id::BufferId,
}
impl Buffer {
/// Map the buffer for reading. The result is returned in a future.
pub fn map_read(&self, start: BufferAddress, size: BufferAddress) -> GpuFuture<BufferMapReadResult>
pub fn map_read(&self, start: BufferAddress, size: BufferAddress) -> impl Future<Output = crate::BufferMapReadResult>
{
let (future, completion) = future::new_gpu_future(self.device_id);
let (future, completion) = native_gpu_future::new_gpu_future(self.device_id);
extern "C" fn buffer_map_read_future_wrapper(
status: wgc::resource::BufferMapAsyncStatus,
@@ -963,9 +963,9 @@ impl Buffer {
}
/// Map the buffer for writing. The result is returned in a future.
pub fn map_write(&self, start: BufferAddress, size: BufferAddress) -> GpuFuture<BufferMapWriteResult>
pub fn map_write(&self, start: BufferAddress, size: BufferAddress) -> impl Future<Output = crate::BufferMapWriteResult>
{
let (future, completion) = future::new_gpu_future(self.device_id);
let (future, completion) = native_gpu_future::new_gpu_future(self.device_id);
extern "C" fn buffer_map_write_future_wrapper(
status: wgc::resource::BufferMapAsyncStatus,