use std::future::Future;
use std::pin::Pin;
use std::sync::{Arc, Condvar, Mutex};
use std::task::{Context, Poll, Waker};
use std::thread;
use std::time::Duration;
struct DevicePollerState {
shutdown: bool,
pending: usize,
}
pub struct DevicePoller {
state: Arc<(Mutex<DevicePollerState>, Condvar)>,
handle: Option<thread::JoinHandle<()>>,
}
impl Clone for DevicePoller {
fn clone(&self) -> Self {
Self {
state: self.state.clone(),
handle: None,
}
}
}
impl DevicePoller {
pub fn start(device: Arc<wgpu::Device>) -> Self {
let state = Arc::new((
Mutex::new(DevicePollerState {
shutdown: false,
pending: 0,
}),
Condvar::new(),
));
let state_for_thread = state.clone();
let handle = thread::spawn(move || {
let (lock, cvar) = &*state_for_thread;
loop {
let mut guard = lock.lock().expect("poller state lock");
while !guard.shutdown && guard.pending == 0 {
guard = cvar.wait(guard).expect("poller cvar wait");
}
let should_exit = guard.shutdown;
let has_work = guard.pending > 0;
drop(guard);
if has_work {
device.poll(wgpu::PollType::Poll).ok();
thread::sleep(Duration::from_micros(100));
}
if should_exit {
break;
}
}
});
Self {
state,
handle: Some(handle),
}
}
pub fn request_poll(&self) {
let (lock, cvar) = &*self.state;
let mut guard = lock.lock().expect("poller state lock");
guard.pending += 1;
cvar.notify_one();
}
pub fn poll_complete(&self) {
let (lock, _cvar) = &*self.state;
let mut guard = lock.lock().expect("poller state lock");
let previous = guard.pending;
guard.pending = guard.pending.saturating_sub(1);
debug_assert!(
previous > 0,
"poll_complete called without a matching request_poll"
);
}
}
impl Drop for DevicePoller {
fn drop(&mut self) {
if self.handle.is_none() {
return;
}
let (lock, cvar) = &*self.state;
let mut guard = lock.lock().expect("poller state lock");
guard.shutdown = true;
cvar.notify_one();
drop(guard);
if let Some(handle) = self.handle.take() {
handle.join().ok();
}
}
}
struct MapAsyncState {
result: Mutex<Option<Result<(), wgpu::BufferAsyncError>>>,
waker: Mutex<Option<Waker>>,
}
impl MapAsyncState {
fn new() -> Self {
Self {
result: Mutex::new(None),
waker: Mutex::new(None),
}
}
fn set_result(&self, result: Result<(), wgpu::BufferAsyncError>) {
*self.result.lock().expect("map_async state result lock") = Some(result);
if let Some(waker) = self
.waker
.lock()
.expect("map_async state waker lock")
.take()
{
waker.wake();
}
}
fn poll(&self, cx: &mut Context<'_>) -> Poll<Result<(), wgpu::BufferAsyncError>> {
let mut result = self.result.lock().expect("map_async state result lock");
if let Some(res) = result.take() {
return Poll::Ready(res);
}
*self.waker.lock().expect("map_async state waker lock") = Some(cx.waker().clone());
Poll::Pending
}
}
pub struct BufferMapAsyncFuture {
state: Arc<MapAsyncState>,
}
impl BufferMapAsyncFuture {
pub fn new(poller: &DevicePoller, buffer: &wgpu::Buffer) -> Self {
let state = Arc::new(MapAsyncState::new());
let state_clone = state.clone();
let poller = poller.clone();
poller.request_poll();
buffer
.slice(..)
.map_async(wgpu::MapMode::Read, move |result| {
state_clone.set_result(result);
poller.poll_complete();
});
Self { state }
}
}
impl Future for BufferMapAsyncFuture {
type Output = Result<(), wgpu::BufferAsyncError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.state.poll(cx)
}
}
pub async fn request_adapter_async(
instance: &wgpu::Instance,
options: &wgpu::RequestAdapterOptions<'_, '_>,
) -> Result<wgpu::Adapter, wgpu::RequestAdapterError> {
instance.request_adapter(options).await
}
pub async fn request_device_async(
adapter: &wgpu::Adapter,
descriptor: &wgpu::DeviceDescriptor<'_>,
) -> Result<(wgpu::Device, wgpu::Queue), wgpu::RequestDeviceError> {
adapter.request_device(descriptor).await
}