use crate::core::Device;
use ash::vk;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum QueueError {
#[error("Queue submit failed: {0}")]
SubmitFailed(vk::Result),
#[error("Queue wait failed: {0}")]
WaitFailed(vk::Result),
#[error("Queue present failed: {0}")]
PresentFailed(vk::Result),
}
pub struct Queue {
queue: vk::Queue,
family_index: u32,
queue_index: u32,
}
impl Queue {
#[inline]
pub fn get(device: &Device, family_index: u32, queue_index: u32) -> Self {
let queue = unsafe { device.handle().get_device_queue(family_index, queue_index) };
Self {
queue,
family_index,
queue_index,
}
}
#[inline]
pub fn handle(&self) -> vk::Queue {
self.queue
}
#[inline]
pub fn family_index(&self) -> u32 {
self.family_index
}
#[inline]
pub fn queue_index(&self) -> u32 {
self.queue_index
}
pub fn submit(
&self,
device: &Device,
command_buffers: &[vk::CommandBuffer],
wait_semaphores: &[vk::Semaphore],
wait_stages: &[vk::PipelineStageFlags],
signal_semaphores: &[vk::Semaphore],
fence: Option<vk::Fence>,
) -> Result<(), QueueError> {
let submit_info = vk::SubmitInfo {
wait_semaphore_count: wait_semaphores.len() as u32,
p_wait_semaphores: wait_semaphores.as_ptr(),
p_wait_dst_stage_mask: wait_stages.as_ptr(),
command_buffer_count: command_buffers.len() as u32,
p_command_buffers: command_buffers.as_ptr(),
signal_semaphore_count: signal_semaphores.len() as u32,
p_signal_semaphores: signal_semaphores.as_ptr(),
..Default::default()
};
unsafe {
device
.handle()
.queue_submit(
self.queue,
&[submit_info],
fence.unwrap_or(vk::Fence::null()),
)
.map_err(QueueError::SubmitFailed)
}
}
pub fn wait_idle(&self, device: &Device) -> Result<(), QueueError> {
unsafe {
device
.handle()
.queue_wait_idle(self.queue)
.map_err(QueueError::WaitFailed)
}
}
pub fn present(
&self,
_device: &Device,
_wait_semaphores: &[vk::Semaphore],
_swapchains: &[vk::SwapchainKHR],
_image_indices: &[u32],
) -> Result<bool, QueueError> {
Err(QueueError::PresentFailed(
vk::Result::ERROR_FEATURE_NOT_PRESENT,
))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::{Device, DeviceCreateInfo, Instance, InstanceCreateInfo, QueueCreateInfo};
#[test]
fn test_queue_get() {
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();
let queue = Queue::get(&device, graphics_family, 0);
assert_eq!(queue.family_index(), graphics_family);
assert_eq!(queue.queue_index(), 0);
}
#[test]
fn test_queue_wait_idle() {
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();
let queue = Queue::get(&device, graphics_family, 0);
assert!(queue.wait_idle(&device).is_ok());
}
}