summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-07-09 12:22:37 -0700
committerIrene Knapp <ireneista@irenes.space>2026-07-09 12:22:37 -0700
commit2f24a8f0916f71df2b48e59cea2b4643b88b11fb (patch)
tree8823834b0b1afc3abada141095a7093d800df950 /src
parent07822896b727b8327045dcb43b2e28cb1b368fea (diff)
new Permanent struct
almost everything in Surreality that isn't in WindowDressing is now in Permanent

Force-Push: yes
Change-Id: I994427668030ed2ebf5f159fa4d5d665ca07b372
Diffstat (limited to 'src')
-rw-r--r--src/main.rs114
1 files changed, 56 insertions, 58 deletions
diff --git a/src/main.rs b/src/main.rs
index 15f38e8..53c8c09 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -70,39 +70,53 @@ struct QueueFamilyIndices {
 
 
 struct Surreality {
+  permanent: RefCell<Option<PermanentGraphicsState>>,
+  window_dressing: RefCell<Option<WindowDressing>>,
+  frame_index: usize,
+}
+
+//   The PermanentGraphicsState collects the various windowing-system and
+// Vulkan objects which never need to be regenerated once they're created. The
+// ones which do need that are collected below, in WindowDressing.
+struct PermanentGraphicsState {
   //   The "window" is the usual operating-system concept of a window; it's
   // provided by winit, and may be X11, Wayland, or some more curious thing.
   // The way we initialize Vulkan requires us to have at least one of these;
   // we could have more, but for now, we don't.
-  window: RefCell<Option<Window>>,
+  window: Window,
 
   //   The Vulkan "entry" is the part of the Vulkan library ecosystem that's
   // responsible for finding and loading the other parts. Once we have the
   // instance, the entry is never directly used again, but we retain it
   // because doing otherwise would segfault.
-  entry: RefCell<Option<Entry>>,
+  #[allow(unused)]
+  entry: Entry,
 
   //   The Vulkan "instance" is the bulk of the Vulkan library, with most of
   // the high-level responsibilities around lifecycle management.
-  instance: RefCell<Option<Instance>>,
+  instance: Instance,
 
   //   The debug messager is a Vulkan object representing our callback which
   // Vulkan uses to tell us things.
   //
   //   Vulkan spells "messager" as "messenger", but this is absurd
   // over-formality and we don't indulge it.
-  debug_messager: RefCell<Option<vk::DebugUtilsMessengerEXT>>,
+  //
+  //    Once we've created this, we never actually need to do anything with
+  // it, but we do need to retain it, so here it is.
+  debug_messager: Option<vk::DebugUtilsMessengerEXT>,
 
   //   The Vulkan "surface" is the destination that rendering happens into.
-  // It is connected to the window but distinct from it.
-  surface: RefCell<Option<vk::SurfaceKHR>>,
+  // It is connected to the window but distinct from it. Since we always have
+  // exactly one window, this is permanent state.
+  surface: vk::SurfaceKHR,
 
   //   The Vulkan "device" is the abstraction for a GPU. A physical one is the
   // actual GPU, and a logical one is our connection to it. We pick a physical
   // device during initialization, but only the logical one is used later, so
   // it's all we track. We'll be referencing the logical device a lot, so we
   // follow Vulkan's lead and let it have a short variable name.
-  device: RefCell<Option<Device>>,
+  device: Device,
 
   //   Vulkan has a first-class concept of command queues. We have two of
   // them, one for graphics drawing commands and one for presentation.
@@ -114,18 +128,15 @@ struct Surreality {
   // find a family that does both.
   //
   //   Yes, this means the compiler has to deal with pointer aliasing
-  // concerns, which have a tendency to defeat optimizations.
-  graphics_queue: RefCell<Option<vk::Queue>>,
-  presentation_queue: RefCell<Option<vk::Queue>>,
-
-  window_dressing: RefCell<Option<WindowDressing>>,
-
-  frame_index: usize,
+  // concerns, which have a tendency to defeat optimizations. Alas.
+  graphics_queue: vk::Queue,
+  presentation_queue: vk::Queue,
 }
 
-//   Of the various Vulkan graphics objects, the WindowDressing consists of
-// the ones which need to be regenerated or modified when the window changes
-// in certain ways, such as resizing.
+//   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.
 #[derive(Debug)]
 struct WindowDressing {
   swapchain: Swapchain,
@@ -187,14 +198,7 @@ struct EnableSwapchain(bool);
 impl Surreality {
   fn new() -> Self {
     Surreality {
-      window: RefCell::new(None),
-      entry: RefCell::new(None),
-      instance: RefCell::new(None),
-      debug_messager: RefCell::new(None),
-      surface: RefCell::new(None),
-      device: RefCell::new(None),
-      graphics_queue: RefCell::new(None),
-      presentation_queue: RefCell::new(None),
+      permanent: RefCell::new(None),
       window_dressing: RefCell::new(None),
       frame_index: 0,
     }
@@ -267,14 +271,16 @@ impl Surreality {
       });
     }
 
-    *self.window.get_mut() = Some(window);
-    *self.entry.get_mut() = Some(entry);
-    *self.instance.get_mut() = Some(instance);
-    *self.debug_messager.get_mut() = debug_messager;
-    *self.surface.get_mut() = Some(surface);
-    *self.device.get_mut() = Some(device);
-    *self.graphics_queue.get_mut() = Some(graphics_queue);
-    *self.presentation_queue.get_mut() = Some(presentation_queue);
+    *self.permanent.get_mut() = Some(PermanentGraphicsState {
+      window,
+      entry,
+      instance,
+      debug_messager,
+      surface,
+      device,
+      graphics_queue,
+      presentation_queue,
+    });
 
     Ok(())
   }
@@ -1274,19 +1280,12 @@ impl Surreality {
 
   #[allow(unsafe_code)]
   fn render(&mut self, window_id: WindowId) -> Result<()> {
-    if let Some(window) = self.window.borrow().as_ref()
-       && window_id == window.id()
+    if let Some(permanent) = self.permanent.borrow().as_ref()
+       && let Some(window_dressing)
+              = self.window_dressing.borrow_mut().as_mut()
+       && window_id == permanent.window.id()
     {
-      let device = self.device.borrow();
-      let device = device.as_ref().unwrap();
-      let graphics_queue = self.graphics_queue.borrow();
-      let graphics_queue = graphics_queue.as_ref().unwrap();
-      let presentation_queue = self.presentation_queue.borrow();
-      let presentation_queue = presentation_queue.as_ref().unwrap();
-      let mut window_dressing = self.window_dressing.borrow_mut();
-      let window_dressing = window_dressing.as_mut().unwrap();
-      let swapchain = &window_dressing.swapchain.swapchain;
-      let command_buffers = &window_dressing.command_buffers;
+      let device = &permanent.device;
       let frame_index = self.frame_index;
       let concurrency = &mut window_dressing.concurrency;
       let image_available_semaphore
@@ -1298,8 +1297,8 @@ impl Surreality {
       unsafe { device.wait_for_fences(&[*frame_fence], true, u64::MAX) }?;
 
       let image_index = unsafe {
-        device.acquire_next_image_khr(*swapchain, u64::MAX,
-                                      *image_available_semaphore,
+        device.acquire_next_image_khr(window_dressing.swapchain.swapchain,
+                                      u64::MAX, *image_available_semaphore,
                                       vk::Fence::null())
       }?.0 as usize;
 
@@ -1314,7 +1313,7 @@ impl Surreality {
       let second_semaphores = [*rendering_finished_semaphore];
 
       let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT];
-      let command_buffers = [command_buffers[image_index]];
+      let command_buffers = [window_dressing.command_buffers[image_index]];
       let submit_info = vk::SubmitInfo::builder()
                             .wait_semaphores(&first_semaphores)
                             .wait_dst_stage_mask(&wait_stages)
@@ -1322,12 +1321,12 @@ impl Surreality {
                             .signal_semaphores(&second_semaphores);
       unsafe { device.reset_fences(&[*frame_fence]) }?;
       unsafe {
-        device.queue_submit(*graphics_queue,
+        device.queue_submit(permanent.graphics_queue,
                             &[submit_info],
                             *frame_fence)
       }?;
 
-      let swapchains = [*swapchain];
+      let swapchains = [window_dressing.swapchain.swapchain];
       let image_indices = [image_index as u32];
       let present_info = vk::PresentInfoKHR::builder()
                              .wait_semaphores(&second_semaphores)
@@ -1335,7 +1334,7 @@ impl Surreality {
                              .image_indices(&image_indices);
 
       unsafe {
-        device.queue_present_khr(*presentation_queue, &present_info)
+        device.queue_present_khr(permanent.presentation_queue, &present_info)
       }?;
 
       self.frame_index = (frame_index + 1) % N_SIMULTANEOUS_FRAMES;
@@ -1348,7 +1347,10 @@ impl Surreality {
 impl Drop for Surreality {
   #[allow(unsafe_code)]
   fn drop(&mut self) {
-    if let Some(device) = self.device.replace(None) {
+    if let Some(permanent) = self.permanent.replace(None) {
+      let device = permanent.device;
+      let instance = permanent.instance;
+
       unsafe { device.device_wait_idle() }.unwrap();
 
       if let Some(window_dressing) = self.window_dressing.replace(None) {
@@ -1396,19 +1398,15 @@ impl Drop for Surreality {
       }
 
       unsafe { device.destroy_device(None) };
-    }
 
-    if let Some(instance) = self.instance.replace(None) {
-      if let Some(surface) = self.surface.replace(None) {
-        unsafe { instance.destroy_surface_khr(surface, None) };
-      }
+      unsafe { instance.destroy_surface_khr(permanent.surface, None) };
 
       //   Everything but the instance itself should already be destroyed,
       // before we destroy the debug messager. The special hook to get debug
       // messages while destroying the instance itself only applies to the
       // instance and the messager, so if we were to destroy anything we
       // shouldn't after this point, we'd miss out on diagnostics.
-      if let Some(debug_messager) = self.debug_messager.replace(None) {
+      if let Some(debug_messager) = permanent.debug_messager {
         unsafe {
           instance.destroy_debug_utils_messenger_ext(debug_messager, None);
         }