pub use self::{
auto::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer, SecondaryAutoCommandBuffer},
commands::{
acceleration_structure::*, clear::*, copy::*, debug::*, dynamic_state::*, pipeline::*,
query::*, render_pass::*, secondary::*, sync::*,
},
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, PipelineStageAccessFlags, PipelineStages},
DeviceSize, Requires, RequiresAllOf, RequiresOneOf, ValidationError,
};
use ahash::HashMap;
use bytemuck::{Pod, Zeroable};
use std::{ops::Range, sync::Arc};
pub mod allocator;
pub mod auto;
mod commands;
pub mod pool;
pub mod sys;
mod traits;
#[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 DrawIndexedIndirectCommand {
pub index_count: u32,
pub instance_count: u32,
pub first_index: u32,
pub vertex_offset: u32,
pub first_instance: u32,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
pub struct DispatchIndirectCommand {
pub x: u32,
pub y: u32,
pub z: 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 query_statistics_flags: QueryPipelineStatisticFlags,
pub _ne: crate::NonExhaustive,
}
impl Default for CommandBufferInheritanceInfo {
#[inline]
fn default() -> Self {
Self {
render_pass: None,
occlusion_query: None,
query_statistics_flags: QueryPipelineStatisticFlags::empty(),
_ne: crate::NonExhaustive(()),
}
}
}
impl CommandBufferInheritanceInfo {
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
ref render_pass,
occlusion_query,
query_statistics_flags,
_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::Feature(
"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::Feature(
"occlusion_query_precise",
)])]),
vuids: &["VUID-vkBeginCommandBuffer-commandBuffer-00052"],
}));
}
}
query_statistics_flags
.validate_device(device)
.map_err(|err| {
err.add_context("query_statistics_flags")
.set_vuids(&["VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-02789"])
})?;
if query_statistics_flags.count() > 0
&& !device.enabled_features().pipeline_statistics_query
{
return Err(Box::new(ValidationError {
context: "query_statistics_flags".into(),
problem: "is not empty".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
"pipeline_statistics_query",
)])]),
vuids: &["VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-00058"],
}));
}
Ok(())
}
}
#[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::Feature("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 potential_format_features = unsafe {
device
.physical_device()
.format_properties_unchecked(format)
.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 potential_format_features = unsafe {
device
.physical_device()
.format_properties_unchecked(format)
.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 potential_format_features = unsafe {
device
.physical_device()
.format_properties_unchecked(format)
.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(())
}
}
#[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<Arc<dyn PrimaryCommandBufferAbstract>>,
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(()),
}
}
}
#[derive(Clone, Debug)]
pub struct SemaphoreSubmitInfo {
pub semaphore: Arc<Semaphore>,
pub stages: PipelineStages,
pub _ne: crate::NonExhaustive,
}
impl SemaphoreSubmitInfo {
#[inline]
pub fn semaphore(semaphore: Arc<Semaphore>) -> Self {
Self {
semaphore,
stages: PipelineStages::ALL_COMMANDS,
_ne: crate::NonExhaustive(()),
}
}
}
#[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 },
}
#[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,
}