mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 00:04:15 +00:00
Add synchronization tracking for render pass operations (#2101)
This commit is contained in:
parent
10d7349556
commit
79c39ecb06
@ -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 }
|
||||
|
@ -1419,7 +1419,6 @@ where
|
||||
DynamicState::ShadingRateImageEnable => todo!(),
|
||||
DynamicState::RepresentativeFragmentTestEnable => todo!(),
|
||||
DynamicState::CoverageReductionMode => todo!(),
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 },
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
@ -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,
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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::{
|
||||
|
@ -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,
|
||||
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user