summary refs log tree commit diff
path: root/src/graphics/frame.rs
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-08-14 02:35:23 -0700
committerIrene Knapp <ireneista@irenes.space>2026-08-14 02:35:23 -0700
commit5a4fad7b67a6ab477b230f4d8a70efed0e9100cb (patch)
tree95f10f8106a225e0fcd4a1fbd0d0bca2ced51b38 /src/graphics/frame.rs
parent19e3a0f319fd04c1dde803796ec272d038b634f7 (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.rs227
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, &copy_info_list)
+    };
+  }
+
+  Ok(sets)
+}