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/frame.rs | |
| 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/frame.rs')
| -rw-r--r-- | src/graphics/frame.rs | 227 |
1 files changed, 227 insertions, 0 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) +} |