use std::cell::{Cell, RefCell};
use std::rc::Rc;
use std::sync::atomic::AtomicU64;
use tracing::trace;
use super::EcsWorld;
pub(crate) static VSYNC_TICK_COUNT: AtomicU64 = AtomicU64::new(0);
pub(crate) static LAST_VSYNC_TICK: AtomicU64 = AtomicU64::new(0);
#[cfg(debug_assertions)]
pub(crate) static DEBUG_WNDPROC_TICK_COUNT: AtomicU64 = AtomicU64::new(0);
thread_local! {
static IS_TICK_FLUSH_IN_PROGRESS: Cell<bool> = const { Cell::new(false) };
}
struct TickFlushGuard;
impl Drop for TickFlushGuard {
fn drop(&mut self) {
IS_TICK_FLUSH_IN_PROGRESS.set(false);
}
}
#[allow(dead_code)]
pub(crate) fn is_tick_flush_in_progress() -> bool {
IS_TICK_FLUSH_IN_PROGRESS.get()
}
pub(crate) fn engage_tick_flush_guard() -> Option<impl Drop> {
if IS_TICK_FLUSH_IN_PROGRESS.get() {
return None;
}
IS_TICK_FLUSH_IN_PROGRESS.set(true);
Some(TickFlushGuard)
}
pub trait VsyncTick {
fn try_tick_on_vsync(&self) -> bool;
}
impl VsyncTick for Rc<RefCell<EcsWorld>> {
fn try_tick_on_vsync(&self) -> bool {
if IS_TICK_FLUSH_IN_PROGRESS.get() {
trace!("[try_tick_on_vsync] Re-entry blocked by IS_TICK_FLUSH_IN_PROGRESS");
return false;
}
IS_TICK_FLUSH_IN_PROGRESS.set(true);
let _guard = TickFlushGuard;
let result = match self.try_borrow_mut() {
Ok(mut world) => {
let result = world.try_tick_on_vsync();
#[cfg(debug_assertions)]
if result {
use std::sync::atomic::Ordering;
DEBUG_WNDPROC_TICK_COUNT.fetch_add(1, Ordering::Relaxed);
}
result
}
Err(_) => {
false
}
};
crate::ecs::window::flush_window_pos_commands();
result
}
}