blob: 4d77a4ef91e26dabc08d1d2f777666c79ea9fbc0 [file] [log] [blame]
// Copyright (c) 2022 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::{
command_buffer::{
allocator::CommandBufferAllocator,
synced::{Command, SyncCommandBufferBuilder},
sys::UnsafeCommandBufferBuilder,
AutoCommandBufferBuilder,
},
device::{DeviceOwned, QueueFlags},
instance::debug::DebugUtilsLabel,
RequiresOneOf,
};
use std::{
error::Error,
ffi::CString,
fmt::{Display, Error as FmtError, Formatter},
};
/// # Commands for debugging.
///
/// These commands all require the [`ext_debug_utils`] extension to be enabled on the instance.
///
/// [`ext_debug_utils`]: crate::instance::InstanceExtensions::ext_debug_utils
impl<L, A> AutoCommandBufferBuilder<L, A>
where
A: CommandBufferAllocator,
{
/// Opens a command buffer debug label region.
pub fn begin_debug_utils_label(
&mut self,
mut label_info: DebugUtilsLabel,
) -> Result<&mut Self, DebugUtilsError> {
self.validate_begin_debug_utils_label(&mut label_info)?;
unsafe {
self.inner.begin_debug_utils_label(label_info);
}
Ok(self)
}
fn validate_begin_debug_utils_label(
&self,
_label_info: &mut DebugUtilsLabel,
) -> Result<(), DebugUtilsError> {
if !self
.device()
.instance()
.enabled_extensions()
.ext_debug_utils
{
return Err(DebugUtilsError::RequirementNotMet {
required_for: "`AutoCommandBufferBuilder::begin_debug_utils_label`",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_debug_utils"],
..Default::default()
},
});
}
let queue_family_properties = self.queue_family_properties();
// VUID-vkCmdBeginDebugUtilsLabelEXT-commandBuffer-cmdpool
if !queue_family_properties
.queue_flags
.intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
{
return Err(DebugUtilsError::NotSupportedByQueueFamily);
}
Ok(())
}
/// Closes a command buffer debug label region.
///
/// # Safety
///
/// - When submitting the command buffer, there must be an outstanding command buffer label
/// region begun with `begin_debug_utils_label` in the queue, either within this command
/// buffer or a previously submitted one.
pub unsafe fn end_debug_utils_label(&mut self) -> Result<&mut Self, DebugUtilsError> {
self.validate_end_debug_utils_label()?;
self.inner.end_debug_utils_label();
Ok(self)
}
fn validate_end_debug_utils_label(&self) -> Result<(), DebugUtilsError> {
if !self
.device()
.instance()
.enabled_extensions()
.ext_debug_utils
{
return Err(DebugUtilsError::RequirementNotMet {
required_for: "`AutoCommandBufferBuilder::end_debug_utils_label`",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_debug_utils"],
..Default::default()
},
});
}
let queue_family_properties = self.queue_family_properties();
// VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-cmdpool
if !queue_family_properties
.queue_flags
.intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
{
return Err(DebugUtilsError::NotSupportedByQueueFamily);
}
// VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-01912
// TODO: not checked, so unsafe for now
// VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-01913
// TODO: not checked, so unsafe for now
Ok(())
}
/// Inserts a command buffer debug label.
pub fn insert_debug_utils_label(
&mut self,
mut label_info: DebugUtilsLabel,
) -> Result<&mut Self, DebugUtilsError> {
self.validate_insert_debug_utils_label(&mut label_info)?;
unsafe {
self.inner.insert_debug_utils_label(label_info);
}
Ok(self)
}
fn validate_insert_debug_utils_label(
&self,
_label_info: &mut DebugUtilsLabel,
) -> Result<(), DebugUtilsError> {
if !self
.device()
.instance()
.enabled_extensions()
.ext_debug_utils
{
return Err(DebugUtilsError::RequirementNotMet {
required_for: "`AutoCommandBufferBuilder::insert_debug_utils_label`",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_debug_utils"],
..Default::default()
},
});
}
let queue_family_properties = self.queue_family_properties();
// VUID-vkCmdInsertDebugUtilsLabelEXT-commandBuffer-cmdpool
if !queue_family_properties
.queue_flags
.intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
{
return Err(DebugUtilsError::NotSupportedByQueueFamily);
}
Ok(())
}
}
impl SyncCommandBufferBuilder {
/// Calls `vkCmdBeginDebugUtilsLabelEXT` on the builder.
///
/// # Safety
/// The command pool that this command buffer was allocated from must support graphics or
/// compute operations
#[inline]
pub unsafe fn begin_debug_utils_label(&mut self, label_info: DebugUtilsLabel) {
struct Cmd {
label_info: DebugUtilsLabel,
}
impl Command for Cmd {
fn name(&self) -> &'static str {
"begin_debug_utils_label"
}
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
out.begin_debug_utils_label(&self.label_info);
}
}
self.commands.push(Box::new(Cmd { label_info }));
}
/// Calls `vkCmdEndDebugUtilsLabelEXT` on the builder.
///
/// # Safety
///
/// - The command pool that this command buffer was allocated from must support graphics or
/// compute operations
/// - There must be an outstanding `debug_marker_begin` command prior to the
/// `debug_marker_end` on the queue.
#[inline]
pub unsafe fn end_debug_utils_label(&mut self) {
struct Cmd {}
impl Command for Cmd {
fn name(&self) -> &'static str {
"end_debug_utils_label"
}
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
out.end_debug_utils_label();
}
}
self.commands.push(Box::new(Cmd {}));
}
/// Calls `vkCmdInsertDebugUtilsLabelEXT` on the builder.
///
/// # Safety
/// The command pool that this command buffer was allocated from must support graphics or
/// compute operations
#[inline]
pub unsafe fn insert_debug_utils_label(&mut self, label_info: DebugUtilsLabel) {
struct Cmd {
label_info: DebugUtilsLabel,
}
impl Command for Cmd {
fn name(&self) -> &'static str {
"insert_debug_utils_label"
}
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
out.insert_debug_utils_label(&self.label_info);
}
}
self.commands.push(Box::new(Cmd { label_info }));
}
}
impl UnsafeCommandBufferBuilder {
/// Calls `vkCmdBeginDebugUtilsLabelEXT` on the builder.
///
/// # Safety
/// The command pool that this command buffer was allocated from must support graphics or
/// compute operations
#[inline]
pub unsafe fn begin_debug_utils_label(&mut self, label_info: &DebugUtilsLabel) {
let &DebugUtilsLabel {
ref label_name,
color,
_ne: _,
} = label_info;
let label_name_vk = CString::new(label_name.as_str()).unwrap();
let label_info = ash::vk::DebugUtilsLabelEXT {
p_label_name: label_name_vk.as_ptr(),
color,
..Default::default()
};
let fns = self.device.instance().fns();
(fns.ext_debug_utils.cmd_begin_debug_utils_label_ext)(self.handle, &label_info);
}
/// Calls `vkCmdEndDebugUtilsLabelEXT` on the builder.
///
/// # Safety
/// There must be an outstanding `vkCmdBeginDebugUtilsLabelEXT` command prior to the
/// `vkQueueEndDebugUtilsLabelEXT` on the queue tha `CommandBuffer` is submitted to.
#[inline]
pub unsafe fn end_debug_utils_label(&mut self) {
let fns = self.device.instance().fns();
(fns.ext_debug_utils.cmd_end_debug_utils_label_ext)(self.handle);
}
/// Calls `vkCmdInsertDebugUtilsLabelEXT` on the builder.
///
/// # Safety
/// The command pool that this command buffer was allocated from must support graphics or
/// compute operations
#[inline]
pub unsafe fn insert_debug_utils_label(&mut self, label_info: &DebugUtilsLabel) {
let &DebugUtilsLabel {
ref label_name,
color,
_ne: _,
} = label_info;
let label_name_vk = CString::new(label_name.as_str()).unwrap();
let label_info = ash::vk::DebugUtilsLabelEXT {
p_label_name: label_name_vk.as_ptr(),
color,
..Default::default()
};
let fns = self.device.instance().fns();
(fns.ext_debug_utils.cmd_insert_debug_utils_label_ext)(self.handle, &label_info);
}
}
/// Error that can happen when recording a debug utils command.
#[derive(Clone, Debug)]
pub enum DebugUtilsError {
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The queue family doesn't allow this operation.
NotSupportedByQueueFamily,
}
impl Error for DebugUtilsError {}
impl Display for DebugUtilsError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::NotSupportedByQueueFamily => {
write!(f, "the queue family doesn't allow this operation")
}
}
}
}