use crate::core::Device;
use ash::vk;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum FenceError {
#[error("Fence creation failed: {0}")]
CreationFailed(vk::Result),
#[error("Fence wait failed: {0}")]
WaitFailed(vk::Result),
#[error("Fence reset failed: {0}")]
ResetFailed(vk::Result),
}
#[derive(Debug, Error)]
pub enum SemaphoreError {
#[error("Semaphore creation failed: {0}")]
CreationFailed(vk::Result),
}
pub struct Fence {
fence: vk::Fence,
}
impl Fence {
pub fn new(device: &Device, signaled: bool) -> Result<Self, FenceError> {
let flags = if signaled {
vk::FenceCreateFlags::SIGNALED
} else {
vk::FenceCreateFlags::empty()
};
let create_info = vk::FenceCreateInfo {
flags,
..Default::default()
};
let fence = unsafe {
device
.handle()
.create_fence(&create_info, None)
.map_err(FenceError::CreationFailed)?
};
Ok(Self { fence })
}
#[inline]
pub fn handle(&self) -> vk::Fence {
self.fence
}
pub fn wait(&self, device: &Device, timeout: u64) -> Result<(), FenceError> {
unsafe {
device
.handle()
.wait_for_fences(&[self.fence], true, timeout)
.map_err(FenceError::WaitFailed)
}
}
pub fn reset(&self, device: &Device) -> Result<(), FenceError> {
unsafe {
device
.handle()
.reset_fences(&[self.fence])
.map_err(FenceError::ResetFailed)
}
}
pub fn destroy(&self, device: &Device) {
unsafe {
device.handle().destroy_fence(self.fence, None);
}
}
}
impl Drop for Fence {
fn drop(&mut self) {
if self.fence != vk::Fence::null() {
eprintln!("WARNING: Fence dropped without calling .destroy() - potential memory leak");
}
}
}
pub struct Semaphore {
semaphore: vk::Semaphore,
}
impl Semaphore {
pub fn new(device: &Device) -> Result<Self, SemaphoreError> {
let create_info = vk::SemaphoreCreateInfo::default();
let semaphore = unsafe {
device
.handle()
.create_semaphore(&create_info, None)
.map_err(SemaphoreError::CreationFailed)?
};
Ok(Self { semaphore })
}
#[inline]
pub fn handle(&self) -> vk::Semaphore {
self.semaphore
}
pub fn destroy(&self, device: &Device) {
unsafe {
device.handle().destroy_semaphore(self.semaphore, None);
}
}
}
impl Drop for Semaphore {
fn drop(&mut self) {
if self.semaphore != vk::Semaphore::null() {
eprintln!(
"WARNING: Semaphore dropped without calling .destroy() - potential memory leak"
);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::{Device, DeviceCreateInfo, Instance, InstanceCreateInfo, QueueCreateInfo};
fn create_test_device() -> (Instance, Device) {
let instance = Instance::new(InstanceCreateInfo {
enable_validation: false,
..Default::default()
})
.unwrap();
let physical_devices = instance.enumerate_physical_devices().unwrap();
let physical_device = physical_devices[0];
let graphics_family = unsafe {
instance
.get_physical_device_queue_family_properties(physical_device)
.iter()
.enumerate()
.find(|(_, qf)| qf.queue_flags.contains(vk::QueueFlags::GRAPHICS))
.map(|(i, _)| i as u32)
.unwrap()
};
let device = Device::new(
&instance,
physical_device,
DeviceCreateInfo {
queue_create_infos: vec![QueueCreateInfo {
queue_family_index: graphics_family,
queue_count: 1,
queue_priorities: vec![1.0],
}],
..Default::default()
},
)
.unwrap();
(instance, device)
}
#[test]
fn test_fence_creation() {
let (_instance, device) = create_test_device();
let fence = Fence::new(&device, false).unwrap();
assert_ne!(fence.handle(), vk::Fence::null());
fence.destroy(&device); }
#[test]
fn test_fence_signaled() {
let (_instance, device) = create_test_device();
let fence = Fence::new(&device, true).unwrap();
assert!(fence.wait(&device, 0).is_ok());
fence.destroy(&device);
}
#[test]
fn test_fence_reset() {
let (_instance, device) = create_test_device();
let fence = Fence::new(&device, true).unwrap();
fence.reset(&device).unwrap();
assert!(fence.wait(&device, 0).is_err());
fence.destroy(&device);
}
#[test]
fn test_semaphore_creation() {
let (_instance, device) = create_test_device();
let semaphore = Semaphore::new(&device).unwrap();
assert_ne!(semaphore.handle(), vk::Semaphore::null());
semaphore.destroy(&device); }
}