summary refs log tree commit diff
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-08-15 20:26:28 -0700
committerIrene Knapp <ireneista@irenes.space>2026-08-16 02:08:18 -0700
commitdb64249ce8108439ada78a2d23d67d2c573a1688 (patch)
tree3029aeaab6f3e30ff199ae367f75a5851e8f0222
parent2fae64a18c3253a892c9b3e529fb7b09e0bac753 (diff)
move uniform buffers into Frame
it's better this way. same lifetime.

Force-Push: yes
Change-Id: Ida309f05132838febcc9eb606f5915e7592ac398
-rw-r--r--src/graphics/frame.rs219
-rw-r--r--src/graphics/window_dressing.rs50
-rw-r--r--src/main.rs2
3 files changed, 121 insertions, 150 deletions
diff --git a/src/graphics/frame.rs b/src/graphics/frame.rs
index 749b5ac..d8d4bcd 100644
--- a/src/graphics/frame.rs
+++ b/src/graphics/frame.rs
@@ -1,11 +1,12 @@
 #![deny(unsafe_code)]
 use crate::error::*;
 use crate::graphics::{ Permanent, ForReinit, WindowDressing, Texture };
+use crate::graphics::util::allocate_buffer;
 use crate::shader_data::UniformBlock;
 
 use std::mem::size_of;
 
-use vulkanalia::Device;
+use vulkanalia::{ Device, Instance };
 use vulkanalia::vk::{ self, HasBuilder, DeviceV1_0 };
 
 
@@ -18,6 +19,14 @@ use vulkanalia::vk::{ self, HasBuilder, DeviceV1_0 };
 pub struct Frame {
   pub framebuffer: vk::Framebuffer,
   pub command_buffer: vk::CommandBuffer,
+
+  //   Uniform buffers are unlike the other things in Frame in that they are
+  // not used at render-time. It's still cleanest to have them here, since
+  // they exist per-frame. Otherwise we get action-at-a-distance passing
+  // around indices, which is harder to trace through.
+  pub uniform_buffer: vk::Buffer,
+  pub uniform_buffer_memory: vk::DeviceMemory,
+
   pub descriptor_set: vk::DescriptorSet,
 }
 
@@ -28,50 +37,22 @@ impl Frame {
   // 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.
+  #[allow(unsafe_code)]
   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,
-      });
-    }
+    Frame::reinit(&mut frames, permanent, for_reinit, window_dressing,
+                  texture, render_pass)?;
 
     Ok(frames)
   }
 
   // See new() in regard to the Vec.
+  #[allow(unsafe_code)]
   pub fn reinit(frames: &mut Vec<Self>, permanent: &Permanent,
                 for_reinit: &ForReinit, window_dressing: &WindowDressing,
                 texture: &Texture, render_pass: &vk::RenderPass)
@@ -79,13 +60,13 @@ impl Frame {
   {
     Frame::destroy_replaceable(frames, permanent);
 
+    let instance = &permanent.instance;
     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;
 
@@ -94,25 +75,31 @@ impl Frame {
     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 command_buffers = allocate_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 descriptor_sets = allocate_descriptor_sets(
+            count, device, descriptor_set_layout, descriptor_pool)?;
 
     for (index, color_resolve_image_view)
         in swapchain.image_views.iter().enumerate()
     {
+      let command_buffer = command_buffers[index];
+      let mut descriptor_set = descriptor_sets[index];
+
       let framebuffer = init_framebuffer(
               device, &swapchain.extent, &color_image_view, &depth_image_view,
               color_resolve_image_view, &render_pass)?;
 
+      let (uniform_buffer, uniform_buffer_memory)
+              = init_uniform_buffer(instance, device)?;
+
+      configure_descriptor_set(&mut descriptor_set, device, &uniform_buffer,
+                               &texture.image_view, sampler)?;
+
       frames.push(Frame {
-        command_buffer: command_buffers[index],
-        descriptor_set: descriptor_sets[index],
-        framebuffer,
+        framebuffer, command_buffer, uniform_buffer, uniform_buffer_memory,
+        descriptor_set,
       });
     }
 
@@ -128,6 +115,10 @@ impl Frame {
 
   #[allow(unsafe_code)]
   pub fn destroy_replaceable(frames: &mut Vec<Self>, permanent: &Permanent) {
+    if frames.is_empty() {
+      return;
+    }
+
     let device = &permanent.device;
 
     let mut command_buffers = Vec::new();
@@ -135,6 +126,9 @@ impl Frame {
       unsafe { device.destroy_framebuffer(frame.framebuffer, None) };
 
       command_buffers.push(frame.command_buffer);
+
+      unsafe { device.destroy_buffer(frame.uniform_buffer, None) };
+      unsafe { device.free_memory(frame.uniform_buffer_memory, None) };
     }
 
     //   Notice that we free the buffers in the pool, but do not destroy the
@@ -178,8 +172,8 @@ fn init_framebuffer(device: &Device, extent: &vk::Extent2D,
 
 
 #[allow(unsafe_code)]
-fn init_command_buffers(count: usize, device: &Device,
-                        command_pool: &vk::CommandPool)
+fn allocate_command_buffers(count: usize, device: &Device,
+                            command_pool: &vk::CommandPool)
     -> Result<Vec<vk::CommandBuffer>>
 {
   let command_buffer_allocation_info
@@ -196,64 +190,89 @@ fn init_command_buffers(count: usize, device: &Device,
 
 
 #[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)
+fn allocate_descriptor_sets(count: usize, device: &Device,
+                            descriptor_set_layout: &vk::DescriptorSetLayout,
+                            descriptor_pool: &vk::DescriptorPool)
     -> 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] = [];
+  let layouts = vec![*descriptor_set_layout; count];
+  let descriptor_set_info = vk::DescriptorSetAllocateInfo::builder()
+          .descriptor_pool(*descriptor_pool)
+          .set_layouts(&layouts[..]);
+  let descriptor_sets = unsafe {
+    device.allocate_descriptor_sets(&descriptor_set_info)
+  }?;
 
-    unsafe {
-      device.update_descriptor_sets(&write_info_list, &copy_info_list)
-    };
-  }
+  Ok(descriptor_sets)
+}
 
-  Ok(sets)
+
+#[allow(unsafe_code)]
+fn configure_descriptor_set(descriptor_set: &mut vk::DescriptorSet,
+                            device: &Device,
+                            uniform_buffer: &vk::Buffer,
+                            texture_image_view: &vk::ImageView,
+                            sampler: &vk::Sampler)
+    -> Result<()>
+{
+  let buffer_info = vk::DescriptorBufferInfo::builder()
+          .buffer(*uniform_buffer)
+          .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(*descriptor_set)
+          .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(*descriptor_set)
+          .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(*descriptor_set)
+          .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(())
 }
 
+
+fn init_uniform_buffer(instance: &Instance, device: &Device)
+    -> Result<(vk::Buffer, vk::DeviceMemory)>
+{
+  let (buffer, memory) = allocate_buffer(
+          instance, device,
+          size_of::<UniformBlock<f32>>() as vk::DeviceSize,
+          vk::BufferUsageFlags::UNIFORM_BUFFER,
+          vk::MemoryPropertyFlags::HOST_COHERENT
+          | vk::MemoryPropertyFlags::HOST_VISIBLE)?;
+
+  Ok((buffer, memory))
+}
+
+
diff --git a/src/graphics/window_dressing.rs b/src/graphics/window_dressing.rs
index 07dfaf0..d6afa20 100644
--- a/src/graphics/window_dressing.rs
+++ b/src/graphics/window_dressing.rs
@@ -2,13 +2,9 @@
 use crate::error::*;
 use crate::graphics::{ Permanent, ForReinit };
 use crate::graphics::permanent::{ QueueFamilyIndices, EnableAnisotropy };
-use crate::graphics::util::{
-  allocate_buffer, allocate_image, init_image_view
-};
-use crate::shader_data::UniformBlock;
+use crate::graphics::util::{ allocate_image, init_image_view };
 
 use std::collections::BTreeSet;
-use std::mem::size_of;
 
 use vulkanalia::{ Device, Instance };
 use vulkanalia::vk::{ self, Handle, HasBuilder, InstanceV1_0, DeviceV1_0,
@@ -42,9 +38,6 @@ pub struct WindowDressing {
 
   pub sampler: vk::Sampler,
 
-  pub uniform_buffers: Vec<vk::Buffer>,
-  pub uniform_buffer_memory: Vec<vk::DeviceMemory>,
-
   pub descriptor_pool: vk::DescriptorPool,
 
   pub concurrency: Concurrency,
@@ -110,9 +103,6 @@ impl WindowDressing {
 
     let sampler = init_sampler(&device, &enable_anisotropy, mip_count)?;
 
-    let (uniform_buffers, uniform_buffer_memory)
-            = init_uniform_buffers(instance, device, swapchain.images.len())?;
-
     let descriptor_pool
             = init_descriptor_pool(device, swapchain.images.len())?;
 
@@ -128,8 +118,6 @@ impl WindowDressing {
       depth_image_view,
       depth_format,
       sampler,
-      uniform_buffers,
-      uniform_buffer_memory,
       descriptor_pool,
       concurrency,
     })
@@ -161,9 +149,6 @@ impl WindowDressing {
     let (depth_image, depth_image_memory, depth_image_view, depth_format)
             = init_depth(instance, device, &swapchain.extent, sample_count)?;
 
-    let (uniform_buffers, uniform_buffer_memory)
-            = init_uniform_buffers(instance, device, swapchain.images.len())?;
-
     // Notice that we did NOT reuse the descriptor pool.
     let descriptor_pool
             = init_descriptor_pool(device, swapchain.images.len())?;
@@ -179,8 +164,6 @@ impl WindowDressing {
     self.depth_image_memory = depth_image_memory;
     self.depth_image_view = depth_image_view;
     self.depth_format = depth_format;
-    self.uniform_buffers = uniform_buffers;
-    self.uniform_buffer_memory = uniform_buffer_memory;
     self.descriptor_pool = descriptor_pool;
 
     Ok(())
@@ -215,16 +198,6 @@ impl WindowDressing {
     // which will be different next time. So, we destroy it all the way.
     unsafe { device.destroy_descriptor_pool(self.descriptor_pool, None) };
 
-    //   Notice that, unlike the vertex and index buffers, we destroy and
-    // re-create these on every reinitialization. That's because the number of
-    // them depends on how many images the swapchain has.
-    for buffer in &self.uniform_buffers {
-      unsafe { device.destroy_buffer(*buffer, None) };
-    }
-    for memory in &self.uniform_buffer_memory {
-      unsafe { device.free_memory(*memory, None) };
-    }
-
     unsafe { device.destroy_image(self.color_image, None) };
     unsafe { device.free_memory(self.color_image_memory, None) };
     unsafe { device.destroy_image_view(self.color_image_view, None) };
@@ -365,27 +338,6 @@ fn init_depth(instance: &Instance, device: &Device, extent: &vk::Extent2D,
 }
 
 
-fn init_uniform_buffers(instance: &Instance, device: &Device, count: usize)
-    -> Result<(Vec<vk::Buffer>, Vec<vk::DeviceMemory>)>
-{
-  let mut buffers = Vec::new();
-  let mut all_memory = Vec::new();
-
-  for _ in 0 .. count {
-    let (buffer, memory) = allocate_buffer(
-            instance, device,
-            size_of::<UniformBlock<f32>>() as vk::DeviceSize,
-            vk::BufferUsageFlags::UNIFORM_BUFFER,
-            vk::MemoryPropertyFlags::HOST_COHERENT
-            | vk::MemoryPropertyFlags::HOST_VISIBLE)?;
-    buffers.push(buffer);
-    all_memory.push(memory);
-  }
-
-  Ok((buffers, all_memory))
-}
-
-
 #[allow(unsafe_code)]
 fn init_sampler(device: &Device, enable_anisotropy: &EnableAnisotropy,
                 mip_count: u32)
diff --git a/src/main.rs b/src/main.rs
index b5af438..d461a63 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -167,7 +167,7 @@ impl Surreality {
               &window_dressing.swapchain.extent)?;
 
       render_uniforms(device,
-                      &window_dressing.uniform_buffer_memory[image_index],
+                      &render.per_frame[image_index].uniform_buffer_memory,
                       &window_dressing.swapchain.extent)?;
 
       let first_semaphores = [*image_available_semaphore];