Add synchronization tracking for render pass operations (#2101)

This commit is contained in:
Rua 2022-12-13 14:46:48 +01:00 committed by GitHub
parent 10d7349556
commit 79c39ecb06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1376 additions and 390 deletions

View File

@ -74,7 +74,18 @@ fn write_shader_execution(execution: &ShaderExecution) -> TokenStream {
)
}
}
ShaderExecution::Fragment => quote! { ::vulkano::shader::ShaderExecution::Fragment },
ShaderExecution::Fragment(::vulkano::shader::FragmentShaderExecution {
fragment_tests_stages,
}) => {
let fragment_tests_stages = format_ident!("{}", format!("{:?}", fragment_tests_stages));
quote! {
::vulkano::shader::ShaderExecution::Fragment(
::vulkano::shader::FragmentShaderExecution {
fragment_tests_stages: ::vulkano::shader::FragmentTestsStages::#fragment_tests_stages,
}
)
}
}
ShaderExecution::Compute => quote! { ::vulkano::shader::ShaderExecution::Compute },
ShaderExecution::RayGeneration => {
quote! { ::vulkano::shader::ShaderExecution::RayGeneration }

View File

@ -1419,7 +1419,6 @@ where
DynamicState::ShadingRateImageEnable => todo!(),
DynamicState::RepresentativeFragmentTestEnable => todo!(),
DynamicState::CoverageReductionMode => todo!(),
}
}

View File

@ -1709,7 +1709,7 @@ impl SyncCommandBufferBuilder {
ResourceUseRef {
command_index,
command_name,
resource_in_command: ResourceInCommand::DepthAttachment,
resource_in_command: ResourceInCommand::DepthStencilAttachment,
secondary_use_ref: None,
},
Resource::Image {
@ -1736,7 +1736,7 @@ impl SyncCommandBufferBuilder {
ResourceUseRef {
command_index,
command_name,
resource_in_command: ResourceInCommand::DepthResolveAttachment,
resource_in_command: ResourceInCommand::DepthStencilResolveAttachment,
secondary_use_ref: None,
},
Resource::Image {
@ -1773,7 +1773,7 @@ impl SyncCommandBufferBuilder {
ResourceUseRef {
command_index,
command_name,
resource_in_command: ResourceInCommand::StencilAttachment,
resource_in_command: ResourceInCommand::DepthStencilAttachment,
secondary_use_ref: None,
},
Resource::Image {
@ -1800,7 +1800,7 @@ impl SyncCommandBufferBuilder {
ResourceUseRef {
command_index,
command_name,
resource_in_command: ResourceInCommand::StencilResolveAttachment,
resource_in_command: ResourceInCommand::DepthStencilResolveAttachment,
secondary_use_ref: None,
},
Resource::Image {

View File

@ -592,8 +592,8 @@ impl From<ResourceUseRef> for SecondaryResourceUseRef {
pub enum ResourceInCommand {
ColorAttachment { index: u32 },
ColorResolveAttachment { index: u32 },
DepthAttachment,
DepthResolveAttachment,
DepthStencilAttachment,
DepthStencilResolveAttachment,
DescriptorSet { set: u32, binding: u32, index: u32 },
Destination,
FramebufferAttachment { index: u32 },
@ -602,8 +602,6 @@ pub enum ResourceInCommand {
IndirectBuffer,
SecondaryCommandBuffer { index: u32 },
Source,
StencilAttachment,
StencilResolveAttachment,
VertexBuffer { binding: u32 },
}

View File

@ -34,14 +34,15 @@ use crate::{
},
descriptor_set::{DescriptorSetResources, DescriptorSetWithOffsets},
device::{Device, DeviceOwned, QueueFamilyProperties, QueueFlags},
format::{Format, FormatFeatures},
image::{sys::Image, ImageAspects, ImageLayout, ImageSubresourceRange},
format::FormatFeatures,
image::{sys::Image, ImageAspects, ImageLayout, ImageSubresourceRange, ImageViewAbstract},
pipeline::{
graphics::{
color_blend::LogicOp,
depth_stencil::{CompareOp, StencilOps},
input_assembly::{IndexType, PrimitiveTopology},
rasterization::{CullMode, DepthBias, FrontFace, LineStipple},
render_pass::PipelineRenderingCreateInfo,
viewport::{Scissor, Viewport},
},
ComputePipeline, DynamicState, GraphicsPipeline, PipelineBindPoint, PipelineLayout,
@ -49,7 +50,7 @@ use crate::{
query::{QueryControlFlags, QueryType},
range_map::RangeMap,
range_set::RangeSet,
render_pass::{Framebuffer, Subpass},
render_pass::{Framebuffer, LoadOp, StoreOp, Subpass},
sync::{
BufferMemoryBarrier, DependencyInfo, ImageMemoryBarrier, PipelineStage,
PipelineStageAccess, PipelineStageAccessSet, PipelineStages,
@ -847,49 +848,48 @@ struct RenderPassState {
contents: SubpassContents,
render_area_offset: [u32; 2],
render_area_extent: [u32; 2],
rendering_info: PipelineRenderingCreateInfo,
attachments: Option<RenderPassStateAttachments>,
render_pass: RenderPassStateType,
view_mask: u32,
}
impl RenderPassState {
fn from_inheritance(render_pass: &CommandBufferInheritanceRenderPassType) -> Self {
// In a secondary command buffer, we don't know the render area yet, so use a
// dummy value.
let render_area_offset = [0, 0];
let mut render_area_extent = [u32::MAX, u32::MAX];
match render_pass {
CommandBufferInheritanceRenderPassType::BeginRenderPass(info) => {
if let Some(framebuffer) = &info.framebuffer {
// Still not exact, but it's a better upper bound.
render_area_extent = framebuffer.extent();
}
RenderPassState {
contents: SubpassContents::Inline,
render_area_offset,
render_area_extent,
render_area_offset: [0, 0],
render_area_extent: (info.framebuffer.as_ref())
// Still not exact, but it's a better upper bound.
.map_or([u32::MAX, u32::MAX], |framebuffer| framebuffer.extent()),
rendering_info: PipelineRenderingCreateInfo::from_subpass(&info.subpass),
attachments: info.framebuffer.as_ref().map(|framebuffer| {
RenderPassStateAttachments::from_subpass(&info.subpass, framebuffer)
}),
render_pass: BeginRenderPassState {
subpass: info.subpass.clone(),
framebuffer: info.framebuffer.clone(),
}
.into(),
view_mask: info.subpass.subpass_desc().view_mask,
}
}
CommandBufferInheritanceRenderPassType::BeginRendering(info) => RenderPassState {
contents: SubpassContents::Inline,
render_area_offset,
render_area_extent,
render_pass: BeginRenderingState {
render_area_offset: [0, 0],
render_area_extent: [u32::MAX, u32::MAX],
rendering_info: PipelineRenderingCreateInfo::from_inheritance_rendering_info(info),
attachments: None,
color_attachment_formats: info.color_attachment_formats.clone(),
depth_attachment_format: info.depth_attachment_format,
stencil_attachment_format: info.stencil_attachment_format,
render_pass: BeginRenderingState {
pipeline_used: false,
}
.into(),
view_mask: info.view_mask,
},
}
}
@ -920,17 +920,190 @@ struct BeginRenderPassState {
}
struct BeginRenderingState {
attachments: Option<BeginRenderingAttachments>,
color_attachment_formats: Vec<Option<Format>>,
depth_attachment_format: Option<Format>,
stencil_attachment_format: Option<Format>,
pipeline_used: bool,
}
struct BeginRenderingAttachments {
color_attachments: Vec<Option<RenderingAttachmentInfo>>,
depth_attachment: Option<RenderingAttachmentInfo>,
stencil_attachment: Option<RenderingAttachmentInfo>,
struct RenderPassStateAttachments {
color_attachments: Vec<Option<RenderPassStateAttachmentInfo>>,
depth_attachment: Option<RenderPassStateAttachmentInfo>,
stencil_attachment: Option<RenderPassStateAttachmentInfo>,
}
impl RenderPassStateAttachments {
fn from_subpass(subpass: &Subpass, framebuffer: &Framebuffer) -> Self {
let subpass_desc = subpass.subpass_desc();
let rp_attachments = subpass.render_pass().attachments();
let fb_attachments = framebuffer.attachments();
Self {
color_attachments: (subpass_desc.color_attachments.iter().enumerate())
.map(|(index, atch_ref)| {
(atch_ref.as_ref()).map(|atch_ref| RenderPassStateAttachmentInfo {
image_view: fb_attachments[atch_ref.attachment as usize].clone(),
image_layout: atch_ref.layout,
load_access: subpass
.load_op(atch_ref.attachment)
.and_then(color_load_access),
store_access: subpass
.store_op(atch_ref.attachment)
.and_then(color_store_access),
resolve_info: (subpass_desc.resolve_attachments.get(index))
.and_then(|atch_ref| atch_ref.as_ref())
.map(|atch_ref| RenderPassStateAttachmentResolveInfo {
image_view: fb_attachments[atch_ref.attachment as usize].clone(),
image_layout: atch_ref.layout,
load_access: subpass
.load_op(atch_ref.attachment)
.and_then(color_load_access),
store_access: subpass
.store_op(atch_ref.attachment)
.and_then(color_store_access),
}),
})
})
.collect(),
depth_attachment: (subpass_desc.depth_stencil_attachment.as_ref())
.filter(|atch_ref| {
(rp_attachments[atch_ref.attachment as usize].format.unwrap())
.aspects()
.intersects(ImageAspects::DEPTH)
})
.map(|atch_ref| RenderPassStateAttachmentInfo {
image_view: fb_attachments[atch_ref.attachment as usize].clone(),
image_layout: atch_ref.layout,
load_access: subpass
.load_op(atch_ref.attachment)
.and_then(depth_stencil_load_access),
store_access: subpass
.store_op(atch_ref.attachment)
.and_then(depth_stencil_store_access),
resolve_info: None,
}),
stencil_attachment: (subpass_desc.depth_stencil_attachment.as_ref())
.filter(|atch_ref| {
(rp_attachments[atch_ref.attachment as usize].format.unwrap())
.aspects()
.intersects(ImageAspects::STENCIL)
})
.map(|atch_ref| RenderPassStateAttachmentInfo {
image_view: fb_attachments[atch_ref.attachment as usize].clone(),
image_layout: atch_ref.layout,
load_access: subpass
.stencil_load_op(atch_ref.attachment)
.and_then(depth_stencil_load_access),
store_access: subpass
.stencil_store_op(atch_ref.attachment)
.and_then(depth_stencil_store_access),
resolve_info: None,
}),
}
}
fn from_rendering_info(info: &RenderingInfo) -> Self {
Self {
color_attachments: (info.color_attachments.iter())
.map(|atch_info| {
(atch_info.as_ref()).map(|atch_info| RenderPassStateAttachmentInfo {
image_view: atch_info.image_view.clone(),
image_layout: atch_info.image_layout,
load_access: color_load_access(atch_info.load_op),
store_access: color_store_access(atch_info.store_op),
resolve_info: atch_info.resolve_info.as_ref().map(|resolve_atch_info| {
RenderPassStateAttachmentResolveInfo {
image_view: resolve_atch_info.image_view.clone(),
image_layout: resolve_atch_info.image_layout,
load_access: None,
store_access: None,
}
}),
})
})
.collect(),
depth_attachment: (info.depth_attachment.as_ref()).map(|atch_info| {
RenderPassStateAttachmentInfo {
image_view: atch_info.image_view.clone(),
image_layout: atch_info.image_layout,
load_access: depth_stencil_load_access(atch_info.load_op),
store_access: depth_stencil_store_access(atch_info.store_op),
resolve_info: atch_info.resolve_info.as_ref().map(|resolve_atch_info| {
RenderPassStateAttachmentResolveInfo {
image_view: resolve_atch_info.image_view.clone(),
image_layout: resolve_atch_info.image_layout,
load_access: None,
store_access: None,
}
}),
}
}),
stencil_attachment: (info.stencil_attachment.as_ref()).map(|atch_info| {
RenderPassStateAttachmentInfo {
image_view: atch_info.image_view.clone(),
image_layout: atch_info.image_layout,
load_access: depth_stencil_load_access(atch_info.load_op),
store_access: depth_stencil_store_access(atch_info.store_op),
resolve_info: atch_info.resolve_info.as_ref().map(|resolve_atch_info| {
RenderPassStateAttachmentResolveInfo {
image_view: resolve_atch_info.image_view.clone(),
image_layout: resolve_atch_info.image_layout,
load_access: None,
store_access: None,
}
}),
}
}),
}
}
}
fn color_load_access(load_op: LoadOp) -> Option<PipelineStageAccess> {
match load_op {
LoadOp::Load => Some(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentRead),
LoadOp::Clear => Some(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite),
LoadOp::DontCare => Some(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite),
//LoadOp::None => None,
}
}
fn depth_stencil_load_access(load_op: LoadOp) -> Option<PipelineStageAccess> {
match load_op {
LoadOp::Load => Some(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentRead),
LoadOp::Clear => Some(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite),
LoadOp::DontCare => {
Some(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite)
} //LoadOp::None => None,
}
}
fn color_store_access(store_op: StoreOp) -> Option<PipelineStageAccess> {
match store_op {
StoreOp::Store => Some(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite),
StoreOp::DontCare => Some(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite),
// StoreOp::None => None,
}
}
fn depth_stencil_store_access(store_op: StoreOp) -> Option<PipelineStageAccess> {
match store_op {
StoreOp::Store => Some(PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite),
StoreOp::DontCare => {
Some(PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite)
} // StoreOp::None => None,
}
}
struct RenderPassStateAttachmentInfo {
image_view: Arc<dyn ImageViewAbstract>,
image_layout: ImageLayout,
load_access: Option<PipelineStageAccess>,
store_access: Option<PipelineStageAccess>,
resolve_info: Option<RenderPassStateAttachmentResolveInfo>,
}
struct RenderPassStateAttachmentResolveInfo {
image_view: Arc<dyn ImageViewAbstract>,
image_layout: ImageLayout,
load_access: Option<PipelineStageAccess>,
store_access: Option<PipelineStageAccess>,
}
struct DescriptorSetState {

View File

@ -8,8 +8,8 @@
// according to those terms.
use super::{
CommandBufferBuilder, DescriptorSetState, PipelineExecutionError, RenderPassState,
RenderPassStateType, ResourcesState,
CommandBufferBuilder, CommandBufferBuilderState, DescriptorSetState, PipelineExecutionError,
RenderPassState, RenderPassStateAttachmentInfo, RenderPassStateType, ResourcesState,
};
use crate::{
buffer::{view::BufferViewAbstract, BufferAccess, BufferUsage, TypedBufferAccess},
@ -21,7 +21,7 @@ use crate::{
descriptor_set::{layout::DescriptorType, DescriptorBindingResources},
device::{DeviceOwned, QueueFlags},
format::FormatFeatures,
image::{ImageAccess, ImageAspects, ImageViewAbstract, SampleCount},
image::{ImageAccess, ImageAspects, ImageSubresourceRange, ImageViewAbstract, SampleCount},
pipeline::{
graphics::{
input_assembly::{IndexType, PrimitiveTopology},
@ -32,7 +32,10 @@ use crate::{
PipelineLayout,
},
sampler::Sampler,
shader::{DescriptorBindingRequirements, ShaderScalarType, ShaderStage, ShaderStages},
shader::{
DescriptorBindingRequirements, FragmentTestsStages, ShaderScalarType, ShaderStage,
ShaderStages,
},
sync::PipelineStageAccess,
RequiresOneOf, VulkanObject,
};
@ -353,6 +356,14 @@ where
&self.builder_state.vertex_buffers,
pipeline,
);
record_subpass_attachments_access(
&mut self.resources_usage_state,
command_index,
command_name,
self.builder_state.render_pass.as_ref().unwrap(),
&self.builder_state,
pipeline,
);
if let RenderPassStateType::BeginRendering(state) =
&mut self.builder_state.render_pass.as_mut().unwrap().render_pass
@ -503,6 +514,14 @@ where
command_name,
&indirect_buffer,
);
record_subpass_attachments_access(
&mut self.resources_usage_state,
command_index,
command_name,
self.builder_state.render_pass.as_ref().unwrap(),
&self.builder_state,
pipeline,
);
if let RenderPassStateType::BeginRendering(state) =
&mut self.builder_state.render_pass.as_mut().unwrap().render_pass
@ -658,6 +677,14 @@ where
command_name,
&self.builder_state.index_buffer,
);
record_subpass_attachments_access(
&mut self.resources_usage_state,
command_index,
command_name,
self.builder_state.render_pass.as_ref().unwrap(),
&self.builder_state,
pipeline,
);
if let RenderPassStateType::BeginRendering(state) =
&mut self.builder_state.render_pass.as_mut().unwrap().render_pass
@ -822,6 +849,14 @@ where
command_name,
&indirect_buffer,
);
record_subpass_attachments_access(
&mut self.resources_usage_state,
command_index,
command_name,
self.builder_state.render_pass.as_ref().unwrap(),
&self.builder_state,
pipeline,
);
if let RenderPassStateType::BeginRendering(state) =
&mut self.builder_state.render_pass.as_mut().unwrap().render_pass
@ -1716,7 +1751,6 @@ where
DynamicState::ShadingRateImageEnable => todo!(),
DynamicState::RepresentativeFragmentTestEnable => todo!(),
DynamicState::CoverageReductionMode => todo!(),
}
}
@ -1757,33 +1791,38 @@ where
}
}
(
RenderPassStateType::BeginRendering(current_rendering_info),
RenderPassStateType::BeginRendering(_),
PipelineRenderPassType::BeginRendering(pipeline_rendering_info),
) => {
// VUID-vkCmdDraw-viewMask-06178
if pipeline_rendering_info.view_mask != render_pass_state.view_mask {
if pipeline_rendering_info.view_mask != render_pass_state.rendering_info.view_mask {
return Err(PipelineExecutionError::PipelineViewMaskMismatch {
pipeline_view_mask: pipeline_rendering_info.view_mask,
required_view_mask: render_pass_state.view_mask,
required_view_mask: render_pass_state.rendering_info.view_mask,
});
}
// VUID-vkCmdDraw-colorAttachmentCount-06179
if pipeline_rendering_info.color_attachment_formats.len()
!= current_rendering_info.color_attachment_formats.len()
!= render_pass_state
.rendering_info
.color_attachment_formats
.len()
{
return Err(
PipelineExecutionError::PipelineColorAttachmentCountMismatch {
pipeline_count: pipeline_rendering_info.color_attachment_formats.len()
as u32,
required_count: current_rendering_info.color_attachment_formats.len()
as u32,
required_count: render_pass_state
.rendering_info
.color_attachment_formats
.len() as u32,
},
);
}
for (color_attachment_index, required_format, pipeline_format) in
current_rendering_info
for (color_attachment_index, required_format, pipeline_format) in render_pass_state
.rendering_info
.color_attachment_formats
.iter()
.zip(
@ -1807,7 +1846,8 @@ where
}
}
if let Some((required_format, pipeline_format)) = current_rendering_info
if let Some((required_format, pipeline_format)) = render_pass_state
.rendering_info
.depth_attachment_format
.map(|r| (r, pipeline_rendering_info.depth_attachment_format))
{
@ -1822,7 +1862,8 @@ where
}
}
if let Some((required_format, pipeline_format)) = current_rendering_info
if let Some((required_format, pipeline_format)) = render_pass_state
.rendering_info
.stencil_attachment_format
.map(|r| (r, pipeline_rendering_info.stencil_attachment_format))
{
@ -2212,3 +2253,164 @@ fn record_indirect_buffer_access(
PipelineStageAccess::DrawIndirect_IndirectCommandRead,
);
}
fn record_subpass_attachments_access(
resources_usage_state: &mut ResourcesState,
command_index: usize,
command_name: &'static str,
render_pass_state: &RenderPassState,
builder_state: &CommandBufferBuilderState,
pipeline: &GraphicsPipeline,
) {
if Option::from(pipeline.rasterization_state().rasterizer_discard_enable)
.or(builder_state.rasterizer_discard_enable)
.unwrap()
{
return;
}
let attachments = match &render_pass_state.attachments {
Some(x) => x,
None => return,
};
if let Some(attachment_info) = attachments.depth_attachment.as_ref() {
let &RenderPassStateAttachmentInfo {
ref image_view,
image_layout,
..
} = attachment_info;
// TODO: check `pipeline.depth_stencil_state` for whether the attachment is going to be
// read and/or written.
let accesses: &'static [PipelineStageAccess] =
match pipeline.fragment_tests_stages().unwrap() {
FragmentTestsStages::Early => {
&[PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite]
}
FragmentTestsStages::Late => {
&[PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite]
}
FragmentTestsStages::EarlyAndLate => &[
PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite,
PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite,
],
};
let image = image_view.image();
let image_inner = image.inner();
let mut subresource_range = ImageSubresourceRange {
aspects: ImageAspects::DEPTH,
..image_view.subresource_range().clone()
};
subresource_range.array_layers.start += image_inner.first_layer;
subresource_range.array_layers.end += image_inner.first_layer;
subresource_range.mip_levels.start += image_inner.first_mipmap_level;
subresource_range.mip_levels.end += image_inner.first_mipmap_level;
let use_ref = ResourceUseRef {
command_index,
command_name,
resource_in_command: ResourceInCommand::DepthStencilAttachment,
secondary_use_ref: None,
};
for &access in accesses {
resources_usage_state.record_image_access(
&use_ref,
image_inner.image,
subresource_range.clone(),
access,
image_layout,
);
}
}
if let Some(attachment_info) = attachments.stencil_attachment.as_ref() {
let &RenderPassStateAttachmentInfo {
ref image_view,
image_layout,
..
} = attachment_info;
// TODO: check `pipeline.depth_stencil_state` for whether the attachment is going to be
// read and/or written.
let accesses: &'static [PipelineStageAccess] =
match pipeline.fragment_tests_stages().unwrap() {
FragmentTestsStages::Early => {
&[PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite]
}
FragmentTestsStages::Late => {
&[PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite]
}
FragmentTestsStages::EarlyAndLate => &[
PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite,
PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite,
],
};
let image = image_view.image();
let image_inner = image.inner();
let mut subresource_range = ImageSubresourceRange {
aspects: ImageAspects::STENCIL,
..image_view.subresource_range().clone()
};
subresource_range.array_layers.start += image_inner.first_layer;
subresource_range.array_layers.end += image_inner.first_layer;
subresource_range.mip_levels.start += image_inner.first_mipmap_level;
subresource_range.mip_levels.end += image_inner.first_mipmap_level;
let use_ref = ResourceUseRef {
command_index,
command_name,
resource_in_command: ResourceInCommand::DepthStencilAttachment,
secondary_use_ref: None,
};
for &access in accesses {
resources_usage_state.record_image_access(
&use_ref,
image_inner.image,
subresource_range.clone(),
access,
image_layout,
);
}
}
for (index, attachment_info) in (attachments.color_attachments.iter().enumerate())
.filter_map(|(i, a)| a.as_ref().map(|a| (i as u32, a)))
{
let &RenderPassStateAttachmentInfo {
ref image_view,
image_layout,
..
} = attachment_info;
let image = image_view.image();
let image_inner = image.inner();
let mut subresource_range = image_view.subresource_range().clone();
subresource_range.array_layers.start += image_inner.first_layer;
subresource_range.array_layers.end += image_inner.first_layer;
subresource_range.mip_levels.start += image_inner.first_mipmap_level;
subresource_range.mip_levels.end += image_inner.first_mipmap_level;
let use_ref = ResourceUseRef {
command_index,
command_name,
resource_in_command: ResourceInCommand::ColorAttachment { index },
secondary_use_ref: None,
};
// TODO: process only the color attachment indices that the fragment shader actually
// writes to.
// TODO: is it possible to only read a color attachment but not write it?
resources_usage_state.record_image_access(
&use_ref,
image_inner.image,
subresource_range,
PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite,
image_layout,
);
}
}

View File

@ -131,7 +131,9 @@ where
if let Some(render_pass_state) = &self.builder_state.render_pass {
// VUID-vkCmdBeginQuery-query-00808
if query + render_pass_state.view_mask.count_ones() > query_pool.query_count() {
if query + render_pass_state.rendering_info.view_mask.count_ones()
> query_pool.query_count()
{
return Err(QueryError::OutOfRangeMultiview);
}
}
@ -216,7 +218,9 @@ where
if let Some(render_pass_state) = &self.builder_state.render_pass {
// VUID-vkCmdEndQuery-query-00812
if query + render_pass_state.view_mask.count_ones() > query_pool.query_count() {
if query + render_pass_state.rendering_info.view_mask.count_ones()
> query_pool.query_count()
{
return Err(QueryError::OutOfRangeMultiview);
}
}
@ -448,7 +452,9 @@ where
if let Some(render_pass_state) = &self.builder_state.render_pass {
// VUID-vkCmdWriteTimestamp2-query-03865
if query + render_pass_state.view_mask.count_ones() > query_pool.query_count() {
if query + render_pass_state.rendering_info.view_mask.count_ones()
> query_pool.query_count()
{
return Err(QueryError::OutOfRangeMultiview);
}
}

View File

@ -8,16 +8,22 @@
// according to those terms.
use super::{
BeginRenderPassState, BeginRenderingAttachments, BeginRenderingState, ClearAttachment,
ClearRect, CommandBufferBuilder, RenderPassBeginInfo, RenderPassError, RenderPassState,
RenderPassStateType, RenderingAttachmentInfo, RenderingAttachmentResolveInfo, RenderingInfo,
BeginRenderPassState, BeginRenderingState, ClearAttachment, ClearRect, CommandBufferBuilder,
RenderPassBeginInfo, RenderPassError, RenderPassState, RenderPassStateAttachmentInfo,
RenderPassStateAttachmentResolveInfo, RenderPassStateAttachments, RenderPassStateType,
RenderingAttachmentInfo, RenderingAttachmentResolveInfo, RenderingInfo, ResourcesState,
};
use crate::{
command_buffer::{allocator::CommandBufferAllocator, PrimaryCommandBuffer, SubpassContents},
command_buffer::{
allocator::CommandBufferAllocator, PrimaryCommandBuffer, ResourceInCommand, ResourceUseRef,
SubpassContents,
},
device::{DeviceOwned, QueueFlags},
format::{ClearColorValue, ClearValue, NumericType},
image::{ImageAspects, ImageLayout, ImageUsage, SampleCount},
pipeline::graphics::render_pass::PipelineRenderingCreateInfo,
render_pass::{AttachmentDescription, LoadOp, ResolveMode, SubpassDescription},
sync::PipelineStageAccess,
RequiresOneOf, Version, VulkanObject,
};
use smallvec::SmallVec;
@ -443,26 +449,47 @@ where
);
}
let subpass = render_pass.clone().first_subpass();
let view_mask = subpass.subpass_desc().view_mask;
let command_index = self.next_command_index;
let command_name = "begin_render_pass";
// Advance to first subpass
{
let subpass = render_pass.clone().first_subpass();
self.builder_state.render_pass = Some(RenderPassState {
contents,
render_area_offset,
render_area_extent,
rendering_info: PipelineRenderingCreateInfo::from_subpass(&subpass),
attachments: Some(RenderPassStateAttachments::from_subpass(
&subpass,
&framebuffer,
)),
render_pass: BeginRenderPassState {
subpass,
framebuffer: Some(framebuffer.clone()),
}
.into(),
view_mask,
});
}
// Start of first subpass
{
// TODO: Apply barriers and layout transitions
let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
record_subpass_attachments_load(
&mut self.resources_usage_state,
command_index,
command_name,
render_pass_state,
);
}
self.resources.push(Box::new(render_pass));
self.resources.push(Box::new(framebuffer));
// TODO: sync state update
self.next_command_index += 1;
self
}
@ -562,6 +589,28 @@ where
(fns.v1_0.cmd_next_subpass)(self.handle(), subpass_begin_info.contents);
}
let command_index = self.next_command_index;
let command_name = "next_subpass";
// End of previous subpass
{
let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
record_subpass_attachments_resolve(
&mut self.resources_usage_state,
command_index,
command_name,
render_pass_state,
);
record_subpass_attachments_store(
&mut self.resources_usage_state,
command_index,
command_name,
render_pass_state,
);
}
// Advance to next subpass
{
let render_pass_state = self.builder_state.render_pass.as_mut().unwrap();
let begin_render_pass_state = match &mut render_pass_state.render_pass {
RenderPassStateType::BeginRenderPass(x) => x,
@ -570,15 +619,32 @@ where
begin_render_pass_state.subpass.next_subpass();
render_pass_state.contents = contents;
render_pass_state.view_mask = begin_render_pass_state.subpass.subpass_desc().view_mask;
render_pass_state.rendering_info =
PipelineRenderingCreateInfo::from_subpass(&begin_render_pass_state.subpass);
render_pass_state.attachments = Some(RenderPassStateAttachments::from_subpass(
&begin_render_pass_state.subpass,
begin_render_pass_state.framebuffer.as_ref().unwrap(),
));
if render_pass_state.view_mask != 0 {
if render_pass_state.rendering_info.view_mask != 0 {
// When multiview is enabled, at the beginning of each subpass, all
// non-render pass state is undefined.
self.builder_state = Default::default();
}
}
// TODO: sync state update
// Start of next subpass
{
// TODO: Apply barriers and layout transitions
let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
record_subpass_attachments_load(
&mut self.resources_usage_state,
command_index,
command_name,
render_pass_state,
);
}
self.next_command_index += 1;
self
@ -673,9 +739,29 @@ where
(fns.v1_0.cmd_end_render_pass)(self.handle());
}
self.builder_state.render_pass = None;
let command_index = self.next_command_index;
let command_name = "end_render_pass";
// TODO: sync state update
// End of last subpass
{
let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
record_subpass_attachments_resolve(
&mut self.resources_usage_state,
command_index,
command_name,
render_pass_state,
);
record_subpass_attachments_store(
&mut self.resources_usage_state,
command_index,
command_name,
render_pass_state,
);
}
// TODO: Apply barriers and layout transitions
self.builder_state.render_pass = None;
self.next_command_index += 1;
self
@ -1268,17 +1354,18 @@ where
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn begin_rendering_unchecked(&mut self, rendering_info: RenderingInfo) -> &mut Self {
let RenderingInfo {
{
let &RenderingInfo {
render_area_offset,
render_area_extent,
layer_count,
view_mask,
color_attachments,
depth_attachment,
stencil_attachment,
ref color_attachments,
ref depth_attachment,
ref stencil_attachment,
contents,
_ne,
} = rendering_info;
} = &rendering_info;
let map_attachment_info = |attachment_info: &Option<_>| {
if let Some(attachment_info) = attachment_info {
@ -1330,10 +1417,10 @@ where
let color_attachments_vk: SmallVec<[_; 2]> =
color_attachments.iter().map(map_attachment_info).collect();
let depth_attachment_vk = map_attachment_info(&depth_attachment);
let stencil_attachment_vk = map_attachment_info(&stencil_attachment);
let depth_attachment_vk = map_attachment_info(depth_attachment);
let stencil_attachment_vk = map_attachment_info(stencil_attachment);
let rendering_info = ash::vk::RenderingInfo {
let rendering_info_vk = ash::vk::RenderingInfo {
flags: contents.into(),
render_area: ash::vk::Rect2D {
offset: ash::vk::Offset2D {
@ -1357,37 +1444,38 @@ where
let fns = self.device().fns();
if self.device().api_version() >= Version::V1_3 {
(fns.v1_3.cmd_begin_rendering)(self.handle(), &rendering_info);
(fns.v1_3.cmd_begin_rendering)(self.handle(), &rendering_info_vk);
} else {
debug_assert!(self.device().enabled_extensions().khr_dynamic_rendering);
(fns.khr_dynamic_rendering.cmd_begin_rendering_khr)(self.handle(), &rendering_info);
(fns.khr_dynamic_rendering.cmd_begin_rendering_khr)(
self.handle(),
&rendering_info_vk,
);
}
self.builder_state.render_pass = Some(RenderPassState {
contents,
render_area_offset,
render_area_extent,
rendering_info: PipelineRenderingCreateInfo::from_rendering_info(&rendering_info),
attachments: Some(RenderPassStateAttachments::from_rendering_info(
&rendering_info,
)),
render_pass: BeginRenderingState {
attachments: Some(BeginRenderingAttachments {
color_attachments: color_attachments.clone(),
depth_attachment: depth_attachment.clone(),
stencil_attachment: stencil_attachment.clone(),
}),
color_attachment_formats: color_attachments
.iter()
.map(|a| a.as_ref().map(|a| a.image_view.format().unwrap()))
.collect(),
depth_attachment_format: depth_attachment
.as_ref()
.map(|a| a.image_view.format().unwrap()),
stencil_attachment_format: stencil_attachment
.as_ref()
.map(|a| a.image_view.format().unwrap()),
pipeline_used: false,
}
.into(),
view_mask,
});
}
let RenderingInfo {
color_attachments,
depth_attachment,
stencil_attachment,
..
} = rendering_info;
for attachment_info in color_attachments.into_iter().flatten() {
let RenderingAttachmentInfo {
@ -1461,8 +1549,6 @@ where
}
}
// TODO: sync state update
self.next_command_index += 1;
self
}
@ -1525,9 +1611,24 @@ where
(fns.khr_dynamic_rendering.cmd_end_rendering_khr)(self.handle());
}
self.builder_state.render_pass = None;
let command_index = self.next_command_index;
let command_name = "end_rendering";
let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
// TODO: sync state update
record_subpass_attachments_resolve(
&mut self.resources_usage_state,
command_index,
command_name,
render_pass_state,
);
record_subpass_attachments_store(
&mut self.resources_usage_state,
command_index,
command_name,
render_pass_state,
);
self.builder_state.render_pass = None;
self.next_command_index += 1;
self
@ -1587,7 +1688,7 @@ where
//let subpass_desc = begin_render_pass_state.subpass.subpass_desc();
//let render_pass = begin_render_pass_state.subpass.render_pass();
let is_multiview = render_pass_state.view_mask != 0;
let is_multiview = render_pass_state.rendering_info.view_mask != 0;
let mut layer_count = u32::MAX;
for &clear_attachment in attachments {
@ -1596,31 +1697,17 @@ where
color_attachment,
clear_value,
} => {
let attachment_format = match &render_pass_state.render_pass {
RenderPassStateType::BeginRenderPass(state) => {
let color_attachments = &state.subpass.subpass_desc().color_attachments;
let atch_ref = color_attachments.get(color_attachment as usize).ok_or(
RenderPassError::ColorAttachmentIndexOutOfRange {
color_attachment_index: color_attachment,
num_color_attachments: color_attachments.len() as u32,
},
)?;
atch_ref.as_ref().map(|atch_ref| {
state.subpass.render_pass().attachments()
[atch_ref.attachment as usize]
.format
.unwrap()
})
}
RenderPassStateType::BeginRendering(state) => *state
let attachment_format = *render_pass_state
.rendering_info
.color_attachment_formats
.get(color_attachment as usize)
.ok_or(RenderPassError::ColorAttachmentIndexOutOfRange {
color_attachment_index: color_attachment,
num_color_attachments: state.color_attachment_formats.len() as u32,
})?,
};
num_color_attachments: render_pass_state
.rendering_info
.color_attachment_formats
.len() as u32,
})?;
// VUID-vkCmdClearAttachments-aspectMask-02501
if !attachment_format.map_or(false, |format| {
@ -1645,24 +1732,13 @@ where
});
}
let image_view = match &render_pass_state.render_pass {
RenderPassStateType::BeginRenderPass(state) => (state.framebuffer.as_ref())
.zip(
state.subpass.subpass_desc().color_attachments
[color_attachment as usize]
.as_ref(),
)
.map(|(framebuffer, atch_ref)| {
&framebuffer.attachments()[atch_ref.attachment as usize]
}),
RenderPassStateType::BeginRendering(state) => state
let image_view = render_pass_state
.attachments
.as_ref()
.and_then(|attachments| {
attachments.color_attachments[color_attachment as usize].as_ref()
})
.map(|attachment_info| &attachment_info.image_view),
};
.map(|attachment_info| &attachment_info.image_view);
// We only know the layer count if we have a known attachment image.
if let Some(image_view) = image_view {
@ -1673,24 +1749,8 @@ where
ClearAttachment::Depth(_)
| ClearAttachment::Stencil(_)
| ClearAttachment::DepthStencil(_) => {
let (depth_format, stencil_format) = match &render_pass_state.render_pass {
RenderPassStateType::BeginRenderPass(state) => state
.subpass
.subpass_desc()
.depth_stencil_attachment
.as_ref()
.map_or((None, None), |atch_ref| {
let format = state.subpass.render_pass().attachments()
[atch_ref.attachment as usize]
.format
.unwrap();
(Some(format), Some(format))
}),
RenderPassStateType::BeginRendering(state) => (
state.depth_attachment_format,
state.stencil_attachment_format,
),
};
let depth_format = render_pass_state.rendering_info.depth_attachment_format;
let stencil_format = render_pass_state.rendering_info.stencil_attachment_format;
// VUID-vkCmdClearAttachments-aspectMask-02502
if matches!(
@ -1718,24 +1778,11 @@ where
});
}
let image_view = match &render_pass_state.render_pass {
RenderPassStateType::BeginRenderPass(state) => (state.framebuffer.as_ref())
.zip(
state
.subpass
.subpass_desc()
.depth_stencil_attachment
.as_ref(),
)
.map(|(framebuffer, atch_ref)| {
&framebuffer.attachments()[atch_ref.attachment as usize]
}),
RenderPassStateType::BeginRendering(state) => state
let image_view = render_pass_state
.attachments
.as_ref()
.and_then(|attachments| attachments.depth_attachment.as_ref())
.map(|attachment_info| &attachment_info.image_view),
};
.map(|attachment_info| &attachment_info.image_view);
// We only know the layer count if we have a known attachment image.
if let Some(image_view) = image_view {
@ -1838,3 +1885,364 @@ where
self
}
}
fn record_subpass_attachments_resolve(
resources_usage_state: &mut ResourcesState,
command_index: usize,
command_name: &'static str,
render_pass_state: &RenderPassState,
) {
let attachments = render_pass_state.attachments.as_ref().unwrap();
let record_attachment = |resources_usage_state: &mut ResourcesState,
attachment_info,
aspects_override,
resource_in_command,
resolve_resource_in_command| {
let &RenderPassStateAttachmentInfo {
ref image_view,
image_layout,
ref resolve_info,
..
} = attachment_info;
let image = image_view.image();
let image_inner = image.inner();
let mut subresource_range = image_view.subresource_range().clone();
subresource_range.array_layers.start += image_inner.first_layer;
subresource_range.array_layers.end += image_inner.first_layer;
subresource_range.mip_levels.start += image_inner.first_mipmap_level;
subresource_range.mip_levels.end += image_inner.first_mipmap_level;
if let Some(aspects) = aspects_override {
subresource_range.aspects = aspects;
}
let use_ref = ResourceUseRef {
command_index,
command_name,
resource_in_command,
secondary_use_ref: None,
};
if let Some(resolve_info) = resolve_info {
let &RenderPassStateAttachmentResolveInfo {
image_view: ref resolve_image_view,
image_layout: resolve_image_layout,
..
} = resolve_info;
let resolve_image = resolve_image_view.image();
let resolve_image_inner = resolve_image.inner();
let mut resolve_subresource_range = resolve_image_view.subresource_range().clone();
resolve_subresource_range.array_layers.start += resolve_image_inner.first_layer;
resolve_subresource_range.array_layers.end += resolve_image_inner.first_layer;
resolve_subresource_range.mip_levels.start += resolve_image_inner.first_mipmap_level;
resolve_subresource_range.mip_levels.end += resolve_image_inner.first_mipmap_level;
if let Some(aspects) = aspects_override {
resolve_subresource_range.aspects = aspects;
}
let resolve_use_ref = ResourceUseRef {
command_index,
command_name,
resource_in_command: resolve_resource_in_command,
secondary_use_ref: None,
};
// The resolve operation uses the stages/access for color attachments,
// even for depth/stencil attachments.
resources_usage_state.record_image_access(
&use_ref,
image_inner.image,
subresource_range,
PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentRead,
image_layout,
);
resources_usage_state.record_image_access(
&resolve_use_ref,
resolve_image_inner.image,
resolve_subresource_range,
PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite,
resolve_image_layout,
);
}
};
if let Some(attachment_info) = attachments.depth_attachment.as_ref() {
record_attachment(
resources_usage_state,
attachment_info,
Some(ImageAspects::DEPTH),
ResourceInCommand::DepthStencilAttachment,
ResourceInCommand::DepthStencilResolveAttachment,
);
}
if let Some(attachment_info) = attachments.stencil_attachment.as_ref() {
record_attachment(
resources_usage_state,
attachment_info,
Some(ImageAspects::STENCIL),
ResourceInCommand::DepthStencilAttachment,
ResourceInCommand::DepthStencilResolveAttachment,
);
}
for (index, attachment_info) in (attachments.color_attachments.iter().enumerate())
.filter_map(|(i, a)| a.as_ref().map(|a| (i as u32, a)))
{
record_attachment(
resources_usage_state,
attachment_info,
None,
ResourceInCommand::ColorAttachment { index },
ResourceInCommand::ColorResolveAttachment { index },
);
}
}
fn record_subpass_attachments_store(
resources_usage_state: &mut ResourcesState,
command_index: usize,
command_name: &'static str,
render_pass_state: &RenderPassState,
) {
let attachments = render_pass_state.attachments.as_ref().unwrap();
let record_attachment = |resources_usage_state: &mut ResourcesState,
attachment_info,
aspects_override,
resource_in_command,
resolve_resource_in_command| {
let &RenderPassStateAttachmentInfo {
ref image_view,
image_layout,
store_access,
ref resolve_info,
..
} = attachment_info;
if let Some(access) = store_access {
let image = image_view.image();
let image_inner = image.inner();
let mut subresource_range = image_view.subresource_range().clone();
subresource_range.array_layers.start += image_inner.first_layer;
subresource_range.array_layers.end += image_inner.first_layer;
subresource_range.mip_levels.start += image_inner.first_mipmap_level;
subresource_range.mip_levels.end += image_inner.first_mipmap_level;
if let Some(aspects) = aspects_override {
subresource_range.aspects = aspects;
}
let use_ref = ResourceUseRef {
command_index,
command_name,
resource_in_command,
secondary_use_ref: None,
};
resources_usage_state.record_image_access(
&use_ref,
image_inner.image,
subresource_range,
access,
image_layout,
);
}
if let Some(resolve_info) = resolve_info {
let &RenderPassStateAttachmentResolveInfo {
ref image_view,
image_layout,
store_access,
..
} = resolve_info;
if let Some(access) = store_access {
let image = image_view.image();
let image_inner = image.inner();
let mut subresource_range = image_view.subresource_range().clone();
subresource_range.array_layers.start += image_inner.first_layer;
subresource_range.array_layers.end += image_inner.first_layer;
subresource_range.mip_levels.start += image_inner.first_mipmap_level;
subresource_range.mip_levels.end += image_inner.first_mipmap_level;
if let Some(aspects) = aspects_override {
subresource_range.aspects = aspects;
}
let use_ref = ResourceUseRef {
command_index,
command_name,
resource_in_command: resolve_resource_in_command,
secondary_use_ref: None,
};
resources_usage_state.record_image_access(
&use_ref,
image_inner.image,
subresource_range,
access,
image_layout,
);
}
}
};
if let Some(attachment_info) = attachments.depth_attachment.as_ref() {
record_attachment(
resources_usage_state,
attachment_info,
Some(ImageAspects::DEPTH),
ResourceInCommand::DepthStencilAttachment,
ResourceInCommand::DepthStencilResolveAttachment,
);
}
if let Some(attachment_info) = attachments.stencil_attachment.as_ref() {
record_attachment(
resources_usage_state,
attachment_info,
Some(ImageAspects::STENCIL),
ResourceInCommand::DepthStencilAttachment,
ResourceInCommand::DepthStencilResolveAttachment,
);
}
for (index, attachment_info) in (attachments.color_attachments.iter().enumerate())
.filter_map(|(i, a)| a.as_ref().map(|a| (i as u32, a)))
{
record_attachment(
resources_usage_state,
attachment_info,
None,
ResourceInCommand::ColorAttachment { index },
ResourceInCommand::ColorResolveAttachment { index },
);
}
}
fn record_subpass_attachments_load(
resources_usage_state: &mut ResourcesState,
command_index: usize,
command_name: &'static str,
render_pass_state: &RenderPassState,
) {
let attachments = render_pass_state.attachments.as_ref().unwrap();
let record_attachment = |resources_usage_state: &mut ResourcesState,
attachment_info,
aspects_override,
resource_in_command,
resolve_resource_in_command| {
let &RenderPassStateAttachmentInfo {
ref image_view,
image_layout,
load_access,
ref resolve_info,
..
} = attachment_info;
if let Some(access) = load_access {
let image = image_view.image();
let image_inner = image.inner();
let mut subresource_range = image_view.subresource_range().clone();
subresource_range.array_layers.start += image_inner.first_layer;
subresource_range.array_layers.end += image_inner.first_layer;
subresource_range.mip_levels.start += image_inner.first_mipmap_level;
subresource_range.mip_levels.end += image_inner.first_mipmap_level;
if let Some(aspects) = aspects_override {
subresource_range.aspects = aspects;
}
let use_ref = ResourceUseRef {
command_index,
command_name,
resource_in_command,
secondary_use_ref: None,
};
resources_usage_state.record_image_access(
&use_ref,
image_inner.image,
subresource_range,
access,
image_layout,
);
}
if let Some(resolve_info) = resolve_info {
let &RenderPassStateAttachmentResolveInfo {
ref image_view,
image_layout,
load_access,
..
} = resolve_info;
if let Some(access) = load_access {
let image = image_view.image();
let image_inner = image.inner();
let mut subresource_range = image_view.subresource_range().clone();
subresource_range.array_layers.start += image_inner.first_layer;
subresource_range.array_layers.end += image_inner.first_layer;
subresource_range.mip_levels.start += image_inner.first_mipmap_level;
subresource_range.mip_levels.end += image_inner.first_mipmap_level;
if let Some(aspects) = aspects_override {
subresource_range.aspects = aspects;
}
let use_ref = ResourceUseRef {
command_index,
command_name,
resource_in_command: resolve_resource_in_command,
secondary_use_ref: None,
};
resources_usage_state.record_image_access(
&use_ref,
image_inner.image,
subresource_range,
access,
image_layout,
);
}
}
};
if let Some(attachment_info) = attachments.depth_attachment.as_ref() {
record_attachment(
resources_usage_state,
attachment_info,
Some(ImageAspects::DEPTH),
ResourceInCommand::DepthStencilAttachment,
ResourceInCommand::DepthStencilResolveAttachment,
);
}
if let Some(attachment_info) = attachments.stencil_attachment.as_ref() {
record_attachment(
resources_usage_state,
attachment_info,
Some(ImageAspects::STENCIL),
ResourceInCommand::DepthStencilAttachment,
ResourceInCommand::DepthStencilResolveAttachment,
);
}
for (index, attachment_info) in (attachments.color_attachments.iter().enumerate())
.filter_map(|(i, a)| a.as_ref().map(|a| (i as u32, a)))
{
record_attachment(
resources_usage_state,
attachment_info,
None,
ResourceInCommand::ColorAttachment { index },
ResourceInCommand::ColorResolveAttachment { index },
);
}
}

View File

@ -120,10 +120,10 @@ where
}
}
(
RenderPassStateType::BeginRendering(state),
RenderPassStateType::BeginRendering(_),
CommandBufferInheritanceRenderPassType::BeginRendering(inheritance_info),
) => {
let attachments = state.attachments.as_ref().unwrap();
let attachments = render_pass_state.attachments.as_ref().unwrap();
// VUID-vkCmdExecuteCommands-colorAttachmentCount-06027
if inheritance_info.color_attachment_formats.len()
@ -230,10 +230,10 @@ where
}
// VUID-vkCmdExecuteCommands-viewMask-06031
if inheritance_info.view_mask != render_pass_state.view_mask {
if inheritance_info.view_mask != render_pass_state.rendering_info.view_mask {
return Err(ExecuteCommandsError::RenderPassViewMaskMismatch {
command_buffer_index,
required_view_mask: render_pass_state.view_mask,
required_view_mask: render_pass_state.rendering_info.view_mask,
inherited_view_mask: inheritance_info.view_mask,
});
}

View File

@ -47,8 +47,8 @@ use crate::{
DynamicState, PartialStateMode, PipelineLayout, StateMode,
},
shader::{
DescriptorBindingRequirements, EntryPoint, ShaderExecution, ShaderStage,
SpecializationConstants, SpecializationMapEntry,
DescriptorBindingRequirements, EntryPoint, FragmentShaderExecution, FragmentTestsStages,
ShaderExecution, ShaderStage, SpecializationConstants, SpecializationMapEntry,
},
DeviceSize, RequiresOneOf, Version, VulkanError, VulkanObject,
};
@ -364,16 +364,18 @@ where
self.validate_create(&device, &pipeline_layout, &vertex_input_state, has)?;
let (handle, descriptor_requirements, dynamic_state, shaders) =
let (handle, descriptor_requirements, dynamic_state, shaders, fragment_tests_stages) =
unsafe { self.record_create(&device, &pipeline_layout, &vertex_input_state, has)? };
let Self {
mut render_pass,
cache: _,
vertex_shader: _,
tessellation_shaders: _,
geometry_shader: _,
fragment_shader: _,
vertex_input_state: _,
input_assembly_state,
tessellation_state,
@ -398,9 +400,12 @@ where
id: GraphicsPipeline::next_id(),
layout: pipeline_layout,
render_pass: render_pass.take().expect("Missing render pass"),
shaders,
descriptor_binding_requirements: descriptor_requirements,
num_used_descriptor_sets,
fragment_tests_stages,
vertex_input_state, // Can be None if there's a mesh shader, but we don't support that yet
input_assembly_state, // Can be None if there's a mesh shader, but we don't support that yet
tessellation_state: has.tessellation_state.then_some(tessellation_state),
@ -1845,7 +1850,7 @@ where
});
match entry_point.execution() {
ShaderExecution::Fragment => (),
ShaderExecution::Fragment(_) => (),
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
}
@ -2540,6 +2545,7 @@ where
HashMap<(u32, u32), DescriptorBindingRequirements>,
HashMap<DynamicState, bool>,
HashMap<ShaderStage, ()>,
Option<FragmentTestsStages>,
),
GraphicsPipelineCreationError,
> {
@ -2572,6 +2578,7 @@ where
let mut dynamic_state: HashMap<DynamicState, bool> = HashMap::default();
let mut stages = HashMap::default();
let mut stages_vk: SmallVec<[_; 5]> = SmallVec::new();
let mut fragment_tests_stages = None;
/*
Render pass
@ -3249,6 +3256,13 @@ where
p_specialization_info: specialization_info_vk as *const _,
..Default::default()
});
fragment_tests_stages = match entry_point.execution() {
ShaderExecution::Fragment(FragmentShaderExecution {
fragment_tests_stages,
..
}) => Some(*fragment_tests_stages),
_ => unreachable!(),
};
}
}
@ -3700,6 +3714,7 @@ where
descriptor_binding_requirements,
dynamic_state,
stages,
fragment_tests_stages,
))
}

View File

@ -67,7 +67,7 @@ use self::{
use super::{DynamicState, Pipeline, PipelineBindPoint, PipelineLayout};
use crate::{
device::{Device, DeviceOwned},
shader::{DescriptorBindingRequirements, ShaderStage},
shader::{DescriptorBindingRequirements, FragmentTestsStages, ShaderStage},
VulkanObject,
};
use ahash::HashMap;
@ -108,6 +108,7 @@ pub struct GraphicsPipeline {
shaders: HashMap<ShaderStage, ()>,
descriptor_binding_requirements: HashMap<(u32, u32), DescriptorBindingRequirements>,
num_used_descriptor_sets: u32,
fragment_tests_stages: Option<FragmentTestsStages>,
vertex_input_state: VertexInputState,
input_assembly_state: InputAssemblyState,
@ -233,6 +234,12 @@ impl GraphicsPipeline {
pub fn dynamic_states(&self) -> impl ExactSizeIterator<Item = (DynamicState, bool)> + '_ {
self.dynamic_state.iter().map(|(k, v)| (*k, *v))
}
/// If the pipeline has a fragment shader, returns the fragment tests stages used.
#[inline]
pub fn fragment_tests_stages(&self) -> Option<FragmentTestsStages> {
self.fragment_tests_stages
}
}
impl Pipeline for GraphicsPipeline {

View File

@ -7,7 +7,12 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::{format::Format, render_pass::Subpass};
use crate::{
command_buffer::{CommandBufferInheritanceRenderingInfo, RenderingInfo},
format::Format,
image::ImageAspects,
render_pass::Subpass,
};
/// Selects the type of render pass that a graphics pipeline is created for.
#[derive(Clone, Debug)]
@ -79,3 +84,58 @@ impl Default for PipelineRenderingCreateInfo {
}
}
}
impl PipelineRenderingCreateInfo {
pub(crate) fn from_subpass(subpass: &Subpass) -> Self {
let subpass_desc = subpass.subpass_desc();
let rp_attachments = subpass.render_pass().attachments();
Self {
view_mask: subpass_desc.view_mask,
color_attachment_formats: (subpass_desc.color_attachments.iter())
.map(|atch_ref| {
atch_ref.as_ref().map(|atch_ref| {
rp_attachments[atch_ref.attachment as usize].format.unwrap()
})
})
.collect(),
depth_attachment_format: (subpass_desc.depth_stencil_attachment.as_ref())
.map(|atch_ref| rp_attachments[atch_ref.attachment as usize].format.unwrap())
.filter(|format| format.aspects().intersects(ImageAspects::DEPTH)),
stencil_attachment_format: (subpass_desc.depth_stencil_attachment.as_ref())
.map(|atch_ref| rp_attachments[atch_ref.attachment as usize].format.unwrap())
.filter(|format| format.aspects().intersects(ImageAspects::STENCIL)),
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn from_rendering_info(info: &RenderingInfo) -> Self {
Self {
view_mask: info.view_mask,
color_attachment_formats: (info.color_attachments.iter())
.map(|atch_info| {
atch_info
.as_ref()
.map(|atch_info| atch_info.image_view.format().unwrap())
})
.collect(),
depth_attachment_format: (info.depth_attachment.as_ref())
.map(|atch_info| atch_info.image_view.format().unwrap()),
stencil_attachment_format: (info.stencil_attachment.as_ref())
.map(|atch_info| atch_info.image_view.format().unwrap()),
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn from_inheritance_rendering_info(
info: &CommandBufferInheritanceRenderingInfo,
) -> Self {
Self {
view_mask: info.view_mask,
color_attachment_formats: info.color_attachment_formats.clone(),
depth_attachment_format: info.depth_attachment_format,
stencil_attachment_format: info.stencil_attachment_format,
_ne: crate::NonExhaustive(()),
}
}
}

View File

@ -426,6 +426,7 @@ pub enum StateMode<F> {
/// The pipeline has a fixed value for this state. Previously set dynamic state will be lost
/// when binding it, and will have to be re-set after binding a pipeline that uses it.
Fixed(F),
/// The pipeline expects a dynamic value to be set by a command buffer. Previously set dynamic
/// state is not disturbed when binding it.
Dynamic,

View File

@ -30,7 +30,7 @@ impl RenderPass {
pub(super) fn validate(
device: &Device,
create_info: &mut RenderPassCreateInfo,
) -> Result<u32, RenderPassCreationError> {
) -> Result<(), RenderPassCreationError> {
let properties = device.physical_device().properties();
let RenderPassCreateInfo {
@ -41,8 +41,6 @@ impl RenderPass {
_ne: _,
} = create_info;
let mut views_used = 0;
/*
Attachments
*/
@ -191,8 +189,6 @@ impl RenderPass {
);
}
views_used = views_used.max(view_count);
// VUID-VkSubpassDescription2-colorAttachmentCount-03063
if color_attachments.len() as u32 > properties.max_color_attachments {
return Err(
@ -1041,7 +1037,7 @@ impl RenderPass {
})?;
}
Ok(views_used)
Ok(())
}
pub(super) unsafe fn create_v2(

View File

@ -109,6 +109,7 @@ pub struct RenderPass {
dependencies: Vec<SubpassDependency>,
correlated_view_masks: Vec<u32>,
attachment_uses: Vec<Option<AttachmentUse>>,
granularity: [u32; 2],
views_used: u32,
}
@ -124,7 +125,7 @@ impl RenderPass {
device: Arc<Device>,
mut create_info: RenderPassCreateInfo,
) -> Result<Arc<RenderPass>, RenderPassCreationError> {
let views_used = Self::validate(&device, &mut create_info)?;
Self::validate(&device, &mut create_info)?;
let handle = unsafe {
if device.api_version() >= Version::V1_2
@ -136,38 +137,7 @@ impl RenderPass {
}
};
let RenderPassCreateInfo {
attachments,
subpasses,
dependencies,
correlated_view_masks,
_ne: _,
} = create_info;
let granularity = unsafe { Self::get_granularity(&device, handle) };
Ok(Arc::new(RenderPass {
handle,
device,
id: Self::next_id(),
attachments,
subpasses,
dependencies,
correlated_view_masks,
granularity,
views_used,
}))
}
unsafe fn get_granularity(device: &Arc<Device>, handle: ash::vk::RenderPass) -> [u32; 2] {
let fns = device.fns();
let mut out = MaybeUninit::uninit();
(fns.v1_0.get_render_area_granularity)(device.handle(), handle, out.as_mut_ptr());
let out = out.assume_init();
debug_assert_ne!(out.width, 0);
debug_assert_ne!(out.height, 0);
[out.width, out.height]
unsafe { Ok(Self::from_handle(device, handle, create_info)) }
}
/// Builds a render pass with one subpass and no attachment.
@ -197,15 +167,7 @@ impl RenderPass {
device: Arc<Device>,
handle: ash::vk::RenderPass,
create_info: RenderPassCreateInfo,
) -> Result<Arc<RenderPass>, RenderPassCreationError> {
let views_used = create_info
.subpasses
.iter()
.map(|subpass| u32::BITS - subpass.view_mask.leading_zeros())
.max()
.unwrap();
let granularity = Self::get_granularity(&device, handle);
) -> Arc<RenderPass> {
let RenderPassCreateInfo {
attachments,
subpasses,
@ -214,17 +176,65 @@ impl RenderPass {
_ne: _,
} = create_info;
Ok(Arc::new(RenderPass {
let granularity = Self::get_granularity(&device, handle);
let mut attachment_uses: Vec<Option<AttachmentUse>> = vec![None; attachments.len()];
let mut views_used = 0;
for (index, subpass_desc) in subpasses.iter().enumerate() {
let index = index as u32;
let &SubpassDescription {
view_mask,
ref input_attachments,
ref color_attachments,
ref resolve_attachments,
ref depth_stencil_attachment,
..
} = subpass_desc;
for atch_ref in (input_attachments.iter().flatten())
.chain(color_attachments.iter().flatten())
.chain(resolve_attachments.iter().flatten())
.chain(depth_stencil_attachment.iter())
{
match &mut attachment_uses[atch_ref.attachment as usize] {
Some(attachment_use) => attachment_use.last_use_subpass = index,
attachment_use @ None => {
*attachment_use = Some(AttachmentUse {
first_use_subpass: index,
last_use_subpass: index,
})
}
}
}
views_used = max(views_used, u32::BITS - view_mask.leading_zeros());
}
Arc::new(RenderPass {
handle,
device,
id: Self::next_id(),
attachments,
subpasses,
dependencies,
correlated_view_masks,
attachment_uses,
granularity,
views_used,
}))
})
}
unsafe fn get_granularity(device: &Arc<Device>, handle: ash::vk::RenderPass) -> [u32; 2] {
let fns = device.fns();
let mut out = MaybeUninit::uninit();
(fns.v1_0.get_render_area_granularity)(device.handle(), handle, out.as_mut_ptr());
let out = out.assume_init();
debug_assert_ne!(out.width, 0);
debug_assert_ne!(out.height, 0);
[out.width, out.height]
}
/// Returns the attachments of the render pass.
@ -292,6 +302,7 @@ impl RenderPass {
subpasses: subpasses1,
dependencies: dependencies1,
correlated_view_masks: correlated_view_masks1,
attachment_uses: _,
granularity: _,
views_used: _,
} = self;
@ -302,6 +313,7 @@ impl RenderPass {
attachments: attachments2,
subpasses: subpasses2,
dependencies: dependencies2,
attachment_uses: _,
correlated_view_masks: correlated_view_masks2,
granularity: _,
views_used: _,
@ -713,6 +725,44 @@ impl Subpass {
self.render_pass
.is_compatible_with_shader(self.subpass_id, shader_interface)
}
pub(crate) fn load_op(&self, attachment_index: u32) -> Option<LoadOp> {
self.render_pass.attachment_uses[attachment_index as usize]
.as_ref()
.and_then(|attachment_use| {
(attachment_use.first_use_subpass == self.subpass_id)
.then(|| self.render_pass.attachments[attachment_index as usize].load_op)
})
}
pub(crate) fn store_op(&self, attachment_index: u32) -> Option<StoreOp> {
self.render_pass.attachment_uses[attachment_index as usize]
.as_ref()
.and_then(|attachment_use| {
(attachment_use.last_use_subpass == self.subpass_id)
.then(|| self.render_pass.attachments[attachment_index as usize].store_op)
})
}
pub(crate) fn stencil_load_op(&self, attachment_index: u32) -> Option<LoadOp> {
self.render_pass.attachment_uses[attachment_index as usize]
.as_ref()
.and_then(|attachment_use| {
(attachment_use.first_use_subpass == self.subpass_id).then(|| {
self.render_pass.attachments[attachment_index as usize].stencil_load_op
})
})
}
pub(crate) fn stencil_store_op(&self, attachment_index: u32) -> Option<StoreOp> {
self.render_pass.attachment_uses[attachment_index as usize]
.as_ref()
.and_then(|attachment_use| {
(attachment_use.last_use_subpass == self.subpass_id).then(|| {
self.render_pass.attachments[attachment_index as usize].stencil_store_op
})
})
}
}
impl From<Subpass> for (Arc<RenderPass>, u32) {
@ -1147,7 +1197,7 @@ vulkan_enum! {
// TODO: document
None = NONE {
api_version: V1_3,
device_extensions: [ext_load_store_op_none],
device_extensions: [khr_dynamic_rendering, ext_load_store_op_none, qcom_render_pass_store_ops],
},*/
}
@ -1184,6 +1234,12 @@ vulkan_bitflags_enum! {
MAX, Max = MAX,
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct AttachmentUse {
first_use_subpass: u32,
last_use_subpass: u32,
}
#[cfg(test)]
mod tests {
use crate::{

View File

@ -467,7 +467,7 @@ pub enum ShaderExecution {
TessellationControl,
TessellationEvaluation,
Geometry(GeometryShaderExecution),
Fragment,
Fragment(FragmentShaderExecution),
Compute,
RayGeneration,
AnyHit,
@ -550,6 +550,20 @@ pub enum GeometryShaderOutput {
TriangleStrip,
}*/
/// The mode in which a fragment shader executes.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct FragmentShaderExecution {
pub fragment_tests_stages: FragmentTestsStages,
}
/// The fragment tests stages that will be executed in a fragment shader.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum FragmentTestsStages {
Early,
Late,
EarlyAndLate,
}
/// The requirements imposed by a shader on a binding within a descriptor set layout, and on any
/// resource that is bound to that binding.
#[derive(Clone, Debug, Default)]
@ -1189,7 +1203,7 @@ impl From<ShaderExecution> for ShaderStage {
ShaderExecution::TessellationControl => Self::TessellationControl,
ShaderExecution::TessellationEvaluation => Self::TessellationEvaluation,
ShaderExecution::Geometry(_) => Self::Geometry,
ShaderExecution::Fragment => Self::Fragment,
ShaderExecution::Fragment(_) => Self::Fragment,
ShaderExecution::Compute => Self::Compute,
ShaderExecution::RayGeneration => Self::Raygen,
ShaderExecution::AnyHit => Self::AnyHit,

View File

@ -9,7 +9,7 @@
//! Extraction of information from SPIR-V modules, that is needed by the rest of Vulkano.
use super::DescriptorBindingRequirements;
use super::{DescriptorBindingRequirements, FragmentShaderExecution, FragmentTestsStages};
use crate::{
descriptor_set::layout::DescriptorType,
image::view::ImageViewType,
@ -128,32 +128,69 @@ fn shader_execution(
ExecutionModel::TessellationEvaluation => ShaderExecution::TessellationEvaluation,
ExecutionModel::Geometry => {
let input = spirv
.iter_execution_mode()
.into_iter()
.find_map(|instruction| match instruction {
let mut input = None;
for instruction in spirv.iter_execution_mode() {
let mode = match instruction {
Instruction::ExecutionMode {
entry_point, mode, ..
} if *entry_point == function_id => match mode {
ExecutionMode::InputPoints => Some(GeometryShaderInput::Points),
ExecutionMode::InputLines => Some(GeometryShaderInput::Lines),
} if *entry_point == function_id => mode,
_ => continue,
};
match mode {
ExecutionMode::InputPoints => {
input = Some(GeometryShaderInput::Points);
}
ExecutionMode::InputLines => {
input = Some(GeometryShaderInput::Lines);
}
ExecutionMode::InputLinesAdjacency => {
Some(GeometryShaderInput::LinesWithAdjacency)
input = Some(GeometryShaderInput::LinesWithAdjacency);
}
ExecutionMode::Triangles => {
input = Some(GeometryShaderInput::Triangles);
}
ExecutionMode::Triangles => Some(GeometryShaderInput::Triangles),
ExecutionMode::InputTrianglesAdjacency => {
Some(GeometryShaderInput::TrianglesWithAdjacency)
input = Some(GeometryShaderInput::TrianglesWithAdjacency);
}
_ => todo!(),
},
_ => None,
_ => (),
}
}
ShaderExecution::Geometry(GeometryShaderExecution {
input: input
.expect("Geometry shader does not have an input primitive ExecutionMode"),
})
.expect("Geometry shader does not have an input primitive ExecutionMode");
ShaderExecution::Geometry(GeometryShaderExecution { input })
}
ExecutionModel::Fragment => ShaderExecution::Fragment,
ExecutionModel::Fragment => {
let mut fragment_tests_stages = FragmentTestsStages::Late;
for instruction in spirv.iter_execution_mode() {
let mode = match instruction {
Instruction::ExecutionMode {
entry_point, mode, ..
} if *entry_point == function_id => mode,
_ => continue,
};
#[allow(clippy::single_match)]
match mode {
ExecutionMode::EarlyFragmentTests => {
fragment_tests_stages = FragmentTestsStages::Early;
}
/*ExecutionMode::EarlyAndLateFragmentTestsAMD => {
fragment_tests_stages = FragmentTestsStages::EarlyAndLate;
}*/
_ => (),
}
}
ShaderExecution::Fragment(FragmentShaderExecution {
fragment_tests_stages,
})
}
ExecutionModel::GLCompute => ShaderExecution::Compute,
@ -164,7 +201,10 @@ fn shader_execution(
ExecutionModel::MissKHR => ShaderExecution::Miss,
ExecutionModel::CallableKHR => ShaderExecution::Callable,
ExecutionModel::Kernel | ExecutionModel::TaskNV | ExecutionModel::MeshNV => todo!(),
ExecutionModel::TaskNV => ShaderExecution::Task,
ExecutionModel::MeshNV => ShaderExecution::Mesh,
ExecutionModel::Kernel => todo!(),
}
}