blob: 2f02da69a3c15b3bf33341194d6aad8644ca1d58 [file] [log] [blame]
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::check_errors;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::OomError;
use crate::Success;
use crate::VulkanObject;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::Arc;
/// Used to block the GPU execution until an event on the CPU occurs.
///
/// Note that Vulkan implementations may have limits on how long a command buffer will wait for an
/// event to be signaled, in order to avoid interfering with progress of other clients of the GPU.
/// If the event isn't signaled within these limits, results are undefined and may include
/// device loss.
#[derive(Debug)]
pub struct Event {
// The event.
event: ash::vk::Event,
// The device.
device: Arc<Device>,
must_put_in_pool: bool,
}
impl Event {
/// Takes an event from the vulkano-provided event pool.
/// If the pool is empty, a new event will be allocated.
/// Upon `drop`, the event is put back into the pool.
///
/// For most applications, using the event pool should be preferred,
/// in order to avoid creating new events every frame.
pub fn from_pool(device: Arc<Device>) -> Result<Event, OomError> {
let maybe_raw_event = device.event_pool().lock().unwrap().pop();
match maybe_raw_event {
Some(raw_event) => {
unsafe {
// Make sure the event isn't signaled
let fns = device.fns();
check_errors(fns.v1_0.reset_event(device.internal_object(), raw_event))?;
}
Ok(Event {
event: raw_event,
device: device,
must_put_in_pool: true,
})
}
None => {
// Pool is empty, alloc new event
Event::alloc_impl(device, true)
}
}
}
/// Builds a new event.
#[inline]
pub fn alloc(device: Arc<Device>) -> Result<Event, OomError> {
Event::alloc_impl(device, false)
}
fn alloc_impl(device: Arc<Device>, must_put_in_pool: bool) -> Result<Event, OomError> {
let event = unsafe {
let infos = ash::vk::EventCreateInfo {
flags: ash::vk::EventCreateFlags::empty(),
..Default::default()
};
let mut output = MaybeUninit::uninit();
let fns = device.fns();
check_errors(fns.v1_0.create_event(
device.internal_object(),
&infos,
ptr::null(),
output.as_mut_ptr(),
))?;
output.assume_init()
};
Ok(Event {
device: device,
event: event,
must_put_in_pool: must_put_in_pool,
})
}
/// Returns true if the event is signaled.
#[inline]
pub fn signaled(&self) -> Result<bool, OomError> {
unsafe {
let fns = self.device.fns();
let result = check_errors(
fns.v1_0
.get_event_status(self.device.internal_object(), self.event),
)?;
match result {
Success::EventSet => Ok(true),
Success::EventReset => Ok(false),
_ => unreachable!(),
}
}
}
/// See the docs of set().
#[inline]
pub fn set_raw(&mut self) -> Result<(), OomError> {
unsafe {
let fns = self.device.fns();
check_errors(
fns.v1_0
.set_event(self.device.internal_object(), self.event),
)?;
Ok(())
}
}
/// Changes the `Event` to the signaled state.
///
/// If a command buffer is waiting on this event, it is then unblocked.
///
/// # Panic
///
/// - Panics if the device or host ran out of memory.
///
#[inline]
pub fn set(&mut self) {
self.set_raw().unwrap();
}
/// See the docs of reset().
#[inline]
pub fn reset_raw(&mut self) -> Result<(), OomError> {
unsafe {
let fns = self.device.fns();
check_errors(
fns.v1_0
.reset_event(self.device.internal_object(), self.event),
)?;
Ok(())
}
}
/// Changes the `Event` to the unsignaled state.
///
/// # Panic
///
/// - Panics if the device or host ran out of memory.
///
#[inline]
pub fn reset(&mut self) {
self.reset_raw().unwrap();
}
}
unsafe impl DeviceOwned for Event {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
unsafe impl VulkanObject for Event {
type Object = ash::vk::Event;
#[inline]
fn internal_object(&self) -> ash::vk::Event {
self.event
}
}
impl Drop for Event {
#[inline]
fn drop(&mut self) {
unsafe {
if self.must_put_in_pool {
let raw_event = self.event;
self.device.event_pool().lock().unwrap().push(raw_event);
} else {
let fns = self.device.fns();
fns.v1_0
.destroy_event(self.device.internal_object(), self.event, ptr::null());
}
}
}
}
#[cfg(test)]
mod tests {
use crate::sync::Event;
use crate::VulkanObject;
#[test]
fn event_create() {
let (device, _) = gfx_dev_and_queue!();
let event = Event::alloc(device).unwrap();
assert!(!event.signaled().unwrap());
}
#[test]
fn event_set() {
let (device, _) = gfx_dev_and_queue!();
let mut event = Event::alloc(device).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::alloc(device).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().unwrap().len(), 0);
let event1_internal_obj = {
let event = Event::from_pool(device.clone()).unwrap();
assert_eq!(device.event_pool().lock().unwrap().len(), 0);
event.internal_object()
};
assert_eq!(device.event_pool().lock().unwrap().len(), 1);
let event2 = Event::from_pool(device.clone()).unwrap();
assert_eq!(device.event_pool().lock().unwrap().len(), 0);
assert_eq!(event2.internal_object(), event1_internal_obj);
}
}