diff options
| author | Irene Knapp <ireneista@irenes.space> | 2026-08-14 02:35:23 -0700 |
|---|---|---|
| committer | Irene Knapp <ireneista@irenes.space> | 2026-08-14 02:35:23 -0700 |
| commit | 5a4fad7b67a6ab477b230f4d8a70efed0e9100cb (patch) | |
| tree | 95f10f8106a225e0fcd4a1fbd0d0bca2ced51b38 /src/graphics | |
| parent | 19e3a0f319fd04c1dde803796ec272d038b634f7 (diff) | |
move all the per-frame stuff into its own struct and file
Force-Push: yes Change-Id: I54b5c8fcc692616f83a37039a445796dddd4b7e4
Diffstat (limited to 'src/graphics')
| -rw-r--r-- | src/graphics/frame.rs | 227 | ||||
| -rw-r--r-- | src/graphics/mod.rs | 2 | ||||
| -rw-r--r-- | src/graphics/render.rs | 180 | ||||
| -rw-r--r-- | src/graphics/scene.rs | 7 |
4 files changed, 249 insertions, 167 deletions
diff --git a/src/graphics/frame.rs b/src/graphics/frame.rs new file mode 100644 index 0000000..721eced --- /dev/null +++ b/src/graphics/frame.rs @@ -0,0 +1,227 @@ +#![deny(unsafe_code)] +use crate::error::*; +use crate::graphics::{ Permanent, ForReinit, WindowDressing, Texture }; +use crate::shader_data::UniformBlock; + +use std::mem::size_of; + +use vulkanalia::Device; +use vulkanalia::vk::{ self, HasBuilder, DeviceV1_0 }; + + +// Frame is a state object that collects the Vulkan graphics objects which +// are used as part of rendering and which need to exist in multiples, one for +// each frame that can be rendered in parallel (see N_SIMULTANEOUS_FRAMES in +// window_dressing.rs). As with WindowDressing, these need to be regenerated +// or modified when the window changes. +#[derive(Debug)] +pub struct Frame { + pub framebuffer: vk::Framebuffer, + pub command_buffer: vk::CommandBuffer, + pub descriptor_set: vk::DescriptorSet, +} + + +impl Frame { + // The lifecycle stuff for Frame is a little different. The Vulkan API to + // allocate and deallocate command buffers is designed on the assumption you + // want to handle a few of them simultaneously. That is in fact what we want, + // so the interfaces to new() and reinit() work on Vec<Frame> instead of on + // an indidivual Frame. + pub fn new(permanent: &Permanent, for_reinit: &ForReinit, + window_dressing: &WindowDressing, texture: &Texture, + render_pass: &vk::RenderPass) + -> Result<Vec<Self>> + { + let device = &permanent.device; + let primary_command_pool = &permanent.primary_command_pool; + let descriptor_set_layout = &for_reinit.descriptor_set_layout; + let swapchain = &window_dressing.swapchain; + let color_image_view = &window_dressing.color_image_view; + let depth_image_view = &window_dressing.depth_image_view; + let uniform_buffers = &window_dressing.uniform_buffers; + let descriptor_pool = &window_dressing.descriptor_pool; + let sampler = &window_dressing.sampler; + + let count = swapchain.image_views.len(); + + let command_buffers = init_command_buffers(count, device, + primary_command_pool)?; + + let descriptor_sets + = init_descriptor_sets(count, device, descriptor_set_layout, + &uniform_buffers, &descriptor_pool, + &texture.image_view, &sampler)?; + + let mut frames = Vec::new(); + for (index, color_resolve_image_view) + in swapchain.image_views.iter().enumerate() + { + let framebuffer = init_framebuffer( + device, &swapchain.extent, &color_image_view, &depth_image_view, + color_resolve_image_view, &render_pass)?; + + frames.push(Frame { + command_buffer: command_buffers[index], + descriptor_set: descriptor_sets[index], + framebuffer, + }); + } + + Ok(frames) + } + + // See new() in regard to the Vec. + pub fn reinit(frames: &mut Vec<Self>, permanent: &Permanent, + for_reinit: &ForReinit, window_dressing: &WindowDressing, + texture: &Texture, render_pass: &vk::RenderPass) + -> Result<()> + { + let device = &permanent.device; + let primary_command_pool = &permanent.primary_command_pool; + let descriptor_set_layout = &for_reinit.descriptor_set_layout; + let swapchain = &window_dressing.swapchain; + let color_image_view = &window_dressing.color_image_view; + let depth_image_view = &window_dressing.depth_image_view; + let uniform_buffers = &window_dressing.uniform_buffers; + let descriptor_pool = &window_dressing.descriptor_pool; + let sampler = &window_dressing.sampler; + + frames.clear(); + + let count = swapchain.image_views.len(); + + // Notice that we reused the command pool. + let command_buffers = init_command_buffers(count, device, + primary_command_pool)?; + + let descriptor_sets + = init_descriptor_sets(count, device, descriptor_set_layout, + &uniform_buffers, &descriptor_pool, + &texture.image_view, sampler)?; + + for (index, color_resolve_image_view) + in swapchain.image_views.iter().enumerate() + { + let framebuffer = init_framebuffer( + device, &swapchain.extent, &color_image_view, &depth_image_view, + color_resolve_image_view, &render_pass)?; + + frames.push(Frame { + command_buffer: command_buffers[index], + descriptor_set: descriptor_sets[index], + framebuffer, + }); + } + + Ok(()) + } +} + + +#[allow(unsafe_code)] +fn init_framebuffer(device: &Device, extent: &vk::Extent2D, + color_image_view: &vk::ImageView, + depth_image_view: &vk::ImageView, + color_resolve_image_view: &vk::ImageView, + render_pass: &vk::RenderPass) + -> Result<vk::Framebuffer> +{ + let attachments = [*color_image_view, + *depth_image_view, + *color_resolve_image_view]; + + let framebuffer_info = vk::FramebufferCreateInfo::builder() + .render_pass(*render_pass) + .attachments(&attachments) + .width(extent.width) + .height(extent.height) + .layers(1); + + let framebuffer = unsafe { + device.create_framebuffer(&framebuffer_info, None) + }?; + + Ok(framebuffer) +} + + +#[allow(unsafe_code)] +fn init_command_buffers(count: usize, device: &Device, + command_pool: &vk::CommandPool) + -> Result<Vec<vk::CommandBuffer>> +{ + let command_buffer_allocation_info + = vk::CommandBufferAllocateInfo::builder() + .command_pool(*command_pool) + .level(vk::CommandBufferLevel::PRIMARY) + .command_buffer_count(count as u32); + let command_buffers = unsafe { + device.allocate_command_buffers(&command_buffer_allocation_info) + }?; + + Ok(command_buffers) +} + + +#[allow(unsafe_code)] +fn init_descriptor_sets(count: usize, device: &Device, + layout: &vk::DescriptorSetLayout, + buffers: &Vec<vk::Buffer>, pool: &vk::DescriptorPool, + texture_image_view: &vk::ImageView, + sampler: &vk::Sampler) + -> Result<Vec<vk::DescriptorSet>> +{ + let layouts = vec![*layout; count]; + let set_info = vk::DescriptorSetAllocateInfo::builder() + .descriptor_pool(*pool) + .set_layouts(&layouts); + let sets = unsafe { device.allocate_descriptor_sets(&set_info) }?; + + for index in 0 .. count { + let buffer_info = vk::DescriptorBufferInfo::builder() + .buffer(buffers[index]) + .offset(0) + .range(size_of::<UniformBlock<f32>>() as vk::DeviceSize); + + let buffer_info_list = [buffer_info]; + let uniform_block_write_info = vk::WriteDescriptorSet::builder() + .dst_set(sets[index]) + .dst_binding(0) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) + .buffer_info(&buffer_info_list); + + let sampler_image_info = vk::DescriptorImageInfo::builder() + .sampler(*sampler); + let sampler_image_info_list = [sampler_image_info]; + let sampler_write_info = vk::WriteDescriptorSet::builder() + .dst_set(sets[index]) + .dst_binding(1) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::SAMPLER) + .image_info(&sampler_image_info_list); + + let texture_image_info = vk::DescriptorImageInfo::builder() + .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) + .image_view(*texture_image_view); + let texture_image_info_list = [texture_image_info]; + let texture_write_info = vk::WriteDescriptorSet::builder() + .dst_set(sets[index]) + .dst_binding(2) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) + .image_info(&texture_image_info_list); + + let write_info_list = [ + uniform_block_write_info, sampler_write_info, texture_write_info + ]; + let copy_info_list: [vk::CopyDescriptorSet; 0] = []; + + unsafe { + device.update_descriptor_sets(&write_info_list, ©_info_list) + }; + } + + Ok(sets) +} diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index bb12c80..7b46cb1 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -1,4 +1,5 @@ #![deny(unsafe_code)] +pub mod frame; pub mod model; pub mod permanent; pub mod render; @@ -7,6 +8,7 @@ pub mod scene; pub mod util; pub mod window_dressing; +pub use crate::graphics::frame::Frame; pub use crate::graphics::model::Model; pub use crate::graphics::texture::Texture; pub use crate::graphics::permanent::{ Permanent, ForReinit }; diff --git a/src/graphics/render.rs b/src/graphics/render.rs index c88b1d6..00e55ee 100644 --- a/src/graphics/render.rs +++ b/src/graphics/render.rs @@ -1,8 +1,10 @@ #![deny(unsafe_code)] use crate::error::*; use crate::assets::asset; -use crate::graphics::{ Permanent, ForReinit, WindowDressing, Model, Texture }; -use crate::shader_data::{ Vertex, UniformBlock, VertexPushBlock }; +use crate::graphics::{ + Permanent, ForReinit, WindowDressing, Frame, Model, Texture +}; +use crate::shader_data::{ Vertex, VertexPushBlock }; use std::mem::size_of; @@ -22,9 +24,7 @@ pub struct Render { pub model: Option<Model>, - pub framebuffers: Vec<vk::Framebuffer>, - pub command_buffers: Vec<vk::CommandBuffer>, - pub descriptor_sets: Vec<vk::DescriptorSet>, + pub per_frame: Vec<Frame>, } @@ -34,16 +34,10 @@ impl Render { -> Result<Self> { let device = &permanent.device; - let primary_command_pool = &permanent.primary_command_pool; let sample_count = for_reinit.sample_count; let descriptor_set_layout = &for_reinit.descriptor_set_layout; let swapchain = &window_dressing.swapchain; let depth_format = &window_dressing.depth_format; - let color_image_view = &window_dressing.color_image_view; - let depth_image_view = &window_dressing.depth_image_view; - let uniform_buffers = &window_dressing.uniform_buffers; - let descriptor_pool = &window_dressing.descriptor_pool; - let sampler = &window_dressing.sampler; let render_pass = init_render_pass(device, sample_count, &swapchain.format, &depth_format)?; @@ -52,18 +46,8 @@ impl Render { = init_pipeline(device, descriptor_set_layout, &swapchain.extent, sample_count, &render_pass)?; - let framebuffers = init_framebuffers( - device, &swapchain.extent, &swapchain.image_views, - &color_image_view, &depth_image_view, &render_pass)?; - - let command_buffers = init_command_buffers(device, &framebuffers, - primary_command_pool)?; - - let descriptor_sets - = init_descriptor_sets(device, descriptor_set_layout, - &uniform_buffers, &descriptor_pool, - swapchain.images.len(), - &texture.image_view, &sampler)?; + let per_frame = Frame::new(permanent, for_reinit, window_dressing, + texture, &render_pass)?; let model = None; @@ -72,9 +56,7 @@ impl Render { pipeline, pipeline_layout, model, - framebuffers, - command_buffers, - descriptor_sets, + per_frame, }) } @@ -88,16 +70,10 @@ impl Render { self.destroy_replaceable(permanent); let device = &permanent.device; - let primary_command_pool = &permanent.primary_command_pool; let sample_count = for_reinit.sample_count; let descriptor_set_layout = &for_reinit.descriptor_set_layout; let swapchain = &window_dressing.swapchain; let depth_format = &window_dressing.depth_format; - let color_image_view = &window_dressing.color_image_view; - let depth_image_view = &window_dressing.depth_image_view; - let uniform_buffers = &window_dressing.uniform_buffers; - let descriptor_pool = &window_dressing.descriptor_pool; - let sampler = &window_dressing.sampler; let render_pass = init_render_pass(device, sample_count, &swapchain.format, &depth_format)?; @@ -106,26 +82,12 @@ impl Render { = init_pipeline(device, descriptor_set_layout, &swapchain.extent, sample_count, &render_pass)?; - let framebuffers = init_framebuffers( - device, &swapchain.extent, &swapchain.image_views, - &color_image_view, &depth_image_view, &render_pass)?; - - // Notice that we reused the command pool. - let command_buffers = init_command_buffers(device, &framebuffers, - primary_command_pool)?; - - let descriptor_sets - = init_descriptor_sets(device, descriptor_set_layout, - &uniform_buffers, &descriptor_pool, - swapchain.images.len(), - &texture.image_view, sampler)?; + Frame::reinit(&mut self.per_frame, permanent, for_reinit, window_dressing, + texture, &render_pass)?; self.render_pass = render_pass; self.pipeline = pipeline; self.pipeline_layout = pipeline_layout; - self.framebuffers = framebuffers; - self.command_buffers = command_buffers; - self.descriptor_sets = descriptor_sets; Ok(()) } @@ -145,8 +107,11 @@ impl Render { fn destroy_replaceable(&mut self, permanent: &Permanent) { let device = &permanent.device; - for framebuffer in &self.framebuffers { - unsafe { device.destroy_framebuffer(*framebuffer, None) }; + let mut command_buffers = Vec::new(); + for frame in &self.per_frame { + unsafe { device.destroy_framebuffer(frame.framebuffer, None) }; + + command_buffers.push(frame.command_buffer); } // Notice that we free the buffers in the pool, but do not destroy the @@ -156,7 +121,7 @@ impl Render { // immediately after using them. unsafe { device.free_command_buffers(permanent.primary_command_pool, - &self.command_buffers) + &command_buffers) }; unsafe { device.destroy_pipeline(self.pipeline, None) }; @@ -392,116 +357,3 @@ fn init_pipeline(device: &Device, Ok((pipeline_layout, pipeline)) } - -#[allow(unsafe_code)] -fn init_framebuffers(device: &Device, extent: &vk::Extent2D, - swapchain_image_views: &Vec<vk::ImageView>, - color_image_view: &vk::ImageView, - depth_image_view: &vk::ImageView, - render_pass: &vk::RenderPass) - -> Result<Vec<vk::Framebuffer>> -{ - let mut framebuffers = Vec::new(); - - for color_resolve_image_view in swapchain_image_views { - let attachments = [*color_image_view, - *depth_image_view, - *color_resolve_image_view]; - - let framebuffer_info = vk::FramebufferCreateInfo::builder() - .render_pass(*render_pass) - .attachments(&attachments) - .width(extent.width) - .height(extent.height) - .layers(1); - - let framebuffer = unsafe { - device.create_framebuffer(&framebuffer_info, None) - }?; - - framebuffers.push(framebuffer); - } - - Ok(framebuffers) -} - - -#[allow(unsafe_code)] -fn init_command_buffers(device: &Device, - framebuffers: &Vec<vk::Framebuffer>, - command_pool: &vk::CommandPool) - -> Result<Vec<vk::CommandBuffer>> -{ - let command_buffer_allocation_info - = vk::CommandBufferAllocateInfo::builder() - .command_pool(*command_pool) - .level(vk::CommandBufferLevel::PRIMARY) - .command_buffer_count(framebuffers.len() as u32); - let command_buffers = unsafe { - device.allocate_command_buffers(&command_buffer_allocation_info) - }?; - - Ok(command_buffers) -} - - -#[allow(unsafe_code)] -fn init_descriptor_sets(device: &Device, layout: &vk::DescriptorSetLayout, - buffers: &Vec<vk::Buffer>, pool: &vk::DescriptorPool, - count: usize, texture_image_view: &vk::ImageView, - sampler: &vk::Sampler) - -> Result<Vec<vk::DescriptorSet>> -{ - let layouts = vec![*layout; count]; - let set_info = vk::DescriptorSetAllocateInfo::builder() - .descriptor_pool(*pool) - .set_layouts(&layouts); - let sets = unsafe { device.allocate_descriptor_sets(&set_info) }?; - - for index in 0 .. count { - let buffer_info = vk::DescriptorBufferInfo::builder() - .buffer(buffers[index]) - .offset(0) - .range(size_of::<UniformBlock<f32>>() as vk::DeviceSize); - - let buffer_info_list = [buffer_info]; - let uniform_block_write_info = vk::WriteDescriptorSet::builder() - .dst_set(sets[index]) - .dst_binding(0) - .dst_array_element(0) - .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) - .buffer_info(&buffer_info_list); - - let sampler_image_info = vk::DescriptorImageInfo::builder() - .sampler(*sampler); - let sampler_image_info_list = [sampler_image_info]; - let sampler_write_info = vk::WriteDescriptorSet::builder() - .dst_set(sets[index]) - .dst_binding(1) - .dst_array_element(0) - .descriptor_type(vk::DescriptorType::SAMPLER) - .image_info(&sampler_image_info_list); - - let texture_image_info = vk::DescriptorImageInfo::builder() - .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) - .image_view(*texture_image_view); - let texture_image_info_list = [texture_image_info]; - let texture_write_info = vk::WriteDescriptorSet::builder() - .dst_set(sets[index]) - .dst_binding(2) - .dst_array_element(0) - .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) - .image_info(&texture_image_info_list); - - let write_info_list = [ - uniform_block_write_info, sampler_write_info, texture_write_info - ]; - let copy_info_list: [vk::CopyDescriptorSet; 0] = []; - - unsafe { - device.update_descriptor_sets(&write_info_list, ©_info_list) - }; - } - - Ok(sets) -} diff --git a/src/graphics/scene.rs b/src/graphics/scene.rs index 874e9ea..f73ebf2 100644 --- a/src/graphics/scene.rs +++ b/src/graphics/scene.rs @@ -12,9 +12,10 @@ pub fn generate_scene_commands<'a>(image_index: usize, time: f32, device: &Device, extent: &vk::Extent2D) -> Result<&'a vk::CommandBuffer> { - let command_buffer = &render.command_buffers[image_index]; - let framebuffer = &render.framebuffers[image_index]; - let descriptor_set = &render.descriptor_sets[image_index]; + let frame = &render.per_frame[image_index]; + let command_buffer = &frame.command_buffer; + let framebuffer = &frame.framebuffer; + let descriptor_set = &frame.descriptor_set; let inheritance_info = vk::CommandBufferInheritanceInfo::builder(); |