use std::ffi::CString;
use std::sync::Arc;
use erupt::vk;
#[cfg(feature = "tracing")]
use tracing1::error;
use crate::context::Context;
use crate::{
AscheError, ComputeCommandBuffer, ComputeCommandPool, Fence, GraphicsCommandBuffer,
GraphicsCommandPool, Result, TransferCommandBuffer, TransferCommandPool,
};
macro_rules! impl_queue {
(
#[doc = $doc:expr]
$queue_name:ident => $pool_name:ident, $buffer_name:ident
) => {
#[doc = $doc]
#[derive(Debug)]
pub struct $queue_name {
raw: vk::Queue,
family_index: u32,
command_pool_counter: u64,
context: Arc<Context>,
}
impl $queue_name {
pub(crate) fn new(context: Arc<Context>, family_index: u32, queue: vk::Queue) -> Self {
Self {
raw: queue,
family_index,
command_pool_counter: 0,
context,
}
}
#[inline]
pub fn raw(&self) -> vk::Queue {
self.raw
}
pub fn family_index(&self) -> u32 {
self.family_index
}
#[cfg_attr(feature = "profiling", profiling::function)]
pub unsafe fn create_command_pool(&mut self) -> Result<$pool_name> {
let counter = self.command_pool_counter;
let command_pool =
$pool_name::new(self.context.clone(), self.family_index, counter)?;
self.command_pool_counter += 1;
Ok(command_pool)
}
#[doc = "[Vulkan Manual Page](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkQueueSubmit2KHR.html)"]
#[cfg_attr(feature = "profiling", profiling::function)]
pub unsafe fn submit(&mut self, command_buffer: &$buffer_name, fence: Option<&Fence>) -> Result<()> {
let command_buffer_infos = [vk::CommandBufferSubmitInfoKHRBuilder::new()
.command_buffer(command_buffer.raw())
.device_mask(1)];
let fence = fence.map(|fence| fence.raw());
let wait_semaphore_infos: Vec<vk::SemaphoreSubmitInfoKHRBuilder> = command_buffer.wait_semaphores.iter().map(|s| s.into()).collect();
let signal_semaphore_infos: Vec<vk::SemaphoreSubmitInfoKHRBuilder> = command_buffer.signal_semaphores.iter().map(|s| s.into()).collect();
let submit_info = vk::SubmitInfo2KHRBuilder::new()
.command_buffer_infos(&command_buffer_infos)
.wait_semaphore_infos(wait_semaphore_infos.as_slice())
.signal_semaphore_infos(signal_semaphore_infos.as_slice());
self.context
.device
.queue_submit2_khr(self.raw, &[submit_info], fence)
.map_err(|err| {
#[cfg(feature = "tracing")]
error!("Unable to queue and submit a command buffer: {}", err);
AscheError::VkResult(err)
})?;
Ok(())
}
#[doc = "[Vulkan Manual Page](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkQueueSubmit2KHR.html)"]
#[cfg_attr(feature = "profiling", profiling::function)]
pub unsafe fn submit_all(&mut self, command_buffer: &[$buffer_name], fence: Option<&Fence>) -> Result<()> {
let command_buffer_infos: Vec<vk::CommandBufferSubmitInfoKHRBuilder> = command_buffer.iter().map(|cb| {
vk::CommandBufferSubmitInfoKHRBuilder::new()
.command_buffer(cb.raw())
.device_mask(1)
})
.collect();
let wait_semaphore_infos: Vec<Vec<vk::SemaphoreSubmitInfoKHRBuilder>> = command_buffer.iter().map(|cb| {
cb.wait_semaphores.iter().map(|s| s.into()).collect()
}).collect();
let signal_semaphore_infos: Vec<Vec<vk::SemaphoreSubmitInfoKHRBuilder>> = command_buffer.iter().map(|cb| {
cb.signal_semaphores.iter().map(|s| s.into()).collect()
}).collect();
let submit_infos: Vec<vk::SubmitInfo2KHRBuilder> = command_buffer.iter().enumerate().map(|(id, _)| {
vk::SubmitInfo2KHRBuilder::new()
.command_buffer_infos(&command_buffer_infos[id..id + 1])
.wait_semaphore_infos(&wait_semaphore_infos[id])
.signal_semaphore_infos(&signal_semaphore_infos[id])
})
.collect();
let fence = fence.map(|fence| fence.raw());
self.context
.device
.queue_submit2_khr(self.raw, &submit_infos, fence)
.map_err(|err| {
#[cfg(feature = "tracing")]
error!("Unable to queue and submit command buffers: {}", err);
AscheError::VkResult(err)
})?;
Ok(())
}
#[doc = "[Vulkan Manual Page](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkQueueWaitIdle.html)"]
#[cfg_attr(feature = "profiling", profiling::function)]
pub unsafe fn wait_idle(&self) -> Result<()> {
self.context.device.queue_wait_idle(self.raw).map_err(|err| {
#[cfg(feature = "tracing")]
error!("Unable to wait for the queue to become idle: {}", err);
AscheError::VkResult(err)
})
}
#[doc = "[Vulkan Manual Page](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkQueueBeginDebugUtilsLabelEXT.html)"]
#[cfg_attr(feature = "profiling", profiling::function)]
pub unsafe fn begin_debug_utils_label(&self, label: &str, color: [f32; 4]) -> Result<()> {
let label = CString::new(label.to_owned())?;
self.context.device.queue_begin_debug_utils_label_ext(
self.raw(),
&vk::DebugUtilsLabelEXTBuilder::new()
.label_name(label.as_c_str())
.color(color),
);
Ok(())
}
#[doc = "[Vulkan Manual Page](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkQueueEndDebugUtilsLabelEXT.html)"]
#[cfg_attr(feature = "profiling", profiling::function)]
pub unsafe fn end_debug_utils_label(&self) {
self.context.device.queue_end_debug_utils_label_ext(self.raw());
}
#[doc = "[Vulkan Manual Page](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkQueueInsertDebugUtilsLabelEXT.html)"]
#[cfg_attr(feature = "profiling", profiling::function)]
pub unsafe fn insert_debug_utils_label(&self, label: &str, color: [f32; 4]) -> Result<()> {
let label = CString::new(label.to_owned())?;
self.context.device.queue_insert_debug_utils_label_ext(
self.raw(),
&vk::DebugUtilsLabelEXTBuilder::new()
.label_name(label.as_c_str())
.color(color),
);
Ok(())
}
}
};
}
impl_queue!(
#[doc = "A queue for compute operations."]
ComputeQueue => ComputeCommandPool, ComputeCommandBuffer
);
impl_queue!(
#[doc = "A queue for graphics operations."]
GraphicsQueue => GraphicsCommandPool, GraphicsCommandBuffer
);
impl_queue!(
#[doc = "A queue for transfer operations."]
TransferQueue => TransferCommandPool, TransferCommandBuffer
);