use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, MutexGuard};
use std::thread::JoinHandle;
use log::warn;
use crate::wgc::global::Global;
#[derive(Debug)]
pub(crate) struct Poller {
work_count: Arc<AtomicUsize>,
is_done: Arc<AtomicBool>,
handle: Option<JoinHandle<()>>,
lock: Arc<Mutex<()>>,
}
#[inline]
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."),
}
}
impl Poller {
pub(crate) fn new(global: Arc<Global>) -> Self {
let work_count = Arc::new(AtomicUsize::new(0));
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())
.spawn(move || {
while !done.load(Ordering::Acquire) {
let 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, &lock);
}
std::thread::park(); }
})
.expect("Spawning thread should not fail"),
),
}
}
pub(crate) fn token(&self) -> WorkToken {
let prev = self.work_count.fetch_add(1, Ordering::AcqRel);
debug_assert!(
prev < usize::MAX,
"cannot have more than `usize::MAX` outstanding operations on the GPU"
);
WorkToken {
work_count: Arc::clone(&self.work_count),
}
}
pub(crate) fn wake(&self) {
self.handle
.as_ref()
.expect("Poller thread does not exist!")
.thread()
.unpark();
}
pub(crate) fn lock(&self) -> MutexGuard<'_, ()> {
self.lock.lock().unwrap()
}
}
impl Drop for Poller {
fn drop(&mut self) {
self.is_done.store(true, Ordering::Release);
let handle = self.handle.take().expect("Poller dropped twice");
handle.thread().unpark();
handle.join().expect("Poller thread panicked");
}
}
pub(crate) struct WorkToken {
work_count: Arc<AtomicUsize>,
}
impl Drop for WorkToken {
fn drop(&mut self) {
self.work_count.fetch_sub(1, Ordering::AcqRel);
}
}