Improve render pass commands, more validation (#1884)

* Use only the selected range of buffer and image views in synchronization

* Improve render pass commands, more validation

Co-authored-by: Austin Johnson <me@austinj.work>
This commit is contained in:
Rua 2022-04-24 03:16:19 +02:00 committed by GitHub
parent 1c71883cd4
commit 9e2b41a5c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1429 additions and 849 deletions

View File

@ -26,7 +26,9 @@ use std::{
};
use vulkano::{
buffer::CpuBufferPool,
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
@ -268,8 +270,6 @@ fn main() {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
// Rotate once (PI*2) every 5 seconds
let elapsed = SystemTime::now()
.duration_since(UNIX_EPOCH)
@ -312,9 +312,11 @@ fn main() {
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
.set_viewport(0, [viewport.clone()])

View File

@ -9,17 +9,15 @@
use std::sync::Arc;
use vulkano::{
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, ClearAttachment, ClearRect, CommandBufferUsage,
RenderPassBeginInfo, SubpassContents,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
format::ClearValue,
image::{
attachment::{ClearAttachment, ClearRect},
view::ImageView,
ImageUsage, SwapchainImage,
},
image::{view::ImageView, ImageUsage, SwapchainImage},
instance::{Instance, InstanceCreateInfo},
pipeline::{graphics::viewport::ViewportState, GraphicsPipeline},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
@ -230,7 +228,6 @@ fn main() {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),
@ -239,9 +236,11 @@ fn main() {
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
.bind_pipeline_graphics(pipeline.clone())
@ -249,32 +248,29 @@ fn main() {
// Note that the ClearRect offsets and extents are not affected by the viewport,
// they are directly applied to the rendering image
.clear_attachments(
[ClearAttachment::Color(
ClearValue::Float([1.0, 0.0, 0.0, 1.0]),
0,
)],
[ClearAttachment::Color {
color_attachment: 0,
clear_value: [1.0, 0.0, 0.0, 1.0].into(),
}],
[
// Fixed offset and extent
ClearRect {
rect_offset: [0, 0],
rect_extent: [100, 100],
base_array_layer: 0,
layer_count: 1,
offset: [0, 0],
extent: [100, 100],
array_layers: 0..1,
},
// Fixed offset
// Relative extent
ClearRect {
rect_offset: [100, 150],
rect_extent: [width / 4, height / 4],
base_array_layer: 0,
layer_count: 1,
offset: [100, 150],
extent: [width / 4, height / 4],
array_layers: 0..1,
},
// Relative offset and extent
ClearRect {
rect_offset: [width / 2, height / 2],
rect_extent: [width / 3, height / 5],
base_array_layer: 0,
layer_count: 1,
offset: [width / 2, height / 2],
extent: [width / 3, height / 5],
array_layers: 0..1,
},
],
)

View File

@ -17,7 +17,7 @@ use std::sync::Arc;
use vulkano::{
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer,
SecondaryCommandBuffer, SubpassContents,
RenderPassBeginInfo, SecondaryCommandBuffer, SubpassContents,
},
device::Queue,
format::Format,
@ -300,14 +300,16 @@ impl FrameSystem {
.unwrap();
command_buffer_builder
.begin_render_pass(
framebuffer.clone(),
RenderPassBeginInfo {
clear_values: vec![
Some([0.0, 0.0, 0.0, 0.0].into()),
Some([0.0, 0.0, 0.0, 0.0].into()),
Some([0.0, 0.0, 0.0, 0.0].into()),
Some(1.0f32.into()),
],
..RenderPassBeginInfo::framebuffer(framebuffer.clone())
},
SubpassContents::SecondaryCommandBuffers,
vec![
[0.0, 0.0, 0.0, 0.0].into(),
[0.0, 0.0, 0.0, 0.0].into(),
[0.0, 0.0, 0.0, 0.0].into(),
1.0f32.into(),
],
)
.unwrap();

View File

@ -16,7 +16,7 @@ mod linux {
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{
submit::SubmitCommandBufferBuilder, AutoCommandBufferBuilder, CommandBufferUsage,
SubpassContents,
RenderPassBeginInfo, SubpassContents,
},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
@ -296,7 +296,6 @@ mod linux {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),
@ -305,9 +304,11 @@ mod linux {
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
.set_viewport(0, [viewport.clone()])

View File

@ -14,7 +14,7 @@ use vulkano::{
command_buffer::{
AutoCommandBufferBuilder, BlitImageInfo, BufferImageCopy, ClearColorImageInfo,
CommandBufferUsage, CopyBufferToImageInfo, CopyImageInfo, ImageBlit, ImageCopy,
PrimaryCommandBuffer, SubpassContents,
PrimaryCommandBuffer, RenderPassBeginInfo, SubpassContents,
},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
@ -378,7 +378,6 @@ fn main() {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),
@ -387,9 +386,11 @@ fn main() {
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
.set_viewport(0, [viewport.clone()])

View File

@ -11,7 +11,9 @@ use bytemuck::{Pod, Zeroable};
use std::{io::Cursor, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
@ -296,7 +298,6 @@ fn main() {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),
@ -305,9 +306,11 @@ fn main() {
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
.set_viewport(0, [viewport.clone()])

View File

@ -20,7 +20,9 @@ use bytemuck::{Pod, Zeroable};
use std::{io::Cursor, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
@ -305,7 +307,6 @@ fn main() {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),
@ -314,9 +315,11 @@ fn main() {
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
.set_viewport(0, [viewport.clone()])

View File

@ -29,7 +29,8 @@ use std::sync::Arc;
use vulkano::{
buffer::{BufferUsage, CpuBufferPool},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, DrawIndirectCommand, SubpassContents,
AutoCommandBufferBuilder, CommandBufferUsage, DrawIndirectCommand, RenderPassBeginInfo,
SubpassContents,
},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
@ -332,8 +333,6 @@ fn main() {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
// Allocate a GPU buffer to hold the arguments for this frames draw call. The compute
// shader will only update vertex_count, so set the other parameters correctly here.
let indirect_commands = [DrawIndirectCommand {
@ -381,9 +380,11 @@ fn main() {
.dispatch([1, 1, 1])
.unwrap()
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
// The indirect draw call is placed in the command buffer with a reference to the GPU buffer that will

View File

@ -16,7 +16,9 @@ use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
@ -327,8 +329,6 @@ fn main() {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),
@ -337,9 +337,11 @@ fn main() {
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
.set_viewport(0, [viewport.clone()])

View File

@ -13,7 +13,9 @@ use crate::{
};
use std::sync::Arc;
use vulkano::{
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
device::Queue,
format::Format,
image::ImageAccess,
@ -86,9 +88,11 @@ impl RenderPassPlaceOverFrame {
// Begin render pass
command_buffer_builder
.begin_render_pass(
framebuffer,
RenderPassBeginInfo {
clear_values: vec![Some([0.0; 4].into())],
..RenderPassBeginInfo::framebuffer(framebuffer)
},
SubpassContents::SecondaryCommandBuffers,
vec![[0.0; 4].into()],
)
.unwrap();
// Create secondary command buffer from texture pipeline & send draw commands

View File

@ -70,13 +70,13 @@ use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, CopyImageToBufferInfo, PrimaryCommandBuffer,
SubpassContents,
RenderPassBeginInfo, SubpassContents,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
format::{ClearValue, Format},
format::Format,
image::{view::ImageView, AttachmentImage, ImageDimensions, SampleCount, StorageImage},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
@ -306,9 +306,11 @@ fn main() {
.unwrap();
builder
.begin_render_pass(
framebuffer.clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into()), None],
..RenderPassBeginInfo::framebuffer(framebuffer.clone())
},
SubpassContents::Inline,
vec![[0.0, 0.0, 1.0, 1.0].into(), ClearValue::None],
)
.unwrap()
.set_viewport(0, [viewport.clone()])

View File

@ -20,7 +20,9 @@ use bytemuck::{Pod, Zeroable};
use std::{collections::HashMap, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
@ -382,8 +384,6 @@ fn main() {
*recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),
@ -393,9 +393,11 @@ fn main() {
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
.set_viewport(0, [viewport.clone()])

View File

@ -13,7 +13,9 @@ use crate::{
};
use std::sync::Arc;
use vulkano::{
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
device::Queue,
format::Format,
image::ImageAccess,
@ -86,9 +88,11 @@ impl RenderPassPlaceOverFrame {
// Begin render pass
command_buffer_builder
.begin_render_pass(
framebuffer,
RenderPassBeginInfo {
clear_values: vec![Some([0.0; 4].into())],
..RenderPassBeginInfo::framebuffer(framebuffer)
},
SubpassContents::SecondaryCommandBuffers,
vec![[0.0; 4].into()],
)
.unwrap();
// Create secondary command buffer from texture pipeline & send draw commands

View File

@ -19,7 +19,7 @@ use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{
AutoCommandBufferBuilder, BufferImageCopy, CommandBufferUsage, CopyImageToBufferInfo,
SubpassContents,
RenderPassBeginInfo, SubpassContents,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
@ -260,8 +260,6 @@ fn main() {
.build(device.clone())
.unwrap();
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
let create_buffer = || {
CpuAccessibleBuffer::from_iter(
device.clone(),
@ -285,7 +283,13 @@ fn main() {
// drawing commands are broadcast to each view in the view mask of the active renderpass
// which means only a single draw call is needed to draw to multiple layers of the framebuffer
builder
.begin_render_pass(framebuffer.clone(), SubpassContents::Inline, clear_values)
.begin_render_pass(
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffer.clone())
},
SubpassContents::Inline,
)
.unwrap()
.bind_pipeline_graphics(pipeline.clone())
.bind_vertex_buffers(0, vertex_buffer.clone())

View File

@ -15,7 +15,9 @@ use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
use vulkano::{
buffer::{BufferAccess, BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, DeviceOwned, QueueCreateInfo,
@ -342,8 +344,6 @@ fn main() {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into(), 1.0.into()];
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),
@ -361,9 +361,11 @@ fn main() {
.set_viewport(0, [viewport.clone()])
.bind_pipeline_graphics(pipeline.clone())
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into()), Some(1.0.into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
// Begin query 0, then draw the red triangle.

View File

@ -11,7 +11,9 @@ use bytemuck::{Pod, Zeroable};
use std::{io::Cursor, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
descriptor_set::WriteDescriptorSet,
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
@ -288,7 +290,6 @@ fn main() {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),
@ -297,9 +298,11 @@ fn main() {
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
.set_viewport(0, [viewport.clone()])

View File

@ -23,7 +23,9 @@ use bytemuck::{Pod, Zeroable};
use std::{fs::File, io::Read, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
@ -273,7 +275,6 @@ fn main() {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 0.0, 1.0].into()];
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),
@ -282,9 +283,11 @@ fn main() {
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
.set_viewport(0, [viewport.clone()])

View File

@ -11,7 +11,9 @@ use bytemuck::{Pod, Zeroable};
use std::{io::Cursor, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
descriptor_set::{
layout::{
DescriptorSetLayout, DescriptorSetLayoutCreateInfo, DescriptorSetLayoutCreationError,
@ -425,7 +427,6 @@ fn main() {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),
@ -434,9 +435,11 @@ fn main() {
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
.set_viewport(0, [viewport.clone()])

View File

@ -12,7 +12,9 @@ use examples::{Normal, Vertex, INDICES, NORMALS, VERTICES};
use std::{sync::Arc, time::Instant};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, CpuBufferPool, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
@ -274,9 +276,14 @@ fn main() {
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![
Some([0.0, 0.0, 1.0, 1.0].into()),
Some(1f32.into()),
],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
vec![[0.0, 0.0, 1.0, 1.0].into(), 1f32.into()],
)
.unwrap()
.bind_pipeline_graphics(pipeline.clone())

View File

@ -22,7 +22,9 @@ use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, Features, QueueCreateInfo,
@ -387,9 +389,11 @@ fn main() {
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
vec![[0.0, 0.0, 0.0, 1.0].into()],
)
.unwrap()
.set_viewport(0, [viewport.clone()])

View File

@ -11,7 +11,9 @@ use bytemuck::{Pod, Zeroable};
use std::{io::Cursor, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
@ -297,7 +299,6 @@ fn main() {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),
@ -306,9 +307,11 @@ fn main() {
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
SubpassContents::Inline,
clear_values,
)
.unwrap()
.set_viewport(0, [viewport.clone()])

View File

@ -20,7 +20,9 @@ use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
@ -472,9 +474,6 @@ fn main() {
recreate_swapchain = true;
}
// Specify the color to clear the framebuffer with i.e. blue
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
// In order to draw, we have to build a *command buffer*. The command buffer object holds
// the list of commands that are going to be executed.
//
@ -492,17 +491,22 @@ fn main() {
.unwrap();
builder
// Before we can draw, we have to *enter a render pass*. There are two methods to do
// this: `draw_inline` and `draw_secondary`. The latter is a bit more advanced and is
// not covered here.
//
// The third parameter builds the list of values to clear the attachments with. The API
// is similar to the list of attachments when building the framebuffers, except that
// only the attachments that use `load: Clear` appear in the list.
// Before we can draw, we have to *enter a render pass*.
.begin_render_pass(
framebuffers[image_num].clone(),
RenderPassBeginInfo {
// A list of values to clear the attachments with. This list contains
// one item for each attachment in the render pass. In this case,
// there is only one attachment, and we clear it with a blue color.
//
// Only attachments that have `LoadOp::Clear` are provided with clear
// values, any others should use `ClearValue::None` as the clear value.
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone())
},
// The contents of the first (and only) subpass. This can be either
// `Inline` or `SecondaryCommandBuffers`. The latter is a bit more advanced
// and is not covered here.
SubpassContents::Inline,
clear_values,
)
.unwrap()
// We are now inside the first subpass of the render pass. We add a draw command.

View File

@ -38,11 +38,10 @@ use crate::{
image::{sys::UnsafeImage, ImageAccess, ImageLayout, ImageSubresourceRange},
pipeline::GraphicsPipeline,
query::{QueryControlFlags, QueryPipelineStatisticFlags, QueryType},
render_pass::Subpass,
render_pass::{Framebuffer, Subpass},
sync::{AccessCheckError, AccessFlags, GpuFuture, PipelineMemoryAccess, PipelineStages},
DeviceSize, OomError,
};
use smallvec::SmallVec;
use std::{
collections::HashMap,
error, fmt,
@ -85,9 +84,9 @@ pub struct AutoCommandBufferBuilder<L, P = StandardCommandPoolBuilder> {
pub(super) struct RenderPassState {
pub(super) subpass: Subpass,
pub(super) contents: SubpassContents,
pub(super) attached_layers_ranges: SmallVec<[Range<u32>; 4]>,
pub(super) extent: [u32; 2],
pub(super) framebuffer: ash::vk::Framebuffer, // Always null for secondary command buffers
pub(super) render_area_offset: [u32; 2],
pub(super) render_area_extent: [u32; 2],
pub(super) framebuffer: Option<Arc<Framebuffer>>, // In a secondary command buffer, this is only known if provided with the inheritance info.
}
// The state of an active query.
@ -286,15 +285,22 @@ impl<L> AutoCommandBufferBuilder<L, StandardCommandPoolBuilder> {
|CommandBufferInheritanceRenderPassInfo {
subpass,
framebuffer,
}| RenderPassState {
subpass: subpass.clone(),
contents: SubpassContents::Inline,
extent: framebuffer.as_ref().map(|f| f.extent()).unwrap_or_default(),
attached_layers_ranges: framebuffer
}| {
// 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 render_area_extent = framebuffer
.as_ref()
.map(|f| f.attached_layers_ranges())
.unwrap_or_default(),
framebuffer: ash::vk::Framebuffer::null(), // Only needed for primary command buffers
.map(|f| f.extent())
.unwrap_or([u32::MAX, u32::MAX]);
RenderPassState {
subpass: subpass.clone(),
contents: SubpassContents::Inline,
render_area_offset,
render_area_extent,
framebuffer: framebuffer.clone(),
}
},
);
@ -785,11 +791,6 @@ err_gen!(BuildError {
OomError,
});
err_gen!(BeginRenderPassError {
AutoCommandBufferBuilderContextError,
SyncCommandBufferBuilderError,
});
err_gen!(CopyQueryPoolResultsError {
AutoCommandBufferBuilderContextError,
CheckCopyQueryPoolResultsError,
@ -884,80 +885,6 @@ err_gen!(ResetQueryPoolError {
CheckResetQueryPoolError,
});
/// Errors that can happen when calling [`clear_attachments`](AutoCommandBufferBuilder::clear_attachments)
#[derive(Debug, Copy, Clone)]
pub enum ClearAttachmentsError {
/// AutoCommandBufferBuilderContextError
AutoCommandBufferBuilderContextError(AutoCommandBufferBuilderContextError),
/// CheckPipelineError
CheckPipelineError(CheckPipelineError),
/// The index of the color attachment is not present
InvalidColorAttachmentIndex(u32),
/// There is no depth/stencil attachment present
DepthStencilAttachmentNotPresent,
/// The clear rect cannot have extent of `0`
ZeroRectExtent,
/// The layer count cannot be `0`
ZeroLayerCount,
/// The clear rect region must be inside the render area of the render pass
RectOutOfBounds,
/// The clear rect's layers must be inside the layers ranges for all the attachments
LayersOutOfBounds,
/// If the render pass instance this is recorded in uses multiview,
/// then `ClearRect.base_array_layer` must be zero and `ClearRect.layer_count` must be one
InvalidMultiviewLayerRange,
}
impl error::Error for ClearAttachmentsError {}
impl fmt::Display for ClearAttachmentsError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
ClearAttachmentsError::AutoCommandBufferBuilderContextError(e) => write!(fmt, "{}", e)?,
ClearAttachmentsError::CheckPipelineError(e) => write!(fmt, "{}", e)?,
ClearAttachmentsError::InvalidColorAttachmentIndex(index) => {
write!(fmt, "Color attachment {} is not present", index)?
}
ClearAttachmentsError::DepthStencilAttachmentNotPresent => {
write!(fmt, "There is no depth/stencil attachment present")?
}
ClearAttachmentsError::ZeroRectExtent => {
write!(fmt, "The clear rect cannot have extent of 0")?
}
ClearAttachmentsError::ZeroLayerCount => write!(fmt, "The layer count cannot be 0")?,
ClearAttachmentsError::RectOutOfBounds => write!(
fmt,
"The clear rect region must be inside the render area of the render pass"
)?,
ClearAttachmentsError::LayersOutOfBounds => write!(
fmt,
"The clear rect's layers must be inside the layers ranges for all the attachments"
)?,
ClearAttachmentsError::InvalidMultiviewLayerRange => write!(
fmt,
"If the render pass instance this is recorded in uses multiview, then `ClearRect.base_array_layer` must be zero and `ClearRect.layer_count` must be one"
)?,
}
Ok(())
}
}
impl From<AutoCommandBufferBuilderContextError> for ClearAttachmentsError {
#[inline]
fn from(err: AutoCommandBufferBuilderContextError) -> ClearAttachmentsError {
ClearAttachmentsError::AutoCommandBufferBuilderContextError(err)
}
}
impl From<CheckPipelineError> for ClearAttachmentsError {
#[inline]
fn from(err: CheckPipelineError) -> ClearAttachmentsError {
ClearAttachmentsError::CheckPipelineError(err)
}
}
#[derive(Debug, Copy, Clone)]
pub enum AutoCommandBufferBuilderContextError {
/// Operation forbidden inside of a render pass.

File diff suppressed because it is too large Load Diff

View File

@ -170,7 +170,7 @@ where
// Framebuffer, if present on the secondary command buffer, must be the
// same as the one in the current render pass.
if let Some(framebuffer) = &render_pass.framebuffer {
if framebuffer.internal_object() != render_pass_state.framebuffer {
if Some(framebuffer) != render_pass_state.framebuffer.as_ref() {
return Err(AutoCommandBufferBuilderContextError::IncompatibleFramebuffer);
}
}

View File

@ -91,6 +91,7 @@ pub use self::commands::{
CheckBeginQueryError, CheckCopyQueryPoolResultsError, CheckEndQueryError,
CheckResetQueryPoolError, CheckWriteTimestampError,
},
render_pass::{ClearAttachment, ClearRect, RenderPassBeginInfo, RenderPassError},
transfer::{
BufferCopy, BufferImageCopy, CopyBufferInfo, CopyBufferInfoTyped, CopyBufferToImageInfo,
CopyImageInfo, CopyImageToBufferInfo, FillBufferInfo, ImageCopy,
@ -100,11 +101,10 @@ pub use self::commands::{
pub use self::{
auto::{
AutoCommandBufferBuilder, AutoCommandBufferBuilderContextError, BeginError,
BeginQueryError, BeginRenderPassError, BuildError, CopyQueryPoolResultsError,
DispatchError, DispatchIndirectError, DrawError, DrawIndexedError,
DrawIndexedIndirectError, DrawIndirectError, EndQueryError, ExecuteCommandsError,
PrimaryAutoCommandBuffer, ResetQueryPoolError, SecondaryAutoCommandBuffer,
WriteTimestampError,
BeginQueryError, BuildError, CopyQueryPoolResultsError, DispatchError,
DispatchIndirectError, DrawError, DrawIndexedError, DrawIndexedIndirectError,
DrawIndirectError, EndQueryError, ExecuteCommandsError, PrimaryAutoCommandBuffer,
ResetQueryPoolError, SecondaryAutoCommandBuffer, WriteTimestampError,
},
traits::{
CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBuffer,

View File

@ -8,7 +8,7 @@
// according to those terms.
pub use super::commands::{
bind_push::UnsafeCommandBufferBuilderBindVertexBuffer, render_pass::RenderPassBeginInfo,
bind_push::UnsafeCommandBufferBuilderBindVertexBuffer,
secondary::UnsafeCommandBufferBuilderExecuteCommands,
};
use super::{

View File

@ -159,41 +159,6 @@ impl Format {
| Format::R8_UINT
)
}
#[inline]
pub fn decode_clear_value(&self, value: ClearValue) -> ClearValue {
let aspects = self.aspects();
if aspects.depth && aspects.stencil {
assert!(matches!(value, ClearValue::DepthStencil(_)));
} else if aspects.depth {
assert!(matches!(value, ClearValue::Depth(_)));
} else if aspects.stencil {
assert!(matches!(value, ClearValue::Stencil(_)));
} else if let Some(numeric_type) = self.type_color() {
match numeric_type {
NumericType::SFLOAT
| NumericType::UFLOAT
| NumericType::SNORM
| NumericType::UNORM
| NumericType::SSCALED
| NumericType::USCALED
| NumericType::SRGB => {
assert!(matches!(value, ClearValue::Float(_)));
}
NumericType::SINT => {
assert!(matches!(value, ClearValue::Int(_)));
}
NumericType::UINT => {
assert!(matches!(value, ClearValue::Uint(_)));
}
}
} else {
panic!("Shouldn't happen!");
}
value
}
}
impl From<Format> for ash::vk::Format {
@ -421,25 +386,67 @@ pub(crate) enum FormatCompatibilityInner {
}
/// Describes a uniform value that will be used to fill an image.
// TODO: should have the same layout as `vk::ClearValue` for performance
#[derive(Debug, Copy, Clone, PartialEq)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ClearValue {
/// Entry for attachments that aren't cleared.
None,
/// Value for floating-point attachments, including `UNORM`, `SNORM`, `SFLOAT`.
Float([f32; 4]),
/// Value for integer attachments, including `SINT`.
Int([i32; 4]),
/// Value for unsigned integer attachments, including `UINT`.
Uint([u32; 4]),
/// Value for depth attachments.
Depth(f32),
/// Value for stencil attachments.
Stencil(u32),
/// Value for depth and stencil attachments.
DepthStencil((f32, u32)),
}
impl From<ClearValue> for ash::vk::ClearValue {
#[inline]
fn from(val: ClearValue) -> Self {
match val {
ClearValue::Float(val) => Self {
color: ash::vk::ClearColorValue { float32: val },
},
ClearValue::Int(val) => Self {
color: ash::vk::ClearColorValue { int32: val },
},
ClearValue::Uint(val) => Self {
color: ash::vk::ClearColorValue { uint32: val },
},
ClearValue::Depth(depth) => Self {
depth_stencil: ash::vk::ClearDepthStencilValue { depth, stencil: 0 },
},
ClearValue::Stencil(stencil) => Self {
depth_stencil: ash::vk::ClearDepthStencilValue {
depth: 0.0,
stencil,
},
},
ClearValue::DepthStencil((depth, stencil)) => Self {
depth_stencil: ash::vk::ClearDepthStencilValue { depth, stencil },
},
}
}
}
impl From<ClearColorValue> for ClearValue {
#[inline]
fn from(val: ClearColorValue) -> Self {
match val {
ClearColorValue::Float(val) => Self::Float(val),
ClearColorValue::Int(val) => Self::Int(val),
ClearColorValue::Uint(val) => Self::Uint(val),
}
}
}
impl From<[f32; 1]> for ClearValue {
#[inline]
fn from(val: [f32; 1]) -> Self {

View File

@ -8,14 +8,12 @@
// according to those terms.
use super::{
sys::UnsafeImage,
traits::{ImageClearValue, ImageContent},
ImageAccess, ImageCreationError, ImageDescriptorLayouts, ImageInner, ImageLayout, ImageUsage,
SampleCount,
sys::UnsafeImage, traits::ImageContent, ImageAccess, ImageCreationError,
ImageDescriptorLayouts, ImageInner, ImageLayout, ImageUsage, SampleCount,
};
use crate::{
device::{Device, DeviceOwned},
format::{ClearValue, Format},
format::Format,
image::{sys::UnsafeImageCreateInfo, ImageDimensions},
memory::{
pool::{
@ -603,16 +601,6 @@ unsafe impl<A> DeviceOwned for AttachmentImage<A> {
}
}
unsafe impl<A> ImageClearValue<ClearValue> for AttachmentImage<A>
where
A: MemoryPoolAlloc,
{
#[inline]
fn decode(&self, value: ClearValue) -> Option<ClearValue> {
Some(self.format.decode_clear_value(value))
}
}
unsafe impl<P, A> ImageContent<P> for AttachmentImage<A>
where
A: MemoryPoolAlloc,
@ -645,74 +633,6 @@ where
}
}
/// Clear attachment type, used in [`clear_attachments`](crate::command_buffer::AutoCommandBufferBuilder::clear_attachments) command.
pub enum ClearAttachment {
/// Clear the color attachment at the specified index, with the specified clear value.
Color(ClearValue, u32),
/// Clear the depth attachment with the speficied depth value.
Depth(f32),
/// Clear the stencil attachment with the speficied stencil value.
Stencil(u32),
/// Clear the depth and stencil attachments with the speficied depth and stencil values.
DepthStencil((f32, u32)),
}
impl From<ClearAttachment> for ash::vk::ClearAttachment {
fn from(v: ClearAttachment) -> Self {
match v {
ClearAttachment::Color(clear_value, color_attachment) => ash::vk::ClearAttachment {
aspect_mask: ash::vk::ImageAspectFlags::COLOR,
color_attachment,
clear_value: ash::vk::ClearValue {
color: match clear_value {
ClearValue::Float(val) => ash::vk::ClearColorValue { float32: val },
ClearValue::Int(val) => ash::vk::ClearColorValue { int32: val },
ClearValue::Uint(val) => ash::vk::ClearColorValue { uint32: val },
_ => ash::vk::ClearColorValue { float32: [0.0; 4] },
},
},
},
ClearAttachment::Depth(depth) => ash::vk::ClearAttachment {
aspect_mask: ash::vk::ImageAspectFlags::DEPTH,
color_attachment: 0,
clear_value: ash::vk::ClearValue {
depth_stencil: ash::vk::ClearDepthStencilValue { depth, stencil: 0 },
},
},
ClearAttachment::Stencil(stencil) => ash::vk::ClearAttachment {
aspect_mask: ash::vk::ImageAspectFlags::STENCIL,
color_attachment: 0,
clear_value: ash::vk::ClearValue {
depth_stencil: ash::vk::ClearDepthStencilValue {
depth: 0.0,
stencil,
},
},
},
ClearAttachment::DepthStencil((depth, stencil)) => ash::vk::ClearAttachment {
aspect_mask: ash::vk::ImageAspectFlags::DEPTH | ash::vk::ImageAspectFlags::STENCIL,
color_attachment: 0,
clear_value: ash::vk::ClearValue {
depth_stencil: ash::vk::ClearDepthStencilValue { depth, stencil },
},
},
}
}
}
/// Specifies the clear region for the [`clear_attachments`](crate::command_buffer::AutoCommandBufferBuilder::clear_attachments) command.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ClearRect {
/// The rectangle offset.
pub rect_offset: [u32; 2],
/// The width and height of the rectangle.
pub rect_extent: [u32; 2],
/// The first layer to be cleared.
pub base_array_layer: u32,
/// The number of layers to be cleared.
pub layer_count: u32,
}
#[cfg(test)]
mod tests {
use super::AttachmentImage;

View File

@ -8,14 +8,12 @@
// according to those terms.
use super::{
sys::UnsafeImage,
traits::{ImageClearValue, ImageContent},
ImageAccess, ImageCreateFlags, ImageCreationError, ImageDescriptorLayouts, ImageDimensions,
ImageInner, ImageLayout, ImageUsage,
sys::UnsafeImage, traits::ImageContent, ImageAccess, ImageCreateFlags, ImageCreationError,
ImageDescriptorLayouts, ImageDimensions, ImageInner, ImageLayout, ImageUsage,
};
use crate::{
device::{physical::QueueFamily, Device, DeviceOwned},
format::{ClearValue, Format},
format::Format,
image::sys::UnsafeImageCreateInfo,
memory::{
pool::{
@ -284,16 +282,6 @@ where
}
}
unsafe impl<A> ImageClearValue<ClearValue> for StorageImage<A>
where
A: MemoryPool,
{
#[inline]
fn decode(&self, value: ClearValue) -> Option<ClearValue> {
Some(self.format.decode_clear_value(value))
}
}
unsafe impl<P, A> ImageContent<P> for StorageImage<A>
where
A: MemoryPool,

View File

@ -7,13 +7,9 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::{
traits::{ImageClearValue, ImageContent},
ImageAccess, ImageDescriptorLayouts, ImageInner, ImageLayout,
};
use super::{traits::ImageContent, ImageAccess, ImageDescriptorLayouts, ImageInner, ImageLayout};
use crate::{
device::{Device, DeviceOwned},
format::ClearValue,
swapchain::Swapchain,
OomError,
};
@ -126,16 +122,6 @@ where
}
}
unsafe impl<W> ImageClearValue<ClearValue> for SwapchainImage<W>
where
W: Send + Sync,
{
#[inline]
fn decode(&self, value: ClearValue) -> Option<ClearValue> {
Some(self.swapchain.image_format().decode_clear_value(value))
}
}
unsafe impl<P, W> ImageContent<P> for SwapchainImage<W>
where
W: Send + Sync,

View File

@ -13,7 +13,7 @@ use super::{
};
use crate::{
device::{Device, DeviceOwned},
format::{ClearValue, Format, FormatFeatures},
format::{Format, FormatFeatures},
SafeDeref,
};
use std::{
@ -315,13 +315,6 @@ where
}
}
/// Extension trait for images. Checks whether the value `T` can be used as a clear value for the
/// given image.
// TODO: isn't that for image views instead?
pub unsafe trait ImageClearValue<T>: ImageAccess {
fn decode(&self, value: T) -> Option<ClearValue>;
}
pub unsafe trait ImageContent<P>: ImageAccess {
/// Checks whether pixels of type `P` match the format of the image.
fn matches_format(&self) -> bool;

View File

@ -76,41 +76,28 @@ impl RenderPass {
.potential_format_features(),
);
if aspects.color {
// VUID-VkAttachmentDescription2-format-03294
if matches!(
initial_layout,
for layout in [initial_layout, final_layout] {
match layout {
ImageLayout::ColorAttachmentOptimal => {
// VUID-VkAttachmentDescription2-format-03295
// VUID-VkAttachmentDescription2-format-03297
if aspects.depth || aspects.stencil {
return Err(RenderPassCreationError::AttachmentLayoutInvalid {
attachment: atch_num,
});
}
}
ImageLayout::DepthStencilAttachmentOptimal
| ImageLayout::DepthStencilReadOnlyOptimal
) {
return Err(RenderPassCreationError::AttachmentLayoutInvalid {
attachment: atch_num,
});
}
// VUID-VkAttachmentDescription2-format-03296
if matches!(
final_layout,
ImageLayout::DepthStencilAttachmentOptimal
| ImageLayout::DepthStencilReadOnlyOptimal
) {
return Err(RenderPassCreationError::AttachmentLayoutInvalid {
attachment: atch_num,
});
}
} else if aspects.depth || aspects.stencil {
// VUID-VkAttachmentDescription2-format-03295
if matches!(initial_layout, ImageLayout::ColorAttachmentOptimal) {
return Err(RenderPassCreationError::AttachmentLayoutInvalid {
attachment: atch_num,
});
}
// VUID-VkAttachmentDescription2-format-03297
if matches!(final_layout, ImageLayout::ColorAttachmentOptimal) {
return Err(RenderPassCreationError::AttachmentLayoutInvalid {
attachment: atch_num,
});
| ImageLayout::DepthStencilReadOnlyOptimal => {
// VUID-VkAttachmentDescription2-format-03294
// VUID-VkAttachmentDescription2-format-03296
if aspects.color {
return Err(RenderPassCreationError::AttachmentLayoutInvalid {
attachment: atch_num,
});
}
}
_ => (),
}
}
}

View File

@ -37,6 +37,7 @@ use crate::{
sync::{AccessFlags, PipelineStages},
Version, VulkanObject,
};
use std::cmp::max;
use std::{
hash::{Hash, Hasher},
mem::MaybeUninit,
@ -243,22 +244,195 @@ impl RenderPass {
}
/// Returns `true` if this render pass is compatible with the other render pass,
/// as defined in the `Render Pass Compatibility` section of the Vulkan specs.
// TODO: return proper error
/// as defined in the [`Render Pass Compatibility` section of the Vulkan specs](https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/chap8.html#renderpass-compatibility).
pub fn is_compatible_with(&self, other: &RenderPass) -> bool {
if self.attachments().len() != other.attachments().len() {
if self == other {
return true;
}
let Self {
handle: _,
device: _,
attachments: attachments1,
subpasses: subpasses1,
dependencies: dependencies1,
correlated_view_masks: correlated_view_masks1,
granularity: _,
views_used: _,
} = self;
let Self {
handle: _,
device: _,
attachments: attachments2,
subpasses: subpasses2,
dependencies: dependencies2,
correlated_view_masks: correlated_view_masks2,
granularity: _,
views_used: _,
} = other;
if attachments1.len() != attachments2.len() {
return false;
}
for (my_atch, other_atch) in self.attachments.iter().zip(other.attachments.iter()) {
if !my_atch.is_compatible_with(&other_atch) {
return false;
}
if !attachments1
.iter()
.zip(attachments2)
.all(|(attachment_desc1, attachment_desc2)| {
let AttachmentDescription {
format: format1,
samples: samples1,
load_op: _,
store_op: _,
stencil_load_op: _,
stencil_store_op: _,
initial_layout: _,
final_layout: _,
_ne: _,
} = attachment_desc1;
let AttachmentDescription {
format: format2,
samples: samples2,
load_op: _,
store_op: _,
stencil_load_op: _,
stencil_store_op: _,
initial_layout: _,
final_layout: _,
_ne: _,
} = attachment_desc2;
format1 == format2 && samples1 == samples2
})
{
return false;
}
return true;
let are_atch_refs_compatible = |atch_ref1, atch_ref2| match (atch_ref1, atch_ref2) {
(None, None) => true,
(Some(atch_ref1), Some(atch_ref2)) => {
let &AttachmentReference {
attachment: attachment1,
layout: _,
aspects: aspects1,
_ne: _,
} = atch_ref1;
let AttachmentDescription {
format: format1,
samples: samples1,
load_op: _,
store_op: _,
stencil_load_op: _,
stencil_store_op: _,
initial_layout: _,
final_layout: _,
_ne: _,
} = &attachments1[attachment1 as usize];
// FIXME: finish
let &AttachmentReference {
attachment: attachment2,
layout: _,
aspects: aspects2,
_ne: _,
} = atch_ref2;
let AttachmentDescription {
format: format2,
samples: samples2,
load_op: _,
store_op: _,
stencil_load_op: _,
stencil_store_op: _,
initial_layout: _,
final_layout: _,
_ne: _,
} = &attachments2[attachment2 as usize];
format1 == format2 && samples1 == samples2 && aspects1 == aspects2
}
_ => false,
};
if subpasses1.len() != subpasses2.len() {
return false;
}
if !(subpasses1.iter())
.zip(subpasses2.iter())
.all(|(subpass1, subpass2)| {
let &SubpassDescription {
view_mask: view_mask1,
input_attachments: ref input_attachments1,
color_attachments: ref color_attachments1,
resolve_attachments: ref resolve_attachments1,
depth_stencil_attachment: ref depth_stencil_attachment1,
preserve_attachments: _,
_ne: _,
} = subpass1;
let &SubpassDescription {
view_mask: view_mask2,
input_attachments: ref input_attachments2,
color_attachments: ref color_attachments2,
resolve_attachments: ref resolve_attachments2,
depth_stencil_attachment: ref depth_stencil_attachment2,
preserve_attachments: _,
_ne: _,
} = subpass2;
if !(0..max(input_attachments1.len(), input_attachments2.len())).all(|i| {
are_atch_refs_compatible(
input_attachments1.get(i).and_then(|x| x.as_ref()),
input_attachments2.get(i).and_then(|x| x.as_ref()),
)
}) {
return false;
}
if !(0..max(color_attachments1.len(), color_attachments2.len())).all(|i| {
are_atch_refs_compatible(
color_attachments1.get(i).and_then(|x| x.as_ref()),
color_attachments2.get(i).and_then(|x| x.as_ref()),
)
}) {
return false;
}
if subpasses1.len() > 1
&& !(0..max(resolve_attachments1.len(), resolve_attachments2.len())).all(|i| {
are_atch_refs_compatible(
resolve_attachments1.get(i).and_then(|x| x.as_ref()),
resolve_attachments2.get(i).and_then(|x| x.as_ref()),
)
})
{
return false;
}
if !are_atch_refs_compatible(
depth_stencil_attachment1.as_ref(),
depth_stencil_attachment2.as_ref(),
) {
return false;
}
if view_mask1 != view_mask2 {
return false;
}
true
})
{
return false;
}
if dependencies1 != dependencies2 {
return false;
}
if correlated_view_masks1 != correlated_view_masks2 {
return false;
}
true
}
/// Returns `true` if the subpass of this description is compatible with the shader's fragment
@ -384,6 +558,18 @@ impl Subpass {
}
}
/// Returns the render pass of this subpass.
#[inline]
pub fn render_pass(&self) -> &Arc<RenderPass> {
&self.render_pass
}
/// Returns the index of this subpass within the renderpass.
#[inline]
pub fn index(&self) -> u32 {
self.subpass_id
}
/// Returns the subpass description for this subpass.
#[inline]
pub fn subpass_desc(&self) -> &SubpassDescription {
@ -391,23 +577,22 @@ impl Subpass {
}
/// Returns whether this subpass is the last one in the render pass. If `true` is returned,
/// `next_subpass` will return `None`.
/// calling `next_subpass` will panic.
#[inline]
pub fn is_last_subpass(&self) -> bool {
self.subpass_id as usize == self.render_pass.subpasses().len() - 1
}
/// Tries to advance to the next subpass after this one, and returns `true` if successful.
/// Advances to the next subpass after this one.
///
/// # Panics
///
/// - Panics if there are no more render passes.
#[inline]
pub fn try_next_subpass(&mut self) -> bool {
pub fn next_subpass(&mut self) {
let next_id = self.subpass_id + 1;
if (next_id as usize) < self.render_pass.subpasses().len() {
self.subpass_id = next_id;
true
} else {
false
}
assert!((next_id as usize) < self.render_pass.subpasses().len());
self.subpass_id = next_id;
}
#[inline]
@ -490,30 +675,6 @@ impl Subpass {
.map_or(false, |f| f.aspects().stencil)
}
/// Returns true if the subpass has any depth/stencil attachment.
#[inline]
pub fn has_depth_stencil_attachment(&self) -> bool {
let subpass_desc = self.subpass_desc();
match &subpass_desc.depth_stencil_attachment {
Some(atch_ref) => true,
None => false,
}
}
/// Returns true if the subpass has any color or depth/stencil attachment.
#[inline]
pub fn has_color_or_depth_stencil_attachment(&self) -> bool {
if self.num_color_attachments() >= 1 {
return true;
}
let subpass_desc = self.subpass_desc();
match &subpass_desc.depth_stencil_attachment {
Some(atch_ref) => true,
None => false,
}
}
/// Returns the number of samples in the color and/or depth/stencil attachments. Returns `None`
/// if there is no such attachment in this subpass.
#[inline]
@ -535,18 +696,6 @@ impl Subpass {
.map(|atch_desc| atch_desc.samples)
}
/// Returns the render pass of this subpass.
#[inline]
pub fn render_pass(&self) -> &Arc<RenderPass> {
&self.render_pass
}
/// Returns the index of this subpass within the renderpass.
#[inline]
pub fn index(&self) -> u32 {
self.subpass_id
}
/// Returns `true` if this subpass is compatible with the fragment output definition.
// TODO: return proper error
pub fn is_compatible_with(&self, shader_interface: &ShaderInterface) -> bool {
@ -682,15 +831,6 @@ impl Default for AttachmentDescription {
}
}
impl AttachmentDescription {
/// Returns true if this attachment is compatible with another attachment, as defined in the
/// `Render Pass Compatibility` section of the Vulkan specs.
#[inline]
pub fn is_compatible_with(&self, other: &AttachmentDescription) -> bool {
self.format == other.format && self.samples == other.samples
}
}
/// Describes one of the subpasses of a render pass.
///
/// A subpass can use zero or more attachments of various types. Attachment types of which there can
@ -847,7 +987,7 @@ impl Default for AttachmentReference {
/// the render pass instance began (for `source_subpass`), or on commands that will be submitted
/// after the render pass instance ends (for `destination_subpass`). The values must not both be
/// `None`.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SubpassDependency {
/// The index of the subpass that writes the data that `destination_subpass` is going to use.
///