#[allow(unused_imports)] pub use self::commands::{
acceleration_structure::*, clear::*, copy::*, debug::*, dynamic_state::*, pipeline::*,
query::*, render_pass::*, secondary::*, sync::*,
};
pub use self::{
auto::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer, SecondaryAutoCommandBuffer},
sys::{CommandBuffer, CommandBufferBeginInfo, RecordingCommandBuffer},
traits::{
CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBufferAbstract,
SecondaryCommandBufferAbstract,
},
};
use crate::{
buffer::{Buffer, Subbuffer},
device::{Device, DeviceOwned},
format::{Format, FormatFeatures},
image::{Image, ImageAspects, ImageLayout, ImageSubresourceRange, SampleCount},
macros::vulkan_enum,
query::{QueryControlFlags, QueryPipelineStatisticFlags},
range_map::RangeMap,
render_pass::{Framebuffer, Subpass},
sync::{
semaphore::{Semaphore, SemaphoreType},
PipelineStageAccessFlags, PipelineStages,
},
DeviceSize, Requires, RequiresAllOf, RequiresOneOf, ValidationError, VulkanObject,
};
#[cfg(doc)]
use crate::{
device::{DeviceFeatures, DeviceProperties},
pipeline::graphics::vertex_input::VertexInputRate,
};
use bytemuck::{Pod, Zeroable};
use foldhash::HashMap;
use smallvec::SmallVec;
use std::{ops::Range, sync::Arc};
pub mod allocator;
pub mod auto;
mod commands;
pub mod pool;
mod sys;
mod traits;
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
pub struct DispatchIndirectCommand {
pub x: u32,
pub y: u32,
pub z: u32,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
pub struct DrawIndirectCommand {
pub vertex_count: u32,
pub instance_count: u32,
pub first_vertex: u32,
pub first_instance: u32,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
pub struct DrawMeshTasksIndirectCommand {
pub group_count_x: u32,
pub group_count_y: u32,
pub group_count_z: u32,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
pub struct DrawIndexedIndirectCommand {
pub index_count: u32,
pub instance_count: u32,
pub first_index: u32,
pub vertex_offset: u32,
pub first_instance: u32,
}
vulkan_enum! {
#[non_exhaustive]
SubpassContents = SubpassContents(i32);
Inline = INLINE,
SecondaryCommandBuffers = SECONDARY_COMMAND_BUFFERS,
}
impl From<SubpassContents> for ash::vk::RenderingFlags {
#[inline]
fn from(val: SubpassContents) -> Self {
match val {
SubpassContents::Inline => Self::empty(),
SubpassContents::SecondaryCommandBuffers => Self::CONTENTS_SECONDARY_COMMAND_BUFFERS,
}
}
}
vulkan_enum! {
CommandBufferLevel = CommandBufferLevel(i32);
Primary = PRIMARY,
Secondary = SECONDARY,
}
#[derive(Clone, Debug)]
pub struct CommandBufferInheritanceInfo {
pub render_pass: Option<CommandBufferInheritanceRenderPassType>,
pub occlusion_query: Option<QueryControlFlags>,
pub pipeline_statistics: QueryPipelineStatisticFlags,
pub _ne: crate::NonExhaustive,
}
impl Default for CommandBufferInheritanceInfo {
#[inline]
fn default() -> Self {
Self {
render_pass: None,
occlusion_query: None,
pipeline_statistics: QueryPipelineStatisticFlags::empty(),
_ne: crate::NonExhaustive(()),
}
}
}
impl CommandBufferInheritanceInfo {
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
ref render_pass,
occlusion_query,
pipeline_statistics,
_ne: _,
} = self;
if let Some(render_pass) = render_pass {
match render_pass {
CommandBufferInheritanceRenderPassType::BeginRenderPass(render_pass_info) => {
render_pass_info
.validate(device)
.map_err(|err| err.add_context("render_pass"))?;
}
CommandBufferInheritanceRenderPassType::BeginRendering(rendering_info) => {
rendering_info
.validate(device)
.map_err(|err| err.add_context("render_pass"))?;
}
}
}
if let Some(control_flags) = occlusion_query {
control_flags.validate_device(device).map_err(|err| {
err.add_context("occlusion_query")
.set_vuids(&["VUID-VkCommandBufferInheritanceInfo-queryFlags-00057"])
})?;
if !device.enabled_features().inherited_queries {
return Err(Box::new(ValidationError {
context: "occlusion_query".into(),
problem: "is `Some`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"inherited_queries",
)])]),
vuids: &["VUID-VkCommandBufferInheritanceInfo-occlusionQueryEnable-00056"],
}));
}
if control_flags.intersects(QueryControlFlags::PRECISE)
&& !device.enabled_features().occlusion_query_precise
{
return Err(Box::new(ValidationError {
context: "occlusion_query".into(),
problem: "contains `QueryControlFlags::PRECISE`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"occlusion_query_precise",
)])]),
vuids: &["VUID-vkBeginCommandBuffer-commandBuffer-00052"],
}));
}
}
pipeline_statistics.validate_device(device).map_err(|err| {
err.add_context("pipeline_statistics")
.set_vuids(&["VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-02789"])
})?;
if pipeline_statistics.count() > 0 && !device.enabled_features().pipeline_statistics_query {
return Err(Box::new(ValidationError {
context: "pipeline_statistics".into(),
problem: "is not empty".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"pipeline_statistics_query",
)])]),
vuids: &["VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-00058"],
}));
}
Ok(())
}
pub(crate) fn to_vk<'a>(
&self,
extensions_vk: &'a mut CommandBufferInheritanceInfoExtensionsVk<'_>,
) -> ash::vk::CommandBufferInheritanceInfo<'a> {
let &Self {
ref render_pass,
occlusion_query,
pipeline_statistics,
_ne: _,
} = self;
let (render_pass_vk, subpass_vk, framebuffer_vk) = render_pass
.as_ref()
.and_then(|render_pass| match render_pass {
CommandBufferInheritanceRenderPassType::BeginRenderPass(render_pass_info) => {
let &CommandBufferInheritanceRenderPassInfo {
ref subpass,
ref framebuffer,
} = render_pass_info;
Some((
subpass.render_pass().handle(),
subpass.index(),
framebuffer
.as_ref()
.map(|fb| fb.handle())
.unwrap_or_default(),
))
}
CommandBufferInheritanceRenderPassType::BeginRendering(_) => None,
})
.unwrap_or_default();
let (occlusion_query_enable, query_flags_vk) = occlusion_query
.map(|flags| (true, flags.into()))
.unwrap_or_default();
let mut val_vk = ash::vk::CommandBufferInheritanceInfo::default()
.render_pass(render_pass_vk)
.subpass(subpass_vk)
.framebuffer(framebuffer_vk)
.occlusion_query_enable(occlusion_query_enable)
.query_flags(query_flags_vk)
.pipeline_statistics(pipeline_statistics.into());
let CommandBufferInheritanceInfoExtensionsVk {
rendering_info_vk: rendering_vk,
} = extensions_vk;
if let Some(next) = rendering_vk {
val_vk = val_vk.push_next(next);
}
val_vk
}
pub(crate) fn to_vk_extensions<'a>(
&self,
fields1_vk: &'a CommandBufferInheritanceInfoFields1Vk,
) -> CommandBufferInheritanceInfoExtensionsVk<'a> {
let CommandBufferInheritanceInfoFields1Vk {
rendering_info_fields1_vk,
} = fields1_vk;
let rendering_info_vk = self
.render_pass
.as_ref()
.zip(rendering_info_fields1_vk.as_ref())
.and_then(
|(render_pass, rendering_info_fields1_vk)| match render_pass {
CommandBufferInheritanceRenderPassType::BeginRenderPass(_) => None,
CommandBufferInheritanceRenderPassType::BeginRendering(rendering_info) => {
Some(rendering_info.to_vk(rendering_info_fields1_vk))
}
},
);
CommandBufferInheritanceInfoExtensionsVk { rendering_info_vk }
}
pub(crate) fn to_vk_fields1(&self) -> CommandBufferInheritanceInfoFields1Vk {
let rendering_info_fields1_vk =
self.render_pass
.as_ref()
.and_then(|render_pass| match render_pass {
CommandBufferInheritanceRenderPassType::BeginRenderPass(_) => None,
CommandBufferInheritanceRenderPassType::BeginRendering(rendering_info) => {
Some(rendering_info.to_vk_fields1())
}
});
CommandBufferInheritanceInfoFields1Vk {
rendering_info_fields1_vk,
}
}
}
pub(crate) struct CommandBufferInheritanceInfoExtensionsVk<'a> {
pub(crate) rendering_info_vk: Option<ash::vk::CommandBufferInheritanceRenderingInfo<'a>>,
}
pub(crate) struct CommandBufferInheritanceInfoFields1Vk {
pub(crate) rendering_info_fields1_vk: Option<CommandBufferInheritanceRenderingInfoFields1Vk>,
}
#[derive(Clone, Debug)]
pub enum CommandBufferInheritanceRenderPassType {
BeginRenderPass(CommandBufferInheritanceRenderPassInfo),
BeginRendering(CommandBufferInheritanceRenderingInfo),
}
impl From<Subpass> for CommandBufferInheritanceRenderPassType {
#[inline]
fn from(val: Subpass) -> Self {
Self::BeginRenderPass(val.into())
}
}
impl From<CommandBufferInheritanceRenderPassInfo> for CommandBufferInheritanceRenderPassType {
#[inline]
fn from(val: CommandBufferInheritanceRenderPassInfo) -> Self {
Self::BeginRenderPass(val)
}
}
impl From<CommandBufferInheritanceRenderingInfo> for CommandBufferInheritanceRenderPassType {
#[inline]
fn from(val: CommandBufferInheritanceRenderingInfo) -> Self {
Self::BeginRendering(val)
}
}
#[derive(Clone, Debug)]
pub struct CommandBufferInheritanceRenderPassInfo {
pub subpass: Subpass,
pub framebuffer: Option<Arc<Framebuffer>>,
}
impl CommandBufferInheritanceRenderPassInfo {
#[inline]
pub fn subpass(subpass: Subpass) -> Self {
Self {
subpass,
framebuffer: None,
}
}
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
ref subpass,
ref framebuffer,
} = self;
assert_eq!(device, subpass.render_pass().device().as_ref());
if let Some(framebuffer) = framebuffer {
assert_eq!(device, framebuffer.device().as_ref());
if !framebuffer
.render_pass()
.is_compatible_with(subpass.render_pass())
{
return Err(Box::new(ValidationError {
problem: "`framebuffer` is not compatible with `subpass.render_pass()`".into(),
vuids: &["VUID-VkCommandBufferBeginInfo-flags-00055"],
..Default::default()
}));
}
}
Ok(())
}
}
impl From<Subpass> for CommandBufferInheritanceRenderPassInfo {
#[inline]
fn from(subpass: Subpass) -> Self {
Self {
subpass,
framebuffer: None,
}
}
}
#[derive(Clone, Debug)]
pub struct CommandBufferInheritanceRenderingInfo {
pub view_mask: u32,
pub color_attachment_formats: Vec<Option<Format>>,
pub depth_attachment_format: Option<Format>,
pub stencil_attachment_format: Option<Format>,
pub rasterization_samples: SampleCount,
}
impl Default for CommandBufferInheritanceRenderingInfo {
#[inline]
fn default() -> Self {
Self {
view_mask: 0,
color_attachment_formats: Vec::new(),
depth_attachment_format: None,
stencil_attachment_format: None,
rasterization_samples: SampleCount::Sample1,
}
}
}
impl CommandBufferInheritanceRenderingInfo {
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
view_mask,
ref color_attachment_formats,
depth_attachment_format,
stencil_attachment_format,
rasterization_samples,
} = self;
let properties = device.physical_device().properties();
if view_mask != 0 && !device.enabled_features().multiview {
return Err(Box::new(ValidationError {
context: "view_mask".into(),
problem: "is not zero".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"multiview",
)])]),
vuids: &["VUID-VkCommandBufferInheritanceRenderingInfo-multiview-06008"],
}));
}
let view_count = u32::BITS - view_mask.leading_zeros();
if view_count > properties.max_multiview_view_count.unwrap_or(0) {
return Err(Box::new(ValidationError {
context: "view_mask".into(),
problem: "the number of views exceeds the \
`max_multiview_view_count` limit"
.into(),
vuids: &["VUID-VkCommandBufferInheritanceRenderingInfo-viewMask-06009"],
..Default::default()
}));
}
for (index, format) in color_attachment_formats
.iter()
.enumerate()
.flat_map(|(i, f)| f.map(|f| (i, f)))
{
format.validate_device(device).map_err(|err| {
err.add_context(format!("color_attachment_formats[{}]", index)).set_vuids(
&["VUID-VkCommandBufferInheritanceRenderingInfo-pColorAttachmentFormats-parameter"],
)
})?;
if format == Format::UNDEFINED {
return Err(Box::new(ValidationError {
context: format!("color_attachment_formats[{}]", index).into(),
problem: "is `Format::UNDEFINED`".into(),
..Default::default()
}));
}
let format_properties =
unsafe { device.physical_device().format_properties_unchecked(format) };
let potential_format_features = format_properties.potential_format_features();
if !potential_format_features.intersects(FormatFeatures::COLOR_ATTACHMENT) {
return Err(Box::new(ValidationError {
context: format!("color_attachment_formats[{}]", index).into(),
problem: "the potential format features do not contain \
`FormatFeatures::COLOR_ATTACHMENT`".into(),
vuids: &["VUID-VkCommandBufferInheritanceRenderingInfo-pColorAttachmentFormats-06006"],
..Default::default()
}));
}
}
if let Some(format) = depth_attachment_format {
format.validate_device(device).map_err(|err| {
err.add_context("depth_attachment_format").set_vuids(&[
"VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-parameter",
])
})?;
if format == Format::UNDEFINED {
return Err(Box::new(ValidationError {
context: "depth_attachment_format".into(),
problem: "is `Format::UNDEFINED`".into(),
..Default::default()
}));
}
if !format.aspects().intersects(ImageAspects::DEPTH) {
return Err(Box::new(ValidationError {
context: "depth_attachment_format".into(),
problem: "does not have a depth aspect".into(),
vuids: &[
"VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06540",
],
..Default::default()
}));
}
let format_properties =
unsafe { device.physical_device().format_properties_unchecked(format) };
let potential_format_features = format_properties.potential_format_features();
if !potential_format_features.intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT) {
return Err(Box::new(ValidationError {
context: "depth_attachment_format".into(),
problem: "the potential format features do not contain \
`FormatFeatures::DEPTH_STENCIL_ATTACHMENT`"
.into(),
vuids: &[
"VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06007",
],
..Default::default()
}));
}
}
if let Some(format) = stencil_attachment_format {
format.validate_device(device).map_err(|err| {
err.add_context("stencil_attachment_format").set_vuids(&["VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-parameter"])
})?;
if format == Format::UNDEFINED {
return Err(Box::new(ValidationError {
context: "stencil_attachment_format".into(),
problem: "is `Format::UNDEFINED`".into(),
..Default::default()
}));
}
if !format.aspects().intersects(ImageAspects::STENCIL) {
return Err(Box::new(ValidationError {
context: "stencil_attachment_format".into(),
problem: "does not have a stencil aspect".into(),
vuids: &[
"VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-06541",
],
..Default::default()
}));
}
let format_properties =
unsafe { device.physical_device().format_properties_unchecked(format) };
let potential_format_features = format_properties.potential_format_features();
if !potential_format_features.intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT) {
return Err(Box::new(ValidationError {
context: "stencil_attachment_format".into(),
problem: "the potential format features do not contain \
`FormatFeatures::DEPTH_STENCIL_ATTACHMENT`"
.into(),
vuids: &[
"VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-06199",
],
..Default::default()
}));
}
}
if let (Some(depth_format), Some(stencil_format)) =
(depth_attachment_format, stencil_attachment_format)
{
if depth_format != stencil_format {
return Err(Box::new(ValidationError {
problem: "`depth_attachment_format` and `stencil_attachment_format` are both \
`Some`, but are not equal"
.into(),
vuids: &[
"VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06200",
],
..Default::default()
}));
}
}
rasterization_samples
.validate_device(device)
.map_err(|err| {
err.add_context("rasterization_samples").set_vuids(&[
"VUID-VkCommandBufferInheritanceRenderingInfo-rasterizationSamples-parameter",
])
})?;
Ok(())
}
pub(crate) fn to_vk<'a>(
&self,
fields1_vk: &'a CommandBufferInheritanceRenderingInfoFields1Vk,
) -> ash::vk::CommandBufferInheritanceRenderingInfo<'a> {
let &Self {
view_mask,
color_attachment_formats: _,
depth_attachment_format,
stencil_attachment_format,
rasterization_samples,
} = self;
let CommandBufferInheritanceRenderingInfoFields1Vk {
color_attachment_formats_vk,
} = fields1_vk;
ash::vk::CommandBufferInheritanceRenderingInfo::default()
.flags(ash::vk::RenderingFlags::empty())
.view_mask(view_mask)
.color_attachment_formats(color_attachment_formats_vk)
.depth_attachment_format(
depth_attachment_format.map_or(ash::vk::Format::UNDEFINED, Into::into),
)
.stencil_attachment_format(
stencil_attachment_format.map_or(ash::vk::Format::UNDEFINED, Into::into),
)
.rasterization_samples(rasterization_samples.into())
}
pub(crate) fn to_vk_fields1(&self) -> CommandBufferInheritanceRenderingInfoFields1Vk {
let Self {
color_attachment_formats,
..
} = self;
let color_attachment_formats_vk = color_attachment_formats
.iter()
.map(|format| format.map_or(ash::vk::Format::UNDEFINED, Into::into))
.collect();
CommandBufferInheritanceRenderingInfoFields1Vk {
color_attachment_formats_vk,
}
}
}
pub(crate) struct CommandBufferInheritanceRenderingInfoFields1Vk {
pub(crate) color_attachment_formats_vk: SmallVec<[ash::vk::Format; 4]>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u32)]
pub enum CommandBufferUsage {
OneTimeSubmit = ash::vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT.as_raw(),
MultipleSubmit = 0,
SimultaneousUse = ash::vk::CommandBufferUsageFlags::SIMULTANEOUS_USE.as_raw(),
}
impl From<CommandBufferUsage> for ash::vk::CommandBufferUsageFlags {
#[inline]
fn from(val: CommandBufferUsage) -> Self {
Self::from_raw(val as u32)
}
}
#[derive(Clone, Debug)]
pub struct SubmitInfo {
pub wait_semaphores: Vec<SemaphoreSubmitInfo>,
pub command_buffers: Vec<CommandBufferSubmitInfo>,
pub signal_semaphores: Vec<SemaphoreSubmitInfo>,
pub _ne: crate::NonExhaustive,
}
impl Default for SubmitInfo {
#[inline]
fn default() -> Self {
Self {
wait_semaphores: Vec::new(),
command_buffers: Vec::new(),
signal_semaphores: Vec::new(),
_ne: crate::NonExhaustive(()),
}
}
}
impl SubmitInfo {
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
ref wait_semaphores,
ref command_buffers,
ref signal_semaphores,
_ne: _,
} = self;
for (index, semaphore_submit_info) in wait_semaphores.iter().enumerate() {
semaphore_submit_info
.validate(device)
.map_err(|err| err.add_context(format!("wait_semaphores[{}]", index)))?;
}
for (index, command_buffer_submit_info) in command_buffers.iter().enumerate() {
command_buffer_submit_info
.validate(device)
.map_err(|err| err.add_context(format!("command_buffers[{}]", index)))?;
}
for (index, semaphore_submit_info) in signal_semaphores.iter().enumerate() {
semaphore_submit_info
.validate(device)
.map_err(|err| err.add_context(format!("signal_semaphores[{}]", index)))?;
let &SemaphoreSubmitInfo {
semaphore: _,
value: _,
stages,
_ne: _,
} = semaphore_submit_info;
if stages != PipelineStages::ALL_COMMANDS && !device.enabled_features().synchronization2
{
return Err(Box::new(ValidationError {
context: format!("signal_semaphores[{}].stages", index).into(),
problem: "is not `PipelineStages::ALL_COMMANDS`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"synchronization2",
)])]),
vuids: &["VUID-vkQueueSubmit2-synchronization2-03866"],
}));
}
}
Ok(())
}
pub(crate) fn to_vk2<'a>(
&self,
fields1_vk: &'a SubmitInfo2Fields1Vk,
) -> ash::vk::SubmitInfo2<'a> {
let SubmitInfo2Fields1Vk {
wait_semaphore_infos_vk,
command_buffer_infos_vk,
signal_semaphore_infos_vk,
} = fields1_vk;
ash::vk::SubmitInfo2::default()
.flags(ash::vk::SubmitFlags::empty()) .wait_semaphore_infos(wait_semaphore_infos_vk)
.command_buffer_infos(command_buffer_infos_vk)
.signal_semaphore_infos(signal_semaphore_infos_vk)
}
pub(crate) fn to_vk2_fields1(&self) -> SubmitInfo2Fields1Vk {
let &Self {
ref wait_semaphores,
ref command_buffers,
ref signal_semaphores,
_ne: _,
} = self;
SubmitInfo2Fields1Vk {
wait_semaphore_infos_vk: wait_semaphores
.iter()
.map(SemaphoreSubmitInfo::to_vk2)
.collect(),
command_buffer_infos_vk: command_buffers
.iter()
.map(CommandBufferSubmitInfo::to_vk2)
.collect(),
signal_semaphore_infos_vk: signal_semaphores
.iter()
.map(SemaphoreSubmitInfo::to_vk2)
.collect(),
}
}
pub(crate) fn to_vk<'a>(
&self,
fields1_vk: &'a SubmitInfoFields1Vk,
extensions_vk: &'a mut SubmitInfoExtensionsVk<'_>,
) -> ash::vk::SubmitInfo<'a> {
let SubmitInfoFields1Vk {
wait_semaphores_vk,
wait_dst_stage_mask_vk,
wait_semaphore_values_vk: _,
command_buffers_vk,
signal_semaphores_vk,
signal_semaphore_values_vk: _,
} = fields1_vk;
let mut val_vk = ash::vk::SubmitInfo::default()
.wait_semaphores(wait_semaphores_vk)
.wait_dst_stage_mask(wait_dst_stage_mask_vk)
.command_buffers(command_buffers_vk)
.signal_semaphores(signal_semaphores_vk);
let SubmitInfoExtensionsVk {
timeline_semaphore_vk,
} = extensions_vk;
if let Some(next) = timeline_semaphore_vk {
val_vk = val_vk.push_next(next);
}
val_vk
}
pub(crate) fn to_vk_extensions<'a>(
&self,
fields1_vk: &'a SubmitInfoFields1Vk,
) -> SubmitInfoExtensionsVk<'a> {
let Self {
wait_semaphores,
command_buffers: _,
signal_semaphores,
_ne: _,
} = self;
let SubmitInfoFields1Vk {
wait_semaphores_vk: _,
wait_dst_stage_mask_vk: _,
command_buffers_vk: _,
signal_semaphores_vk: _,
wait_semaphore_values_vk,
signal_semaphore_values_vk,
} = fields1_vk;
let timeline_semaphore_vk = (wait_semaphores.iter())
.chain(signal_semaphores.iter())
.any(|semaphore_submit_info| {
semaphore_submit_info.semaphore.semaphore_type() == SemaphoreType::Timeline
})
.then(|| {
ash::vk::TimelineSemaphoreSubmitInfo::default()
.wait_semaphore_values(wait_semaphore_values_vk)
.signal_semaphore_values(signal_semaphore_values_vk)
});
SubmitInfoExtensionsVk {
timeline_semaphore_vk,
}
}
pub(crate) fn to_vk_fields1(&self) -> SubmitInfoFields1Vk {
let Self {
wait_semaphores,
command_buffers,
signal_semaphores,
_ne: _,
} = self;
let mut wait_semaphores_vk = SmallVec::with_capacity(wait_semaphores.len());
let mut wait_dst_stage_mask_vk = SmallVec::with_capacity(wait_semaphores.len());
let mut wait_semaphore_values_vk = SmallVec::with_capacity(wait_semaphores.len());
for semaphore_submit_info in wait_semaphores {
let &SemaphoreSubmitInfo {
ref semaphore,
value,
stages,
_ne: _,
} = semaphore_submit_info;
wait_semaphores_vk.push(semaphore.handle());
wait_dst_stage_mask_vk.push(stages.into());
wait_semaphore_values_vk.push(value);
}
let command_buffers_vk = command_buffers
.iter()
.map(CommandBufferSubmitInfo::to_vk)
.collect();
let mut signal_semaphores_vk = SmallVec::with_capacity(signal_semaphores.len());
let mut signal_semaphore_values_vk = SmallVec::with_capacity(signal_semaphores.len());
for semaphore_submit_info in signal_semaphores {
let &SemaphoreSubmitInfo {
ref semaphore,
value,
stages: _,
_ne: _,
} = semaphore_submit_info;
signal_semaphores_vk.push(semaphore.handle());
signal_semaphore_values_vk.push(value);
}
SubmitInfoFields1Vk {
wait_semaphores_vk,
wait_dst_stage_mask_vk,
wait_semaphore_values_vk,
command_buffers_vk,
signal_semaphores_vk,
signal_semaphore_values_vk,
}
}
}
pub(crate) struct SubmitInfo2Fields1Vk {
pub(crate) wait_semaphore_infos_vk: SmallVec<[ash::vk::SemaphoreSubmitInfo<'static>; 4]>,
pub(crate) command_buffer_infos_vk: SmallVec<[ash::vk::CommandBufferSubmitInfo<'static>; 4]>,
pub(crate) signal_semaphore_infos_vk: SmallVec<[ash::vk::SemaphoreSubmitInfo<'static>; 4]>,
}
pub(crate) struct SubmitInfoExtensionsVk<'a> {
pub(crate) timeline_semaphore_vk: Option<ash::vk::TimelineSemaphoreSubmitInfo<'a>>,
}
pub(crate) struct SubmitInfoFields1Vk {
pub(crate) wait_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>,
pub(crate) wait_dst_stage_mask_vk: SmallVec<[ash::vk::PipelineStageFlags; 4]>,
pub(crate) wait_semaphore_values_vk: SmallVec<[u64; 4]>,
pub(crate) command_buffers_vk: SmallVec<[ash::vk::CommandBuffer; 4]>,
pub(crate) signal_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>,
pub(crate) signal_semaphore_values_vk: SmallVec<[u64; 4]>,
}
#[derive(Clone, Debug)]
pub struct CommandBufferSubmitInfo {
pub command_buffer: Arc<dyn PrimaryCommandBufferAbstract>,
pub _ne: crate::NonExhaustive,
}
impl CommandBufferSubmitInfo {
#[inline]
pub fn new(command_buffer: Arc<dyn PrimaryCommandBufferAbstract>) -> Self {
Self {
command_buffer,
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
ref command_buffer,
_ne: _,
} = self;
assert_eq!(device, command_buffer.device().as_ref());
Ok(())
}
pub(crate) fn to_vk2(&self) -> ash::vk::CommandBufferSubmitInfo<'static> {
let &Self {
ref command_buffer,
_ne: _,
} = self;
ash::vk::CommandBufferSubmitInfo::default()
.command_buffer(command_buffer.handle())
.device_mask(0) }
pub(crate) fn to_vk(&self) -> ash::vk::CommandBuffer {
let &Self {
ref command_buffer,
_ne: _,
} = self;
command_buffer.handle()
}
}
#[derive(Clone, Debug)]
pub struct SemaphoreSubmitInfo {
pub semaphore: Arc<Semaphore>,
pub value: u64,
pub stages: PipelineStages,
pub _ne: crate::NonExhaustive,
}
impl SemaphoreSubmitInfo {
#[inline]
pub fn new(semaphore: Arc<Semaphore>) -> Self {
Self {
semaphore,
value: 0,
stages: PipelineStages::ALL_COMMANDS,
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
ref semaphore,
value,
stages,
_ne: _,
} = self;
assert_eq!(device, semaphore.device().as_ref());
match semaphore.semaphore_type() {
SemaphoreType::Binary => {
if value != 0 {
return Err(Box::new(ValidationError {
problem: "`semaphore.semaphore_type()` is `SemaphoreType::Binary`, but \
`value` is not `0`"
.into(),
..Default::default()
}));
}
}
SemaphoreType::Timeline => {}
}
stages.validate_device(device).map_err(|err| {
err.add_context("stages")
.set_vuids(&["VUID-VkSemaphoreSubmitInfo-stageMask-parameter"])
})?;
if !device.enabled_features().synchronization2 && stages.contains_flags2() {
return Err(Box::new(ValidationError {
context: "stages".into(),
problem: "contains flags from `VkPipelineStageFlagBits2`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"synchronization2",
)])]),
..Default::default()
}));
}
if !device.enabled_features().geometry_shader
&& stages.intersects(PipelineStages::GEOMETRY_SHADER)
{
return Err(Box::new(ValidationError {
context: "stages".into(),
problem: "contains `PipelineStages::GEOMETRY_SHADER`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"geometry_shader",
)])]),
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03929"],
}));
}
if !device.enabled_features().tessellation_shader
&& stages.intersects(
PipelineStages::TESSELLATION_CONTROL_SHADER
| PipelineStages::TESSELLATION_EVALUATION_SHADER,
)
{
return Err(Box::new(ValidationError {
context: "stages".into(),
problem: "contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \
`PipelineStages::TESSELLATION_EVALUATION_SHADER`"
.into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"tessellation_shader",
)])]),
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03930"],
}));
}
if !device.enabled_features().conditional_rendering
&& stages.intersects(PipelineStages::CONDITIONAL_RENDERING)
{
return Err(Box::new(ValidationError {
context: "stages".into(),
problem: "contains `PipelineStages::CONDITIONAL_RENDERING`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"conditional_rendering",
)])]),
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03931"],
}));
}
if !device.enabled_features().fragment_density_map
&& stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS)
{
return Err(Box::new(ValidationError {
context: "stages".into(),
problem: "contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"fragment_density_map",
)])]),
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03932"],
}));
}
if !device.enabled_features().transform_feedback
&& stages.intersects(PipelineStages::TRANSFORM_FEEDBACK)
{
return Err(Box::new(ValidationError {
context: "stages".into(),
problem: "contains `PipelineStages::TRANSFORM_FEEDBACK`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"transform_feedback",
)])]),
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03933"],
}));
}
if !device.enabled_features().mesh_shader && stages.intersects(PipelineStages::MESH_SHADER)
{
return Err(Box::new(ValidationError {
context: "stages".into(),
problem: "contains `PipelineStages::MESH_SHADER`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"mesh_shader",
)])]),
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03934"],
}));
}
if !device.enabled_features().task_shader && stages.intersects(PipelineStages::TASK_SHADER)
{
return Err(Box::new(ValidationError {
context: "stages".into(),
problem: "contains `PipelineStages::TASK_SHADER`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"task_shader",
)])]),
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03935"],
}));
}
if !(device.enabled_features().attachment_fragment_shading_rate
|| device.enabled_features().shading_rate_image)
&& stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT)
{
return Err(Box::new(ValidationError {
context: "stages".into(),
problem: "contains `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`".into(),
requires_one_of: RequiresOneOf(&[
RequiresAllOf(&[Requires::DeviceFeature("attachment_fragment_shading_rate")]),
RequiresAllOf(&[Requires::DeviceFeature("shading_rate_image")]),
]),
vuids: &["VUID-VkMemoryBarrier2-shadingRateImage-07316"],
}));
}
if !device.enabled_features().subpass_shading
&& stages.intersects(PipelineStages::SUBPASS_SHADER)
{
return Err(Box::new(ValidationError {
context: "stages".into(),
problem: "contains `PipelineStages::SUBPASS_SHADER`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"subpass_shading",
)])]),
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-04957"],
}));
}
if !device.enabled_features().invocation_mask
&& stages.intersects(PipelineStages::INVOCATION_MASK)
{
return Err(Box::new(ValidationError {
context: "stages".into(),
problem: "contains `PipelineStages::INVOCATION_MASK`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"invocation_mask",
)])]),
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-04995"],
}));
}
if !(device.enabled_extensions().nv_ray_tracing
|| device.enabled_features().ray_tracing_pipeline)
&& stages.intersects(PipelineStages::RAY_TRACING_SHADER)
{
return Err(Box::new(ValidationError {
context: "stages".into(),
problem: "contains `PipelineStages::RAY_TRACING_SHADER`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"ray_tracing_pipeline",
)])]),
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-07946"],
}));
}
Ok(())
}
pub(crate) fn to_vk2(&self) -> ash::vk::SemaphoreSubmitInfo<'static> {
let &Self {
ref semaphore,
value,
stages,
_ne: _,
} = self;
ash::vk::SemaphoreSubmitInfo::default()
.semaphore(semaphore.handle())
.value(value)
.stage_mask(stages.into())
.device_index(0) }
}
#[derive(Debug, Default)]
pub struct CommandBufferState {
has_been_submitted: bool,
pending_submits: u32,
}
impl CommandBufferState {
pub(crate) fn has_been_submitted(&self) -> bool {
self.has_been_submitted
}
pub(crate) fn is_submit_pending(&self) -> bool {
self.pending_submits != 0
}
pub(crate) unsafe fn add_queue_submit(&mut self) {
self.has_been_submitted = true;
self.pending_submits += 1;
}
pub(crate) unsafe fn set_submit_finished(&mut self) {
self.pending_submits -= 1;
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct CommandBufferResourcesUsage {
pub(crate) buffers: Vec<CommandBufferBufferUsage>,
pub(crate) images: Vec<CommandBufferImageUsage>,
pub(crate) buffer_indices: HashMap<Arc<Buffer>, usize>,
pub(crate) image_indices: HashMap<Arc<Image>, usize>,
}
#[derive(Debug)]
pub(crate) struct CommandBufferBufferUsage {
pub(crate) buffer: Arc<Buffer>,
pub(crate) ranges: RangeMap<DeviceSize, CommandBufferBufferRangeUsage>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct CommandBufferBufferRangeUsage {
pub(crate) first_use: Option<ResourceUseRef>,
pub(crate) mutable: bool,
}
#[derive(Debug)]
pub(crate) struct CommandBufferImageUsage {
pub(crate) image: Arc<Image>,
pub(crate) ranges: RangeMap<DeviceSize, CommandBufferImageRangeUsage>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct CommandBufferImageRangeUsage {
pub(crate) first_use: Option<ResourceUseRef>,
pub(crate) mutable: bool,
pub(crate) expected_layout: ImageLayout,
pub(crate) final_layout: ImageLayout,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ResourceUseRef {
pub command_index: usize,
pub command_name: &'static str,
pub resource_in_command: ResourceInCommand,
pub secondary_use_ref: Option<SecondaryResourceUseRef>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct SecondaryResourceUseRef {
pub command_index: usize,
pub command_name: &'static str,
pub resource_in_command: ResourceInCommand,
}
impl From<ResourceUseRef> for SecondaryResourceUseRef {
#[inline]
fn from(val: ResourceUseRef) -> Self {
let ResourceUseRef {
command_index,
command_name,
resource_in_command,
secondary_use_ref,
} = val;
debug_assert!(secondary_use_ref.is_none());
SecondaryResourceUseRef {
command_index,
command_name,
resource_in_command,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ResourceInCommand {
AccelerationStructure { index: u32 },
ColorAttachment { index: u32 },
ColorResolveAttachment { index: u32 },
DepthStencilAttachment,
DepthStencilResolveAttachment,
DescriptorSet { set: u32, binding: u32, index: u32 },
Destination,
FramebufferAttachment { index: u32 },
GeometryAabbsData { index: u32 },
GeometryInstancesData,
GeometryTrianglesTransformData { index: u32 },
GeometryTrianglesIndexData { index: u32 },
GeometryTrianglesVertexData { index: u32 },
ImageMemoryBarrier { index: u32 },
IndexBuffer,
IndirectBuffer,
ScratchData,
SecondaryCommandBuffer { index: u32 },
Source,
VertexBuffer { binding: u32 },
ShaderBindingTableBuffer,
}
#[doc(hidden)]
#[derive(Debug, Default)]
pub struct SecondaryCommandBufferResourcesUsage {
pub(crate) buffers: Vec<SecondaryCommandBufferBufferUsage>,
pub(crate) images: Vec<SecondaryCommandBufferImageUsage>,
}
#[derive(Debug)]
pub(crate) struct SecondaryCommandBufferBufferUsage {
pub(crate) use_ref: ResourceUseRef,
pub(crate) buffer: Subbuffer<[u8]>,
pub(crate) range: Range<DeviceSize>,
pub(crate) memory_access: PipelineStageAccessFlags,
}
#[derive(Debug)]
pub(crate) struct SecondaryCommandBufferImageUsage {
pub(crate) use_ref: ResourceUseRef,
pub(crate) image: Arc<Image>,
pub(crate) subresource_range: ImageSubresourceRange,
pub(crate) memory_access: PipelineStageAccessFlags,
pub(crate) start_layout: ImageLayout,
pub(crate) end_layout: ImageLayout,
}