summary refs log tree commit diff
path: root/src/graphics_window_dressing.rs
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-08-06 16:43:02 -0700
committerIrene Knapp <ireneista@irenes.space>2026-08-06 16:43:02 -0700
commit2c8110d93e04a1bfd976fe20c8c7493a41d51eae (patch)
treeac7b4271e07e58bdc61e009a06f56164186c08aa /src/graphics_window_dressing.rs
parent5b5f7bb4b3cac1fa96b2325e7c3d0784ade28ebf (diff)
state needed when rendering is now in its own struct
subdividing the lifetimes of all our various objects may feel questionable in general, but this particular division is a very natural one

Force-Push: yes
Change-Id: I499a32875a4d75965944af720e7bfd6ec5965c15
Diffstat (limited to 'src/graphics_window_dressing.rs')
-rw-r--r--src/graphics_window_dressing.rs309
1 files changed, 186 insertions, 123 deletions
diff --git a/src/graphics_window_dressing.rs b/src/graphics_window_dressing.rs
index 51483cf..1b5b602 100644
--- a/src/graphics_window_dressing.rs
+++ b/src/graphics_window_dressing.rs
@@ -27,8 +27,9 @@ pub const N_SIMULTANEOUS_FRAMES: usize = 5;
 
 //   The WindowDressing collects the Vulkan graphics objects which need to be
 // regenerated or modified when the window changes in certain ways, such as
-// resizing. The ones which don't need that are collected above, in
-// PermanentGraphicsState.
+// resizing, but are not needed during rendering. The ones which don't need to
+// be regenerated are collected in PermanentGraphicsState. The ones which are
+// needed during rendering are collected in RenderState, below.
 #[derive(Debug)]
 pub struct WindowDressing {
   pub swapchain: Swapchain,
@@ -42,23 +43,9 @@ pub struct WindowDressing {
   depth_image_view: vk::ImageView,
   depth_format: vk::Format,
 
-  pub render_pass: vk::RenderPass,
-
-  pub pipeline: vk::Pipeline,
-  pub pipeline_layout: vk::PipelineLayout,
-
-  pub framebuffers: Vec<vk::Framebuffer>,
-
   primary_command_pool: vk::CommandPool,
   transient_command_pool: vk::CommandPool,
 
-  pub vertex_buffer: vk::Buffer,
-  vertex_buffer_memory: vk::DeviceMemory,
-
-  pub index_buffer: vk::Buffer,
-  index_buffer_memory: vk::DeviceMemory,
-  pub index_count: usize,
-
   texture_image: vk::Image,
   texture_image_memory: vk::DeviceMemory,
   texture_image_view: vk::ImageView,
@@ -69,13 +56,32 @@ pub struct WindowDressing {
   pub uniform_buffer_memory: Vec<vk::DeviceMemory>,
 
   descriptor_pool: vk::DescriptorPool,
-  pub descriptor_sets: Vec<vk::DescriptorSet>,
-
-  pub command_buffers: Vec<vk::CommandBuffer>,
 
   pub concurrency: Concurrency,
 }
 
+//   The RenderState collects the Vulkan graphics objects which need to be
+// regenerated or modified when the window changes, as with WindowDressing,
+// and which are also used as part of rendering.
+#[derive(Debug)]
+pub struct RenderState {
+  pub render_pass: vk::RenderPass,
+
+  pub pipeline: vk::Pipeline,
+  pub pipeline_layout: vk::PipelineLayout,
+
+  pub vertex_buffer: vk::Buffer,
+  vertex_buffer_memory: vk::DeviceMemory,
+
+  pub index_buffer: vk::Buffer,
+  index_buffer_memory: vk::DeviceMemory,
+  pub index_count: usize,
+
+  pub framebuffers: Vec<vk::Framebuffer>,
+  pub command_buffers: Vec<vk::CommandBuffer>,
+  pub descriptor_sets: Vec<vk::DescriptorSet>,
+}
+
 //   A swapchain is the generalized facility that is used to implement
 // double buffering, triple buffering, rendering passes that feed into each
 // other, and other things of that nature. It's a first-class thing but for
@@ -125,7 +131,6 @@ impl WindowDressing {
     let physical_device = &for_reinit.physical_device;
     let sample_count = for_reinit.sample_count;
     let indices = &for_reinit.indices;
-    let descriptor_set_layout = &for_reinit.descriptor_set_layout;
 
     let swapchain = init_swapchain(
             window, instance, surface, &physical_device, device, &indices)?;
@@ -138,30 +143,9 @@ impl WindowDressing {
             = init_depth(instance, &physical_device, device,
                          &swapchain.extent, sample_count)?;
 
-    let render_pass = init_render_pass(device, sample_count,
-                                       &swapchain.format, &depth_format)?;
-
-    let (pipeline_layout, pipeline)
-            = 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 (primary_command_pool, transient_command_pool)
             = init_command_pools(device, indices)?;
 
-    let (vertices, indices) = load_model()?;
-    let index_count = indices.len();
-
-    let (vertex_buffer, vertex_buffer_memory)
-            = init_vertex_buffer(vertices, instance, physical_device, device,
-                                 graphics_queue, &transient_command_pool)?;
-    let (index_buffer, index_buffer_memory)
-            = init_index_buffer(indices, instance, physical_device, device,
-                                graphics_queue, &transient_command_pool)?;
-
     let (texture_image, texture_image_memory, texture_image_view, mip_count)
             = init_texture(instance, physical_device, device,
                            graphics_queue, &transient_command_pool)?;
@@ -174,16 +158,6 @@ impl WindowDressing {
 
     let descriptor_pool
             = init_descriptor_pool(device, swapchain.images.len())?;
-    let descriptor_sets
-            = init_descriptor_sets(device, descriptor_set_layout,
-                                   &uniform_buffers, &descriptor_pool,
-                                   swapchain.images.len(),
-                                   &texture_image_view, &sampler)?;
-
-    let command_buffers = init_command_buffers(
-            device, &swapchain.extent, &framebuffers, &render_pass,
-            &pipeline_layout, &pipeline, &vertex_buffer, &index_buffer,
-            index_count, &descriptor_sets, &primary_command_pool)?;
 
     let concurrency = init_concurrency(device, &swapchain.images)?;
 
@@ -196,15 +170,6 @@ impl WindowDressing {
       depth_image_memory,
       depth_image_view,
       depth_format,
-      render_pass,
-      pipeline,
-      pipeline_layout,
-      framebuffers,
-      vertex_buffer,
-      vertex_buffer_memory,
-      index_buffer,
-      index_buffer_memory,
-      index_count,
       texture_image,
       texture_image_memory,
       texture_image_view,
@@ -213,10 +178,8 @@ impl WindowDressing {
       uniform_buffers,
       uniform_buffer_memory,
       descriptor_pool,
-      descriptor_sets,
       primary_command_pool,
       transient_command_pool,
-      command_buffers,
       concurrency,
     })
   }
@@ -251,17 +214,6 @@ impl WindowDressing {
             = init_depth(instance, &physical_device, device,
                          &swapchain.extent, sample_count)?;
 
-    let render_pass = init_render_pass(device, sample_count,
-                                       &swapchain.format, &depth_format)?;
-
-    let (pipeline_layout, pipeline)
-            = 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 (uniform_buffers, uniform_buffer_memory)
             = init_uniform_buffers(instance, physical_device, device,
                                    swapchain.images.len())?;
@@ -270,19 +222,6 @@ impl WindowDressing {
     let descriptor_pool
             = init_descriptor_pool(device, swapchain.images.len())?;
 
-    let descriptor_sets
-            = init_descriptor_sets(device, descriptor_set_layout,
-                                   &uniform_buffers, &descriptor_pool,
-                                   swapchain.images.len(),
-                                   &self.texture_image_view, &self.sampler)?;
-
-    // Notice that we reused the command pool.
-    let command_buffers = init_command_buffers(
-            device, &swapchain.extent, &framebuffers, &render_pass,
-            &pipeline_layout, &pipeline, &self.vertex_buffer,
-            &self.index_buffer, self.index_count, &descriptor_sets,
-            &self.primary_command_pool)?;
-
     self.concurrency.image_fences.resize(swapchain.images.len(),
                                          vk::Fence::null());
 
@@ -294,15 +233,9 @@ impl WindowDressing {
     self.depth_image_memory = depth_image_memory;
     self.depth_image_view = depth_image_view;
     self.depth_format = depth_format;
-    self.render_pass = render_pass;
-    self.pipeline = pipeline;
-    self.pipeline_layout = pipeline_layout;
-    self.framebuffers = framebuffers;
     self.uniform_buffers = uniform_buffers;
     self.uniform_buffer_memory = uniform_buffer_memory;
     self.descriptor_pool = descriptor_pool;
-    self.descriptor_sets = descriptor_sets;
-    self.command_buffers = command_buffers;
 
     Ok(())
   }
@@ -314,12 +247,6 @@ impl WindowDressing {
   pub fn destroy(mut self, device: &Device) {
     self.destroy_replaceable(device);
 
-    unsafe { device.destroy_buffer(self.vertex_buffer, None) };
-    unsafe { device.free_memory(self.vertex_buffer_memory, None) };
-
-    unsafe { device.destroy_buffer(self.index_buffer, None) };
-    unsafe { device.free_memory(self.index_buffer_memory, None) };
-
     unsafe { device.destroy_image(self.texture_image, None) };
     unsafe { device.free_memory(self.texture_image_memory, None) };
     unsafe { device.destroy_image_view(self.texture_image_view, None) };
@@ -346,20 +273,6 @@ impl WindowDressing {
 
   #[allow(unsafe_code)]
   fn destroy_replaceable(&mut self, device: &Device) {
-    for framebuffer in &self.framebuffers {
-      unsafe { device.destroy_framebuffer(*framebuffer, None) };
-    }
-
-    //   Notice that we free the buffers in the pool, but do not destroy the
-    // pool itself. Notice also that we only do this for the primary command
-    // pool, because that's the only one where we've kept track of the
-    // buffers. We promise ourselves to free buffers in the transient pool
-    // immediately after using them.
-    unsafe {
-      device.free_command_buffers(self.primary_command_pool,
-                                  &self.command_buffers)
-    };
-
     //   While the descriptor pool is also a pool, it has a preallocated size
     // which will be different next time. So, we destroy it all the way.
     unsafe { device.destroy_descriptor_pool(self.descriptor_pool, None) };
@@ -374,9 +287,6 @@ impl WindowDressing {
       unsafe { device.free_memory(*memory, None) };
     }
 
-    unsafe { device.destroy_pipeline(self.pipeline, None) };
-    unsafe { device.destroy_pipeline_layout(self.pipeline_layout, None) };
-    unsafe { device.destroy_render_pass(self.render_pass, 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) };
@@ -393,6 +303,167 @@ impl WindowDressing {
 }
 
 
+impl RenderState {
+  pub fn new(permanent: &PermanentGraphicsState,
+             for_reinit: &GraphicsStateForReinit,
+             window_dressing: &WindowDressing)
+      -> Result<Self>
+  {
+    let device = &permanent.device;
+    let instance = &permanent.instance;
+    let graphics_queue = &permanent.graphics_queue;
+    let physical_device = &for_reinit.physical_device;
+    let sample_count = for_reinit.sample_count;
+    let descriptor_set_layout = &for_reinit.descriptor_set_layout;
+    let primary_command_pool = &window_dressing.primary_command_pool;
+    let transient_command_pool = &window_dressing.transient_command_pool;
+    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 texture_image_view = &window_dressing.texture_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)?;
+
+    let (pipeline_layout, pipeline)
+            = 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 (vertices, indices) = load_model()?;
+    let index_count = indices.len();
+
+    let command_buffers = init_command_buffers(device, &framebuffers,
+                                               primary_command_pool)?;
+
+    let (vertex_buffer, vertex_buffer_memory)
+            = init_vertex_buffer(vertices, instance, physical_device, device,
+                                 graphics_queue, &transient_command_pool)?;
+    let (index_buffer, index_buffer_memory)
+            = init_index_buffer(indices, instance, physical_device, device,
+                                graphics_queue, &transient_command_pool)?;
+
+    let descriptor_sets
+            = init_descriptor_sets(device, descriptor_set_layout,
+                                   &uniform_buffers, &descriptor_pool,
+                                   swapchain.images.len(),
+                                   &texture_image_view, &sampler)?;
+
+    Ok(RenderState {
+      render_pass,
+      pipeline,
+      pipeline_layout,
+      vertex_buffer,
+      vertex_buffer_memory,
+      index_buffer,
+      index_buffer_memory,
+      index_count,
+      framebuffers,
+      command_buffers,
+      descriptor_sets,
+    })
+  }
+
+  //   This relies on its caller to have already waited for the device to be
+  // idle.
+  pub fn reinit(&mut self, permanent: &PermanentGraphicsState,
+                for_reinit: &GraphicsStateForReinit,
+                window_dressing: &WindowDressing)
+      -> Result<()>
+  {
+    let device = &permanent.device;
+    let sample_count = for_reinit.sample_count;
+    let descriptor_set_layout = &for_reinit.descriptor_set_layout;
+    let primary_command_pool = &window_dressing.primary_command_pool;
+    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 texture_image_view = &window_dressing.texture_image_view;
+    let uniform_buffers = &window_dressing.uniform_buffers;
+    let descriptor_pool = &window_dressing.descriptor_pool;
+    let sampler = &window_dressing.sampler;
+
+    self.destroy_replaceable(device, primary_command_pool);
+
+    let render_pass = init_render_pass(device, sample_count,
+                                       &swapchain.format, &depth_format)?;
+
+    let (pipeline_layout, pipeline)
+            = 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)?;
+
+    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(())
+  }
+
+  //   This relies on its caller to have already waited for the device to be
+  // idle.
+  #[allow(unsafe_code)]
+  pub fn destroy(mut self, device: &Device,
+                 window_dressing: &WindowDressing)
+  {
+    self.destroy_replaceable(device, &window_dressing.primary_command_pool);
+
+    unsafe { device.destroy_buffer(self.vertex_buffer, None) };
+    unsafe { device.free_memory(self.vertex_buffer_memory, None) };
+
+    unsafe { device.destroy_buffer(self.index_buffer, None) };
+    unsafe { device.free_memory(self.index_buffer_memory, None) };
+  }
+
+  #[allow(unsafe_code)]
+  fn destroy_replaceable(&mut self, device: &Device,
+                         primary_command_pool: &vk::CommandPool)
+  {
+    for framebuffer in &self.framebuffers {
+      unsafe { device.destroy_framebuffer(*framebuffer, None) };
+    }
+
+    //   Notice that we free the buffers in the pool, but do not destroy the
+    // pool itself. Notice also that we only do this for the primary command
+    // pool, because that's the only one where we've kept track of the
+    // buffers. We promise ourselves to free buffers in the transient pool
+    // immediately after using them.
+    unsafe {
+      device.free_command_buffers(*primary_command_pool,
+                                  &self.command_buffers)
+    };
+
+    unsafe { device.destroy_pipeline(self.pipeline, None) };
+    unsafe { device.destroy_pipeline_layout(self.pipeline_layout, None) };
+    unsafe { device.destroy_render_pass(self.render_pass, None) };
+  }
+}
+
+
 #[allow(unsafe_code)]
 fn init_swapchain(window: &Window, instance: &Instance,
                   surface: &vk::SurfaceKHR,
@@ -1041,15 +1112,7 @@ fn init_command_pools(device: &Device, indices: &QueueFamilyIndices)
 
 #[allow(unsafe_code)]
 fn init_command_buffers(device: &Device,
-                        extent: &vk::Extent2D,
                         framebuffers: &Vec<vk::Framebuffer>,
-                        render_pass: &vk::RenderPass,
-                        pipeline_layout: &vk::PipelineLayout,
-                        pipeline: &vk::Pipeline,
-                        vertex_buffer: &vk::Buffer,
-                        index_buffer: &vk::Buffer,
-                        index_count: usize,
-                        descriptor_sets: &Vec<vk::DescriptorSet>,
                         command_pool: &vk::CommandPool)
     -> Result<Vec<vk::CommandBuffer>>
 {