use crate::{
device::{Device, DeviceOwned},
OomError, RequiresOneOf, VulkanError, VulkanObject,
};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
mem::MaybeUninit,
num::NonZeroU64,
ptr,
sync::Arc,
};
#[derive(Debug)]
pub struct Event {
handle: ash::vk::Event,
device: Arc<Device>,
id: NonZeroU64,
must_put_in_pool: bool,
}
impl Event {
#[inline]
pub fn new(device: Arc<Device>, _create_info: EventCreateInfo) -> Result<Event, EventError> {
if device.enabled_extensions().khr_portability_subset && !device.enabled_features().events {
return Err(EventError::RequirementNotMet {
required_for: "this device is a portability subset device, and `Event::new` was \
called",
requires_one_of: RequiresOneOf {
features: &["events"],
..Default::default()
},
});
}
let create_info = ash::vk::EventCreateInfo {
flags: ash::vk::EventCreateFlags::empty(),
..Default::default()
};
let handle = unsafe {
let mut output = MaybeUninit::uninit();
let fns = device.fns();
(fns.v1_0.create_event)(
device.handle(),
&create_info,
ptr::null(),
output.as_mut_ptr(),
)
.result()
.map_err(VulkanError::from)?;
output.assume_init()
};
Ok(Event {
handle,
device,
id: Self::next_id(),
must_put_in_pool: false,
})
}
#[inline]
pub fn from_pool(device: Arc<Device>) -> Result<Event, EventError> {
let handle = device.event_pool().lock().pop();
let event = match handle {
Some(handle) => {
unsafe {
let fns = device.fns();
(fns.v1_0.reset_event)(device.handle(), handle)
.result()
.map_err(VulkanError::from)?;
}
Event {
handle,
device,
id: Self::next_id(),
must_put_in_pool: true,
}
}
None => {
let mut event = Event::new(device, Default::default())?;
event.must_put_in_pool = true;
event
}
};
Ok(event)
}
#[inline]
pub unsafe fn from_handle(
device: Arc<Device>,
handle: ash::vk::Event,
_create_info: EventCreateInfo,
) -> Event {
Event {
handle,
device,
id: Self::next_id(),
must_put_in_pool: false,
}
}
#[inline]
pub fn signaled(&self) -> Result<bool, OomError> {
unsafe {
let fns = self.device.fns();
let result = (fns.v1_0.get_event_status)(self.device.handle(), self.handle);
match result {
ash::vk::Result::EVENT_SET => Ok(true),
ash::vk::Result::EVENT_RESET => Ok(false),
err => Err(VulkanError::from(err).into()),
}
}
}
#[inline]
pub fn set_raw(&mut self) -> Result<(), OomError> {
unsafe {
let fns = self.device.fns();
(fns.v1_0.set_event)(self.device.handle(), self.handle)
.result()
.map_err(VulkanError::from)?;
Ok(())
}
}
#[inline]
pub fn set(&mut self) {
self.set_raw().unwrap();
}
#[inline]
pub fn reset_raw(&mut self) -> Result<(), OomError> {
unsafe {
let fns = self.device.fns();
(fns.v1_0.reset_event)(self.device.handle(), self.handle)
.result()
.map_err(VulkanError::from)?;
Ok(())
}
}
#[inline]
pub fn reset(&mut self) {
self.reset_raw().unwrap();
}
}
impl Drop for Event {
#[inline]
fn drop(&mut self) {
unsafe {
if self.must_put_in_pool {
let raw_event = self.handle;
self.device.event_pool().lock().push(raw_event);
} else {
let fns = self.device.fns();
(fns.v1_0.destroy_event)(self.device.handle(), self.handle, ptr::null());
}
}
}
}
unsafe impl VulkanObject for Event {
type Handle = ash::vk::Event;
#[inline]
fn handle(&self) -> Self::Handle {
self.handle
}
}
unsafe impl DeviceOwned for Event {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
crate::impl_id_counter!(Event);
#[derive(Clone, Debug)]
pub struct EventCreateInfo {
pub _ne: crate::NonExhaustive,
}
impl Default for EventCreateInfo {
#[inline]
fn default() -> Self {
Self {
_ne: crate::NonExhaustive(()),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum EventError {
OomError(OomError),
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
}
impl Error for EventError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::OomError(err) => Some(err),
_ => None,
}
}
}
impl Display for EventError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::OomError(_) => write!(f, "not enough memory available"),
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
}
}
}
impl From<VulkanError> for EventError {
fn from(err: VulkanError) -> Self {
match err {
e @ VulkanError::OutOfHostMemory | e @ VulkanError::OutOfDeviceMemory => {
Self::OomError(e.into())
}
_ => panic!("unexpected error: {:?}", err),
}
}
}
#[cfg(test)]
mod tests {
use crate::{sync::Event, VulkanObject};
#[test]
fn event_create() {
let (device, _) = gfx_dev_and_queue!();
let event = Event::new(device, Default::default()).unwrap();
assert!(!event.signaled().unwrap());
}
#[test]
fn event_set() {
let (device, _) = gfx_dev_and_queue!();
let mut event = Event::new(device, Default::default()).unwrap();
assert!(!event.signaled().unwrap());
event.set();
assert!(event.signaled().unwrap());
}
#[test]
fn event_reset() {
let (device, _) = gfx_dev_and_queue!();
let mut event = Event::new(device, Default::default()).unwrap();
event.set();
assert!(event.signaled().unwrap());
event.reset();
assert!(!event.signaled().unwrap());
}
#[test]
fn event_pool() {
let (device, _) = gfx_dev_and_queue!();
assert_eq!(device.event_pool().lock().len(), 0);
let event1_internal_obj = {
let event = Event::from_pool(device.clone()).unwrap();
assert_eq!(device.event_pool().lock().len(), 0);
event.handle()
};
assert_eq!(device.event_pool().lock().len(), 1);
let event2 = Event::from_pool(device.clone()).unwrap();
assert_eq!(device.event_pool().lock().len(), 0);
assert_eq!(event2.handle(), event1_internal_obj);
}
}