use objc2::rc::Retained;
use objc2::runtime::ProtocolObject;
use objc2_metal::{MTLDevice, MTLSharedEvent};
use super::Device;
use crate::{GpuError, Result};
const SPIN: std::time::Duration = std::time::Duration::from_micros(50);
pub struct Event {
raw: Retained<ProtocolObject<dyn MTLSharedEvent>>,
}
unsafe impl Send for Event {}
unsafe impl Sync for Event {}
impl Event {
pub fn new(device: &Device) -> Result<Self> {
let raw = device
.raw()
.newSharedEvent()
.ok_or_else(|| GpuError::CommandBuffer("cannot create a shared event".into()))?;
Ok(Self { raw })
}
pub fn signal(&self, value: u64) {
self.raw.setSignaledValue(value);
}
pub fn wait(&self, value: u64, timeout: std::time::Duration) -> bool {
let spin = std::time::Instant::now();
while spin.elapsed() < SPIN.min(timeout) {
if self.value() >= value {
return true;
}
std::hint::spin_loop();
}
let ms = timeout.saturating_sub(SPIN).as_millis().max(1) as u64;
self.raw.waitUntilSignaledValue_timeoutMS(value, ms)
}
pub fn value(&self) -> u64 {
self.raw.signaledValue()
}
pub(crate) fn raw(&self) -> &ProtocolObject<dyn MTLSharedEvent> {
&self.raw
}
}
impl std::fmt::Debug for Event {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Event")
.field("value", &self.value())
.finish()
}
}