diff options
Diffstat (limited to 'components/webgpu/poll_thread.rs')
-rw-r--r-- | components/webgpu/poll_thread.rs | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/components/webgpu/poll_thread.rs b/components/webgpu/poll_thread.rs index 9239f41e60c..060b5171ffb 100644 --- a/components/webgpu/poll_thread.rs +++ b/components/webgpu/poll_thread.rs @@ -7,7 +7,7 @@ //! This is roughly based on <https://github.com/LucentFlux/wgpu-async/blob/1322c7e3fcdfc1865a472c7bbbf0e2e06dcf4da8/src/wgpu_future.rs> use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::sync::Arc; +use std::sync::{Arc, Mutex, MutexGuard}; use std::thread::JoinHandle; use log::warn; @@ -40,14 +40,25 @@ pub(crate) struct Poller { is_done: Arc<AtomicBool>, /// Handle to the WGPU poller thread (to be used for unparking the thread) handle: Option<JoinHandle<()>>, + /// Lock for device maintain calls (in poll_all_devices and queue_submit) + /// + /// This is workaround for wgpu deadlocks: https://github.com/gfx-rs/wgpu/issues/5572 + lock: Arc<Mutex<()>>, } #[inline] -fn poll_all_devices(global: &Arc<Global>, more_work: &mut bool, force_wait: bool) { +fn poll_all_devices( + global: &Arc<Global>, + more_work: &mut bool, + force_wait: bool, + lock: &Mutex<()>, +) { + let _guard = lock.lock().unwrap(); match global.poll_all_devices(force_wait) { Ok(all_queue_empty) => *more_work = !all_queue_empty, Err(e) => warn!("Poller thread got `{e}` on poll_all_devices."), } + // drop guard } impl Poller { @@ -56,9 +67,11 @@ impl Poller { let is_done = Arc::new(AtomicBool::new(false)); let work = work_count.clone(); let done = is_done.clone(); + let lock = Arc::new(Mutex::new(())); Self { work_count, is_done, + lock: Arc::clone(&lock), handle: Some( std::thread::Builder::new() .name("WGPU poller".into()) @@ -69,9 +82,9 @@ impl Poller { // so every `ẁake` (even spurious) will do at least one poll. // this is mostly useful for stuff that is deferred // to maintain calls in wgpu (device resource destruction) - poll_all_devices(&global, &mut more_work, false); + poll_all_devices(&global, &mut more_work, false, &lock); while more_work || work.load(Ordering::Acquire) != 0 { - poll_all_devices(&global, &mut more_work, true); + poll_all_devices(&global, &mut more_work, true, &lock); } std::thread::park(); //TODO: should we use timeout here } @@ -101,6 +114,11 @@ impl Poller { .thread() .unpark(); } + + /// Lock for device maintain calls (in poll_all_devices and queue_submit) + pub(crate) fn lock(&self) -> MutexGuard<()> { + self.lock.lock().unwrap() + } } impl Drop for Poller { |