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::Compute => quote! { ::vulkano::shader::ShaderExecution::Compute },
ShaderExecution::RayGeneration => { ShaderExecution::RayGeneration => {
quote! { ::vulkano::shader::ShaderExecution::RayGeneration } quote! { ::vulkano::shader::ShaderExecution::RayGeneration }

View File

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

View File

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

View File

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

View File

@ -34,14 +34,15 @@ use crate::{
}, },
descriptor_set::{DescriptorSetResources, DescriptorSetWithOffsets}, descriptor_set::{DescriptorSetResources, DescriptorSetWithOffsets},
device::{Device, DeviceOwned, QueueFamilyProperties, QueueFlags}, device::{Device, DeviceOwned, QueueFamilyProperties, QueueFlags},
format::{Format, FormatFeatures}, format::FormatFeatures,
image::{sys::Image, ImageAspects, ImageLayout, ImageSubresourceRange}, image::{sys::Image, ImageAspects, ImageLayout, ImageSubresourceRange, ImageViewAbstract},
pipeline::{ pipeline::{
graphics::{ graphics::{
color_blend::LogicOp, color_blend::LogicOp,
depth_stencil::{CompareOp, StencilOps}, depth_stencil::{CompareOp, StencilOps},
input_assembly::{IndexType, PrimitiveTopology}, input_assembly::{IndexType, PrimitiveTopology},
rasterization::{CullMode, DepthBias, FrontFace, LineStipple}, rasterization::{CullMode, DepthBias, FrontFace, LineStipple},
render_pass::PipelineRenderingCreateInfo,
viewport::{Scissor, Viewport}, viewport::{Scissor, Viewport},
}, },
ComputePipeline, DynamicState, GraphicsPipeline, PipelineBindPoint, PipelineLayout, ComputePipeline, DynamicState, GraphicsPipeline, PipelineBindPoint, PipelineLayout,
@ -49,7 +50,7 @@ use crate::{
query::{QueryControlFlags, QueryType}, query::{QueryControlFlags, QueryType},
range_map::RangeMap, range_map::RangeMap,
range_set::RangeSet, range_set::RangeSet,
render_pass::{Framebuffer, Subpass}, render_pass::{Framebuffer, LoadOp, StoreOp, Subpass},
sync::{ sync::{
BufferMemoryBarrier, DependencyInfo, ImageMemoryBarrier, PipelineStage, BufferMemoryBarrier, DependencyInfo, ImageMemoryBarrier, PipelineStage,
PipelineStageAccess, PipelineStageAccessSet, PipelineStages, PipelineStageAccess, PipelineStageAccessSet, PipelineStages,
@ -847,49 +848,48 @@ struct RenderPassState {
contents: SubpassContents, contents: SubpassContents,
render_area_offset: [u32; 2], render_area_offset: [u32; 2],
render_area_extent: [u32; 2], render_area_extent: [u32; 2],
rendering_info: PipelineRenderingCreateInfo,
attachments: Option<RenderPassStateAttachments>,
render_pass: RenderPassStateType, render_pass: RenderPassStateType,
view_mask: u32,
} }
impl RenderPassState { impl RenderPassState {
fn from_inheritance(render_pass: &CommandBufferInheritanceRenderPassType) -> Self { 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 { match render_pass {
CommandBufferInheritanceRenderPassType::BeginRenderPass(info) => { 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 { RenderPassState {
contents: SubpassContents::Inline, contents: SubpassContents::Inline,
render_area_offset, render_area_offset: [0, 0],
render_area_extent, 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 { render_pass: BeginRenderPassState {
subpass: info.subpass.clone(), subpass: info.subpass.clone(),
framebuffer: info.framebuffer.clone(), framebuffer: info.framebuffer.clone(),
} }
.into(), .into(),
view_mask: info.subpass.subpass_desc().view_mask,
} }
} }
CommandBufferInheritanceRenderPassType::BeginRendering(info) => RenderPassState { CommandBufferInheritanceRenderPassType::BeginRendering(info) => RenderPassState {
contents: SubpassContents::Inline, contents: SubpassContents::Inline,
render_area_offset, render_area_offset: [0, 0],
render_area_extent, render_area_extent: [u32::MAX, u32::MAX],
rendering_info: PipelineRenderingCreateInfo::from_inheritance_rendering_info(info),
attachments: None,
render_pass: BeginRenderingState { render_pass: BeginRenderingState {
attachments: None,
color_attachment_formats: info.color_attachment_formats.clone(),
depth_attachment_format: info.depth_attachment_format,
stencil_attachment_format: info.stencil_attachment_format,
pipeline_used: false, pipeline_used: false,
} }
.into(), .into(),
view_mask: info.view_mask,
}, },
} }
} }
@ -920,17 +920,190 @@ struct BeginRenderPassState {
} }
struct BeginRenderingState { struct BeginRenderingState {
attachments: Option<BeginRenderingAttachments>,
color_attachment_formats: Vec<Option<Format>>,
depth_attachment_format: Option<Format>,
stencil_attachment_format: Option<Format>,
pipeline_used: bool, pipeline_used: bool,
} }
struct BeginRenderingAttachments { struct RenderPassStateAttachments {
color_attachments: Vec<Option<RenderingAttachmentInfo>>, color_attachments: Vec<Option<RenderPassStateAttachmentInfo>>,
depth_attachment: Option<RenderingAttachmentInfo>, depth_attachment: Option<RenderPassStateAttachmentInfo>,
stencil_attachment: Option<RenderingAttachmentInfo>, 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 { struct DescriptorSetState {

View File

@ -8,8 +8,8 @@
// according to those terms. // according to those terms.
use super::{ use super::{
CommandBufferBuilder, DescriptorSetState, PipelineExecutionError, RenderPassState, CommandBufferBuilder, CommandBufferBuilderState, DescriptorSetState, PipelineExecutionError,
RenderPassStateType, ResourcesState, RenderPassState, RenderPassStateAttachmentInfo, RenderPassStateType, ResourcesState,
}; };
use crate::{ use crate::{
buffer::{view::BufferViewAbstract, BufferAccess, BufferUsage, TypedBufferAccess}, buffer::{view::BufferViewAbstract, BufferAccess, BufferUsage, TypedBufferAccess},
@ -21,7 +21,7 @@ use crate::{
descriptor_set::{layout::DescriptorType, DescriptorBindingResources}, descriptor_set::{layout::DescriptorType, DescriptorBindingResources},
device::{DeviceOwned, QueueFlags}, device::{DeviceOwned, QueueFlags},
format::FormatFeatures, format::FormatFeatures,
image::{ImageAccess, ImageAspects, ImageViewAbstract, SampleCount}, image::{ImageAccess, ImageAspects, ImageSubresourceRange, ImageViewAbstract, SampleCount},
pipeline::{ pipeline::{
graphics::{ graphics::{
input_assembly::{IndexType, PrimitiveTopology}, input_assembly::{IndexType, PrimitiveTopology},
@ -32,7 +32,10 @@ use crate::{
PipelineLayout, PipelineLayout,
}, },
sampler::Sampler, sampler::Sampler,
shader::{DescriptorBindingRequirements, ShaderScalarType, ShaderStage, ShaderStages}, shader::{
DescriptorBindingRequirements, FragmentTestsStages, ShaderScalarType, ShaderStage,
ShaderStages,
},
sync::PipelineStageAccess, sync::PipelineStageAccess,
RequiresOneOf, VulkanObject, RequiresOneOf, VulkanObject,
}; };
@ -353,6 +356,14 @@ where
&self.builder_state.vertex_buffers, &self.builder_state.vertex_buffers,
pipeline, 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) = if let RenderPassStateType::BeginRendering(state) =
&mut self.builder_state.render_pass.as_mut().unwrap().render_pass &mut self.builder_state.render_pass.as_mut().unwrap().render_pass
@ -503,6 +514,14 @@ where
command_name, command_name,
&indirect_buffer, &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) = if let RenderPassStateType::BeginRendering(state) =
&mut self.builder_state.render_pass.as_mut().unwrap().render_pass &mut self.builder_state.render_pass.as_mut().unwrap().render_pass
@ -658,6 +677,14 @@ where
command_name, command_name,
&self.builder_state.index_buffer, &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) = if let RenderPassStateType::BeginRendering(state) =
&mut self.builder_state.render_pass.as_mut().unwrap().render_pass &mut self.builder_state.render_pass.as_mut().unwrap().render_pass
@ -822,6 +849,14 @@ where
command_name, command_name,
&indirect_buffer, &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) = if let RenderPassStateType::BeginRendering(state) =
&mut self.builder_state.render_pass.as_mut().unwrap().render_pass &mut self.builder_state.render_pass.as_mut().unwrap().render_pass
@ -1716,7 +1751,6 @@ where
DynamicState::ShadingRateImageEnable => todo!(), DynamicState::ShadingRateImageEnable => todo!(),
DynamicState::RepresentativeFragmentTestEnable => todo!(), DynamicState::RepresentativeFragmentTestEnable => todo!(),
DynamicState::CoverageReductionMode => todo!(), DynamicState::CoverageReductionMode => todo!(),
} }
} }
@ -1757,43 +1791,48 @@ where
} }
} }
( (
RenderPassStateType::BeginRendering(current_rendering_info), RenderPassStateType::BeginRendering(_),
PipelineRenderPassType::BeginRendering(pipeline_rendering_info), PipelineRenderPassType::BeginRendering(pipeline_rendering_info),
) => { ) => {
// VUID-vkCmdDraw-viewMask-06178 // 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 { return Err(PipelineExecutionError::PipelineViewMaskMismatch {
pipeline_view_mask: pipeline_rendering_info.view_mask, 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 // VUID-vkCmdDraw-colorAttachmentCount-06179
if pipeline_rendering_info.color_attachment_formats.len() 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( return Err(
PipelineExecutionError::PipelineColorAttachmentCountMismatch { PipelineExecutionError::PipelineColorAttachmentCountMismatch {
pipeline_count: pipeline_rendering_info.color_attachment_formats.len() pipeline_count: pipeline_rendering_info.color_attachment_formats.len()
as u32, as u32,
required_count: current_rendering_info.color_attachment_formats.len() required_count: render_pass_state
as u32, .rendering_info
.color_attachment_formats
.len() as u32,
}, },
); );
} }
for (color_attachment_index, required_format, pipeline_format) in for (color_attachment_index, required_format, pipeline_format) in render_pass_state
current_rendering_info .rendering_info
.color_attachment_formats .color_attachment_formats
.iter() .iter()
.zip( .zip(
pipeline_rendering_info pipeline_rendering_info
.color_attachment_formats .color_attachment_formats
.iter() .iter()
.copied(), .copied(),
) )
.enumerate() .enumerate()
.filter_map(|(i, (r, p))| r.map(|r| (i as u32, r, p))) .filter_map(|(i, (r, p))| r.map(|r| (i as u32, r, p)))
{ {
// VUID-vkCmdDraw-colorAttachmentCount-06180 // VUID-vkCmdDraw-colorAttachmentCount-06180
if Some(required_format) != pipeline_format { if Some(required_format) != pipeline_format {
@ -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 .depth_attachment_format
.map(|r| (r, pipeline_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 .stencil_attachment_format
.map(|r| (r, pipeline_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, 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 { if let Some(render_pass_state) = &self.builder_state.render_pass {
// VUID-vkCmdBeginQuery-query-00808 // 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); return Err(QueryError::OutOfRangeMultiview);
} }
} }
@ -216,7 +218,9 @@ where
if let Some(render_pass_state) = &self.builder_state.render_pass { if let Some(render_pass_state) = &self.builder_state.render_pass {
// VUID-vkCmdEndQuery-query-00812 // 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); return Err(QueryError::OutOfRangeMultiview);
} }
} }
@ -448,7 +452,9 @@ where
if let Some(render_pass_state) = &self.builder_state.render_pass { if let Some(render_pass_state) = &self.builder_state.render_pass {
// VUID-vkCmdWriteTimestamp2-query-03865 // 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); return Err(QueryError::OutOfRangeMultiview);
} }
} }

View File

@ -8,16 +8,22 @@
// according to those terms. // according to those terms.
use super::{ use super::{
BeginRenderPassState, BeginRenderingAttachments, BeginRenderingState, ClearAttachment, BeginRenderPassState, BeginRenderingState, ClearAttachment, ClearRect, CommandBufferBuilder,
ClearRect, CommandBufferBuilder, RenderPassBeginInfo, RenderPassError, RenderPassState, RenderPassBeginInfo, RenderPassError, RenderPassState, RenderPassStateAttachmentInfo,
RenderPassStateType, RenderingAttachmentInfo, RenderingAttachmentResolveInfo, RenderingInfo, RenderPassStateAttachmentResolveInfo, RenderPassStateAttachments, RenderPassStateType,
RenderingAttachmentInfo, RenderingAttachmentResolveInfo, RenderingInfo, ResourcesState,
}; };
use crate::{ use crate::{
command_buffer::{allocator::CommandBufferAllocator, PrimaryCommandBuffer, SubpassContents}, command_buffer::{
allocator::CommandBufferAllocator, PrimaryCommandBuffer, ResourceInCommand, ResourceUseRef,
SubpassContents,
},
device::{DeviceOwned, QueueFlags}, device::{DeviceOwned, QueueFlags},
format::{ClearColorValue, ClearValue, NumericType}, format::{ClearColorValue, ClearValue, NumericType},
image::{ImageAspects, ImageLayout, ImageUsage, SampleCount}, image::{ImageAspects, ImageLayout, ImageUsage, SampleCount},
pipeline::graphics::render_pass::PipelineRenderingCreateInfo,
render_pass::{AttachmentDescription, LoadOp, ResolveMode, SubpassDescription}, render_pass::{AttachmentDescription, LoadOp, ResolveMode, SubpassDescription},
sync::PipelineStageAccess,
RequiresOneOf, Version, VulkanObject, RequiresOneOf, Version, VulkanObject,
}; };
use smallvec::SmallVec; use smallvec::SmallVec;
@ -443,26 +449,47 @@ where
); );
} }
let subpass = render_pass.clone().first_subpass(); let command_index = self.next_command_index;
let view_mask = subpass.subpass_desc().view_mask; let command_name = "begin_render_pass";
self.builder_state.render_pass = Some(RenderPassState { // Advance to first subpass
contents, {
render_area_offset, let subpass = render_pass.clone().first_subpass();
render_area_extent, self.builder_state.render_pass = Some(RenderPassState {
render_pass: BeginRenderPassState { contents,
subpass, render_area_offset,
framebuffer: Some(framebuffer.clone()), render_area_extent,
}
.into(), rendering_info: PipelineRenderingCreateInfo::from_subpass(&subpass),
view_mask, attachments: Some(RenderPassStateAttachments::from_subpass(
}); &subpass,
&framebuffer,
)),
render_pass: BeginRenderPassState {
subpass,
framebuffer: Some(framebuffer.clone()),
}
.into(),
});
}
// 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(render_pass));
self.resources.push(Box::new(framebuffer)); self.resources.push(Box::new(framebuffer));
// TODO: sync state update
self.next_command_index += 1; self.next_command_index += 1;
self self
} }
@ -562,23 +589,62 @@ where
(fns.v1_0.cmd_next_subpass)(self.handle(), subpass_begin_info.contents); (fns.v1_0.cmd_next_subpass)(self.handle(), subpass_begin_info.contents);
} }
let render_pass_state = self.builder_state.render_pass.as_mut().unwrap(); let command_index = self.next_command_index;
let begin_render_pass_state = match &mut render_pass_state.render_pass { let command_name = "next_subpass";
RenderPassStateType::BeginRenderPass(x) => x,
_ => unreachable!(),
};
begin_render_pass_state.subpass.next_subpass(); // End of previous subpass
render_pass_state.contents = contents; {
render_pass_state.view_mask = begin_render_pass_state.subpass.subpass_desc().view_mask; let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
record_subpass_attachments_resolve(
if render_pass_state.view_mask != 0 { &mut self.resources_usage_state,
// When multiview is enabled, at the beginning of each subpass, all command_index,
// non-render pass state is undefined. command_name,
self.builder_state = Default::default(); render_pass_state,
);
record_subpass_attachments_store(
&mut self.resources_usage_state,
command_index,
command_name,
render_pass_state,
);
} }
// TODO: sync state update // 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,
_ => unreachable!(),
};
begin_render_pass_state.subpass.next_subpass();
render_pass_state.contents = contents;
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.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();
}
}
// 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.next_command_index += 1;
self self
@ -673,9 +739,29 @@ where
(fns.v1_0.cmd_end_render_pass)(self.handle()); (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.next_command_index += 1;
self self
@ -1268,127 +1354,129 @@ where
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn begin_rendering_unchecked(&mut self, rendering_info: RenderingInfo) -> &mut Self { pub unsafe fn begin_rendering_unchecked(&mut self, rendering_info: RenderingInfo) -> &mut Self {
{
let &RenderingInfo {
render_area_offset,
render_area_extent,
layer_count,
view_mask,
ref color_attachments,
ref depth_attachment,
ref stencil_attachment,
contents,
_ne,
} = &rendering_info;
let map_attachment_info = |attachment_info: &Option<_>| {
if let Some(attachment_info) = attachment_info {
let &RenderingAttachmentInfo {
ref image_view,
image_layout,
resolve_info: ref resolve,
load_op,
store_op,
clear_value,
_ne: _,
} = attachment_info;
let (resolve_mode, resolve_image_view, resolve_image_layout) =
if let Some(resolve) = resolve {
let &RenderingAttachmentResolveInfo {
mode,
ref image_view,
image_layout,
} = resolve;
(mode.into(), image_view.handle(), image_layout.into())
} else {
(
ash::vk::ResolveModeFlags::NONE,
Default::default(),
Default::default(),
)
};
ash::vk::RenderingAttachmentInfo {
image_view: image_view.handle(),
image_layout: image_layout.into(),
resolve_mode,
resolve_image_view,
resolve_image_layout,
load_op: load_op.into(),
store_op: store_op.into(),
clear_value: clear_value.map_or_else(Default::default, Into::into),
..Default::default()
}
} else {
ash::vk::RenderingAttachmentInfo {
image_view: ash::vk::ImageView::null(),
..Default::default()
}
}
};
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 rendering_info_vk = ash::vk::RenderingInfo {
flags: contents.into(),
render_area: ash::vk::Rect2D {
offset: ash::vk::Offset2D {
x: render_area_offset[0] as i32,
y: render_area_offset[1] as i32,
},
extent: ash::vk::Extent2D {
width: render_area_extent[0],
height: render_area_extent[1],
},
},
layer_count,
view_mask,
color_attachment_count: color_attachments_vk.len() as u32,
p_color_attachments: color_attachments_vk.as_ptr(),
p_depth_attachment: &depth_attachment_vk,
p_stencil_attachment: &stencil_attachment_vk,
..Default::default()
};
let fns = self.device().fns();
if self.device().api_version() >= Version::V1_3 {
(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_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 {
pipeline_used: false,
}
.into(),
});
}
let RenderingInfo { let RenderingInfo {
render_area_offset,
render_area_extent,
layer_count,
view_mask,
color_attachments, color_attachments,
depth_attachment, depth_attachment,
stencil_attachment, stencil_attachment,
contents, ..
_ne,
} = rendering_info; } = rendering_info;
let map_attachment_info = |attachment_info: &Option<_>| {
if let Some(attachment_info) = attachment_info {
let &RenderingAttachmentInfo {
ref image_view,
image_layout,
resolve_info: ref resolve,
load_op,
store_op,
clear_value,
_ne: _,
} = attachment_info;
let (resolve_mode, resolve_image_view, resolve_image_layout) =
if let Some(resolve) = resolve {
let &RenderingAttachmentResolveInfo {
mode,
ref image_view,
image_layout,
} = resolve;
(mode.into(), image_view.handle(), image_layout.into())
} else {
(
ash::vk::ResolveModeFlags::NONE,
Default::default(),
Default::default(),
)
};
ash::vk::RenderingAttachmentInfo {
image_view: image_view.handle(),
image_layout: image_layout.into(),
resolve_mode,
resolve_image_view,
resolve_image_layout,
load_op: load_op.into(),
store_op: store_op.into(),
clear_value: clear_value.map_or_else(Default::default, Into::into),
..Default::default()
}
} else {
ash::vk::RenderingAttachmentInfo {
image_view: ash::vk::ImageView::null(),
..Default::default()
}
}
};
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 rendering_info = ash::vk::RenderingInfo {
flags: contents.into(),
render_area: ash::vk::Rect2D {
offset: ash::vk::Offset2D {
x: render_area_offset[0] as i32,
y: render_area_offset[1] as i32,
},
extent: ash::vk::Extent2D {
width: render_area_extent[0],
height: render_area_extent[1],
},
},
layer_count,
view_mask,
color_attachment_count: color_attachments_vk.len() as u32,
p_color_attachments: color_attachments_vk.as_ptr(),
p_depth_attachment: &depth_attachment_vk,
p_stencil_attachment: &stencil_attachment_vk,
..Default::default()
};
let fns = self.device().fns();
if self.device().api_version() >= Version::V1_3 {
(fns.v1_3.cmd_begin_rendering)(self.handle(), &rendering_info);
} else {
debug_assert!(self.device().enabled_extensions().khr_dynamic_rendering);
(fns.khr_dynamic_rendering.cmd_begin_rendering_khr)(self.handle(), &rendering_info);
}
self.builder_state.render_pass = Some(RenderPassState {
contents,
render_area_offset,
render_area_extent,
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,
});
for attachment_info in color_attachments.into_iter().flatten() { for attachment_info in color_attachments.into_iter().flatten() {
let RenderingAttachmentInfo { let RenderingAttachmentInfo {
image_view, image_view,
@ -1461,8 +1549,6 @@ where
} }
} }
// TODO: sync state update
self.next_command_index += 1; self.next_command_index += 1;
self self
} }
@ -1525,9 +1611,24 @@ where
(fns.khr_dynamic_rendering.cmd_end_rendering_khr)(self.handle()); (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.next_command_index += 1;
self self
@ -1587,7 +1688,7 @@ where
//let subpass_desc = begin_render_pass_state.subpass.subpass_desc(); //let subpass_desc = begin_render_pass_state.subpass.subpass_desc();
//let render_pass = begin_render_pass_state.subpass.render_pass(); //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; let mut layer_count = u32::MAX;
for &clear_attachment in attachments { for &clear_attachment in attachments {
@ -1596,31 +1697,17 @@ where
color_attachment, color_attachment,
clear_value, clear_value,
} => { } => {
let attachment_format = match &render_pass_state.render_pass { let attachment_format = *render_pass_state
RenderPassStateType::BeginRenderPass(state) => { .rendering_info
let color_attachments = &state.subpass.subpass_desc().color_attachments; .color_attachment_formats
let atch_ref = color_attachments.get(color_attachment as usize).ok_or( .get(color_attachment as usize)
RenderPassError::ColorAttachmentIndexOutOfRange { .ok_or(RenderPassError::ColorAttachmentIndexOutOfRange {
color_attachment_index: color_attachment, color_attachment_index: color_attachment,
num_color_attachments: color_attachments.len() as u32, num_color_attachments: render_pass_state
}, .rendering_info
)?; .color_attachment_formats
.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
.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,
})?,
};
// VUID-vkCmdClearAttachments-aspectMask-02501 // VUID-vkCmdClearAttachments-aspectMask-02501
if !attachment_format.map_or(false, |format| { if !attachment_format.map_or(false, |format| {
@ -1645,24 +1732,13 @@ where
}); });
} }
let image_view = match &render_pass_state.render_pass { let image_view = render_pass_state
RenderPassStateType::BeginRenderPass(state) => (state.framebuffer.as_ref()) .attachments
.zip( .as_ref()
state.subpass.subpass_desc().color_attachments .and_then(|attachments| {
[color_attachment as usize] attachments.color_attachments[color_attachment as usize].as_ref()
.as_ref(), })
) .map(|attachment_info| &attachment_info.image_view);
.map(|(framebuffer, atch_ref)| {
&framebuffer.attachments()[atch_ref.attachment as usize]
}),
RenderPassStateType::BeginRendering(state) => state
.attachments
.as_ref()
.and_then(|attachments| {
attachments.color_attachments[color_attachment as usize].as_ref()
})
.map(|attachment_info| &attachment_info.image_view),
};
// We only know the layer count if we have a known attachment image. // We only know the layer count if we have a known attachment image.
if let Some(image_view) = image_view { if let Some(image_view) = image_view {
@ -1673,24 +1749,8 @@ where
ClearAttachment::Depth(_) ClearAttachment::Depth(_)
| ClearAttachment::Stencil(_) | ClearAttachment::Stencil(_)
| ClearAttachment::DepthStencil(_) => { | ClearAttachment::DepthStencil(_) => {
let (depth_format, stencil_format) = match &render_pass_state.render_pass { let depth_format = render_pass_state.rendering_info.depth_attachment_format;
RenderPassStateType::BeginRenderPass(state) => state let stencil_format = render_pass_state.rendering_info.stencil_attachment_format;
.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,
),
};
// VUID-vkCmdClearAttachments-aspectMask-02502 // VUID-vkCmdClearAttachments-aspectMask-02502
if matches!( if matches!(
@ -1718,24 +1778,11 @@ where
}); });
} }
let image_view = match &render_pass_state.render_pass { let image_view = render_pass_state
RenderPassStateType::BeginRenderPass(state) => (state.framebuffer.as_ref()) .attachments
.zip( .as_ref()
state .and_then(|attachments| attachments.depth_attachment.as_ref())
.subpass .map(|attachment_info| &attachment_info.image_view);
.subpass_desc()
.depth_stencil_attachment
.as_ref(),
)
.map(|(framebuffer, atch_ref)| {
&framebuffer.attachments()[atch_ref.attachment as usize]
}),
RenderPassStateType::BeginRendering(state) => state
.attachments
.as_ref()
.and_then(|attachments| attachments.depth_attachment.as_ref())
.map(|attachment_info| &attachment_info.image_view),
};
// We only know the layer count if we have a known attachment image. // We only know the layer count if we have a known attachment image.
if let Some(image_view) = image_view { if let Some(image_view) = image_view {
@ -1838,3 +1885,364 @@ where
self 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), CommandBufferInheritanceRenderPassType::BeginRendering(inheritance_info),
) => { ) => {
let attachments = state.attachments.as_ref().unwrap(); let attachments = render_pass_state.attachments.as_ref().unwrap();
// VUID-vkCmdExecuteCommands-colorAttachmentCount-06027 // VUID-vkCmdExecuteCommands-colorAttachmentCount-06027
if inheritance_info.color_attachment_formats.len() if inheritance_info.color_attachment_formats.len()
@ -230,10 +230,10 @@ where
} }
// VUID-vkCmdExecuteCommands-viewMask-06031 // 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 { return Err(ExecuteCommandsError::RenderPassViewMaskMismatch {
command_buffer_index, 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, inherited_view_mask: inheritance_info.view_mask,
}); });
} }

View File

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

View File

@ -67,7 +67,7 @@ use self::{
use super::{DynamicState, Pipeline, PipelineBindPoint, PipelineLayout}; use super::{DynamicState, Pipeline, PipelineBindPoint, PipelineLayout};
use crate::{ use crate::{
device::{Device, DeviceOwned}, device::{Device, DeviceOwned},
shader::{DescriptorBindingRequirements, ShaderStage}, shader::{DescriptorBindingRequirements, FragmentTestsStages, ShaderStage},
VulkanObject, VulkanObject,
}; };
use ahash::HashMap; use ahash::HashMap;
@ -108,6 +108,7 @@ pub struct GraphicsPipeline {
shaders: HashMap<ShaderStage, ()>, shaders: HashMap<ShaderStage, ()>,
descriptor_binding_requirements: HashMap<(u32, u32), DescriptorBindingRequirements>, descriptor_binding_requirements: HashMap<(u32, u32), DescriptorBindingRequirements>,
num_used_descriptor_sets: u32, num_used_descriptor_sets: u32,
fragment_tests_stages: Option<FragmentTestsStages>,
vertex_input_state: VertexInputState, vertex_input_state: VertexInputState,
input_assembly_state: InputAssemblyState, input_assembly_state: InputAssemblyState,
@ -233,6 +234,12 @@ impl GraphicsPipeline {
pub fn dynamic_states(&self) -> impl ExactSizeIterator<Item = (DynamicState, bool)> + '_ { pub fn dynamic_states(&self) -> impl ExactSizeIterator<Item = (DynamicState, bool)> + '_ {
self.dynamic_state.iter().map(|(k, v)| (*k, *v)) 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 { impl Pipeline for GraphicsPipeline {

View File

@ -7,7 +7,12 @@
// notice may not be copied, modified, or distributed except // notice may not be copied, modified, or distributed except
// according to those terms. // 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. /// Selects the type of render pass that a graphics pipeline is created for.
#[derive(Clone, Debug)] #[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 /// 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. /// when binding it, and will have to be re-set after binding a pipeline that uses it.
Fixed(F), Fixed(F),
/// The pipeline expects a dynamic value to be set by a command buffer. Previously set dynamic /// The pipeline expects a dynamic value to be set by a command buffer. Previously set dynamic
/// state is not disturbed when binding it. /// state is not disturbed when binding it.
Dynamic, Dynamic,

View File

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

View File

@ -109,6 +109,7 @@ pub struct RenderPass {
dependencies: Vec<SubpassDependency>, dependencies: Vec<SubpassDependency>,
correlated_view_masks: Vec<u32>, correlated_view_masks: Vec<u32>,
attachment_uses: Vec<Option<AttachmentUse>>,
granularity: [u32; 2], granularity: [u32; 2],
views_used: u32, views_used: u32,
} }
@ -124,7 +125,7 @@ impl RenderPass {
device: Arc<Device>, device: Arc<Device>,
mut create_info: RenderPassCreateInfo, mut create_info: RenderPassCreateInfo,
) -> Result<Arc<RenderPass>, RenderPassCreationError> { ) -> Result<Arc<RenderPass>, RenderPassCreationError> {
let views_used = Self::validate(&device, &mut create_info)?; Self::validate(&device, &mut create_info)?;
let handle = unsafe { let handle = unsafe {
if device.api_version() >= Version::V1_2 if device.api_version() >= Version::V1_2
@ -136,38 +137,7 @@ impl RenderPass {
} }
}; };
let RenderPassCreateInfo { unsafe { Ok(Self::from_handle(device, handle, create_info)) }
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]
} }
/// Builds a render pass with one subpass and no attachment. /// Builds a render pass with one subpass and no attachment.
@ -197,15 +167,7 @@ impl RenderPass {
device: Arc<Device>, device: Arc<Device>,
handle: ash::vk::RenderPass, handle: ash::vk::RenderPass,
create_info: RenderPassCreateInfo, create_info: RenderPassCreateInfo,
) -> Result<Arc<RenderPass>, RenderPassCreationError> { ) -> Arc<RenderPass> {
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);
let RenderPassCreateInfo { let RenderPassCreateInfo {
attachments, attachments,
subpasses, subpasses,
@ -214,17 +176,65 @@ impl RenderPass {
_ne: _, _ne: _,
} = create_info; } = 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, handle,
device, device,
id: Self::next_id(), id: Self::next_id(),
attachments, attachments,
subpasses, subpasses,
dependencies, dependencies,
correlated_view_masks, correlated_view_masks,
attachment_uses,
granularity, granularity,
views_used, 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. /// Returns the attachments of the render pass.
@ -292,6 +302,7 @@ impl RenderPass {
subpasses: subpasses1, subpasses: subpasses1,
dependencies: dependencies1, dependencies: dependencies1,
correlated_view_masks: correlated_view_masks1, correlated_view_masks: correlated_view_masks1,
attachment_uses: _,
granularity: _, granularity: _,
views_used: _, views_used: _,
} = self; } = self;
@ -302,6 +313,7 @@ impl RenderPass {
attachments: attachments2, attachments: attachments2,
subpasses: subpasses2, subpasses: subpasses2,
dependencies: dependencies2, dependencies: dependencies2,
attachment_uses: _,
correlated_view_masks: correlated_view_masks2, correlated_view_masks: correlated_view_masks2,
granularity: _, granularity: _,
views_used: _, views_used: _,
@ -713,6 +725,44 @@ impl Subpass {
self.render_pass self.render_pass
.is_compatible_with_shader(self.subpass_id, shader_interface) .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) { impl From<Subpass> for (Arc<RenderPass>, u32) {
@ -1147,7 +1197,7 @@ vulkan_enum! {
// TODO: document // TODO: document
None = NONE { None = NONE {
api_version: V1_3, 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, MAX, Max = MAX,
} }
#[derive(Clone, Copy, Debug)]
pub(crate) struct AttachmentUse {
first_use_subpass: u32,
last_use_subpass: u32,
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{

View File

@ -467,7 +467,7 @@ pub enum ShaderExecution {
TessellationControl, TessellationControl,
TessellationEvaluation, TessellationEvaluation,
Geometry(GeometryShaderExecution), Geometry(GeometryShaderExecution),
Fragment, Fragment(FragmentShaderExecution),
Compute, Compute,
RayGeneration, RayGeneration,
AnyHit, AnyHit,
@ -550,6 +550,20 @@ pub enum GeometryShaderOutput {
TriangleStrip, 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 /// The requirements imposed by a shader on a binding within a descriptor set layout, and on any
/// resource that is bound to that binding. /// resource that is bound to that binding.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@ -1189,7 +1203,7 @@ impl From<ShaderExecution> for ShaderStage {
ShaderExecution::TessellationControl => Self::TessellationControl, ShaderExecution::TessellationControl => Self::TessellationControl,
ShaderExecution::TessellationEvaluation => Self::TessellationEvaluation, ShaderExecution::TessellationEvaluation => Self::TessellationEvaluation,
ShaderExecution::Geometry(_) => Self::Geometry, ShaderExecution::Geometry(_) => Self::Geometry,
ShaderExecution::Fragment => Self::Fragment, ShaderExecution::Fragment(_) => Self::Fragment,
ShaderExecution::Compute => Self::Compute, ShaderExecution::Compute => Self::Compute,
ShaderExecution::RayGeneration => Self::Raygen, ShaderExecution::RayGeneration => Self::Raygen,
ShaderExecution::AnyHit => Self::AnyHit, 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. //! 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::{ use crate::{
descriptor_set::layout::DescriptorType, descriptor_set::layout::DescriptorType,
image::view::ImageViewType, image::view::ImageViewType,
@ -128,32 +128,69 @@ fn shader_execution(
ExecutionModel::TessellationEvaluation => ShaderExecution::TessellationEvaluation, ExecutionModel::TessellationEvaluation => ShaderExecution::TessellationEvaluation,
ExecutionModel::Geometry => { ExecutionModel::Geometry => {
let input = spirv let mut input = None;
.iter_execution_mode()
.into_iter() for instruction in spirv.iter_execution_mode() {
.find_map(|instruction| match instruction { let mode = match instruction {
Instruction::ExecutionMode { Instruction::ExecutionMode {
entry_point, mode, .. entry_point, mode, ..
} if *entry_point == function_id => match mode { } if *entry_point == function_id => mode,
ExecutionMode::InputPoints => Some(GeometryShaderInput::Points), _ => continue,
ExecutionMode::InputLines => Some(GeometryShaderInput::Lines), };
ExecutionMode::InputLinesAdjacency => {
Some(GeometryShaderInput::LinesWithAdjacency)
}
ExecutionMode::Triangles => Some(GeometryShaderInput::Triangles),
ExecutionMode::InputTrianglesAdjacency => {
Some(GeometryShaderInput::TrianglesWithAdjacency)
}
_ => todo!(),
},
_ => None,
})
.expect("Geometry shader does not have an input primitive ExecutionMode");
ShaderExecution::Geometry(GeometryShaderExecution { input }) match mode {
ExecutionMode::InputPoints => {
input = Some(GeometryShaderInput::Points);
}
ExecutionMode::InputLines => {
input = Some(GeometryShaderInput::Lines);
}
ExecutionMode::InputLinesAdjacency => {
input = Some(GeometryShaderInput::LinesWithAdjacency);
}
ExecutionMode::Triangles => {
input = Some(GeometryShaderInput::Triangles);
}
ExecutionMode::InputTrianglesAdjacency => {
input = Some(GeometryShaderInput::TrianglesWithAdjacency);
}
_ => (),
}
}
ShaderExecution::Geometry(GeometryShaderExecution {
input: input
.expect("Geometry shader does not have an input primitive ExecutionMode"),
})
} }
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, ExecutionModel::GLCompute => ShaderExecution::Compute,
@ -164,7 +201,10 @@ fn shader_execution(
ExecutionModel::MissKHR => ShaderExecution::Miss, ExecutionModel::MissKHR => ShaderExecution::Miss,
ExecutionModel::CallableKHR => ShaderExecution::Callable, ExecutionModel::CallableKHR => ShaderExecution::Callable,
ExecutionModel::Kernel | ExecutionModel::TaskNV | ExecutionModel::MeshNV => todo!(), ExecutionModel::TaskNV => ShaderExecution::Task,
ExecutionModel::MeshNV => ShaderExecution::Mesh,
ExecutionModel::Kernel => todo!(),
} }
} }