summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-07-09 13:54:04 -0700
committerIrene Knapp <ireneista@irenes.space>2026-07-09 13:54:04 -0700
commitce60c460eb5d9cf43f2b980635b651f310b6cc90 (patch)
tree938730fe396867983ebea917a97820c2bde46230 /src/main.rs
parent4b5ceb8d7fef310349de138b9b811e6abfa9efe3 (diff)
move all the window dressing init logic into impl WindowDressing
Force-Push: yes
Change-Id: Icd63ed890ae0c726b71bb85e02072faff32cb87e
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs773
1 files changed, 383 insertions, 390 deletions
diff --git a/src/main.rs b/src/main.rs
index f8f44a6..5411bc9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -238,19 +238,13 @@ impl Surreality {
                                    enable_validation, enable_portability)?;
 
     let permanent = PermanentGraphicsState {
-      window,
-      entry,
-      instance,
-      debug_messager,
-      surface,
-      device,
-      graphics_queue,
-      presentation_queue,
+      window, entry, instance, debug_messager, surface, device,
+      graphics_queue, presentation_queue,
     };
 
     if enable_swapchain.0 {
-      *self.window_dressing.get_mut() = Some(Self::init_window_dressing(
-          &permanent, physical_device, indices)?);
+      *self.window_dressing.get_mut()
+          = Some(WindowDressing::new(&permanent, physical_device, indices)?);
     }
 
     *self.permanent.get_mut() = Some(permanent);
@@ -555,10 +549,348 @@ impl Surreality {
         enable_swapchain))
   }
 
-  fn init_window_dressing(permanent: &PermanentGraphicsState,
-                          physical_device: vk::PhysicalDevice,
-                          indices: QueueFamilyIndices)
-      -> Result<WindowDressing>
+  //   To Vulkan, a "physical" device is the actual GPU, and a "logical"
+  // device is per-process state that represents a connection to the GPU.
+  // Before we can create a logical device, we must choose which physical
+  // device to connect it to.
+  #[allow(unsafe_code)]
+  fn pick_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR)
+      -> Result<(vk::PhysicalDevice, QueueFamilyIndices)>
+  {
+    let mut best_device = None;
+    let mut best_score = None;
+    let mut best_indices = None;
+    let mut rejected = BTreeMap::new();
+
+    for device in unsafe { instance.enumerate_physical_devices() }? {
+      match Self::score_vulkan_device(instance, surface, &device)? {
+        Acceptable::Accepted((new_score, new_indices)) => {
+          if let Some(old_score) = best_score {
+            if new_score > old_score {
+              best_device = Some(device);
+              best_score = Some(new_score);
+              best_indices = Some(new_indices);
+            }
+          } else {
+            best_device = Some(device);
+            best_score = Some(new_score);
+            best_indices = Some(new_indices);
+          }
+        }
+        Acceptable::Rejected(reason) => {
+          let properties = unsafe {
+            instance.get_physical_device_properties(device)
+          };
+
+          let name = properties.device_name.to_string_lossy().into_owned();
+
+          rejected.insert(properties.device_id, (name, reason));
+        }
+      }
+    }
+
+    if let (Some(device), Some(indices)) = (best_device, best_indices) {
+      Ok((device, indices))
+    } else if rejected.is_empty() {
+      Err(Error {
+        message: "The system has no GPUs of any kind.".to_string()
+      })
+    } else {
+      for (_, (name, reason)) in rejected {
+        eprintln!("Can't run on {} because: {}", name, reason);
+      }
+
+      Err(Error {
+        message: "The system has GPUs, but none are acceptable (see above)."
+                 .to_string()
+      })
+    }
+  }
+
+  //   We're doing two tasks: Quantifying how strongly we prefer a device, and
+  // deciding whether it's acceptable at all. If it's unacceptable, it's
+  // possible there will be no acceptable devices, and in that case our caller
+  // will want to print explanations, but otherwise it'll want to be quiet. So
+  // the outer Result is whether we successfully evaluated the device, and the
+  // inner Acceptable is whether we approve of it.
+  //
+  //   In the event that we find the device acceptable, we also return the
+  // queue family indices we'd be using if we ultimately go with it. While
+  // this is not strictly necessary, it's better to return them from here
+  // than to recompute them later on the assumption it'll work out the same.
+  #[allow(unsafe_code)]
+  fn score_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR,
+                         physical_device: &vk::PhysicalDevice)
+      -> Result<Acceptable<(u64, QueueFamilyIndices)>>
+  {
+    //   Not all devices support graphics, and not all devices support
+    // presenting to any given surface. We check whether this one is suitable
+    // by looking up the indices of the queue families we would use. If we
+    // ultimately use this device, we'll need these, so we make sure to return
+    // them.
+    let indices = match Self::find_device_queue_family_indices(
+                            instance, surface, physical_device)?
+    {
+      Acceptable::Rejected(rationale) => {
+        return Ok(Acceptable::Rejected(rationale));
+      }
+      Acceptable::Accepted(indices) => indices
+    };
+
+    //   At this point we know the device meets our high-level requirements,
+    // so it's just a question of scoring.
+    let properties = unsafe {
+      instance.get_physical_device_properties(*physical_device)
+    };
+
+    let mut score = 0;
+    if properties.device_type == vk::PhysicalDeviceType::DISCRETE_GPU {
+      // If the user has a fancy GPU, they prefer it.
+      score += 128;
+    } else if properties.device_type
+                  == vk::PhysicalDeviceType::INTEGRATED_GPU
+    {
+      // It's still hardware rendering.
+      score += 96;
+    } else if properties.device_type == vk::PhysicalDeviceType::VIRTUAL_GPU {
+      // Whatever it is, the user went to some trouble to set it up.
+      score += 64;
+    } else if properties.device_type == vk::PhysicalDeviceType::CPU {
+      // Software rendering is slow, but at least it's a known quantity.
+      score += 32;
+    }
+    // If it's none of those, we don't have enough information to know if
+    // that's good or bad, so we assume it's bad.
+
+    //   Some of our scoring will depend on what extensions the device
+    // supports, so we enumerate those.
+    let mut available_extensions = HashSet::new();
+    for extension in unsafe {
+      instance.enumerate_device_extension_properties(*physical_device, None)
+    }? {
+      available_extensions.insert(extension.extension_name);
+    }
+    let available_extensions = available_extensions;
+
+    if available_extensions.contains(&vk::KHR_SWAPCHAIN_EXTENSION.name) {
+      //   Double buffering is both quite a nice feature to have, and a good
+      // indicator that this is a "real" graphics card rather than some
+      // trivial weird thing.
+      //
+      //   With that said, however, it only counts if we're able to actually
+      // use it on the surface we have. Let's find out...
+      if let Acceptable::Accepted(_) = Self::find_device_swapchain_features(
+                 instance, surface, physical_device)?
+      {
+        //   We don't count it for enough points to override a device type
+        // bracket, but it's good for a lot within the bracket.
+        score += 16;
+      }
+
+      //   This isn't disqualifying, so we don't worry about tracking the
+      // rationale. We'll deal with that later, if the device actually gets
+      // selected.
+    }
+
+    Ok(Acceptable::Accepted((score, indices)))
+  }
+
+  #[allow(unsafe_code)]
+  fn find_device_queue_family_indices(instance: &Instance,
+                                      surface: &vk::SurfaceKHR,
+                                      device: &vk::PhysicalDevice)
+      -> Result<Acceptable<QueueFamilyIndices>>
+  {
+    //   We need a queue family that supports graphics drawing commands, and a
+    // queue family that supports presentation commands. These may or may not
+    // be the same family.
+    let mut graphics = None;
+    let mut presentation = None;
+
+    for (index, queue_family) in (unsafe {
+      instance.get_physical_device_queue_family_properties(*device)
+    }).into_iter().enumerate() {
+      if graphics.is_none()
+         && queue_family.queue_flags.contains(vk::QueueFlags::GRAPHICS)
+      {
+        graphics = Some(index as u32);
+      }
+
+      if presentation.is_none() && unsafe {
+        instance.get_physical_device_surface_support_khr(
+            *device, index as u32, *surface)
+      }? {
+        presentation = Some(index as u32);
+      }
+    }
+
+    if let Some(graphics) = graphics {
+      if let Some(presentation) = presentation {
+        Ok(Acceptable::Accepted(QueueFamilyIndices {
+          graphics, presentation
+        }))
+      } else {
+        Ok(Acceptable::Rejected(
+            "Doesn't support presenting to our window.".to_string()))
+      }
+    } else {
+      Ok(Acceptable::Rejected("Doesn't support graphics.".to_string()))
+    }
+  }
+
+  //   We expect our caller to have already verified that the device supports
+  // the swapchain extension.
+  #[allow(unsafe_code)]
+  fn find_device_swapchain_features(instance: &Instance,
+                                    surface: &vk::SurfaceKHR,
+                                    physical_device: &vk::PhysicalDevice)
+      -> Result<Acceptable<(vk::SurfaceCapabilitiesKHR,
+                            Vec<vk::SurfaceFormatKHR>,
+                            Vec<vk::PresentModeKHR>)>>
+  {
+    let capabilities = unsafe {
+      instance.get_physical_device_surface_capabilities_khr(
+          *physical_device, *surface)
+    }?;
+    let formats = unsafe {
+      instance.get_physical_device_surface_formats_khr(
+          *physical_device, *surface)
+    }?;
+    let presentation_modes = unsafe {
+      instance.get_physical_device_surface_present_modes_khr(
+          *physical_device, *surface)
+    }?;
+
+    if formats.is_empty() {
+      Ok(Acceptable::Rejected("No matching surface formats.".to_string()))
+    } else if presentation_modes.is_empty() {
+      Ok(Acceptable::Rejected("No matching presentation modes.".to_string()))
+    } else {
+      Ok(Acceptable::Accepted((capabilities, formats, presentation_modes)))
+    }
+  }
+
+  #[allow(unsafe_code)]
+  fn load_spirv_shader_module(device: &Device, binary: &[u8])
+      -> Result<vk::ShaderModule>
+  {
+    let bytecode = Bytecode::new(binary)?;
+
+    let module_info = vk::ShaderModuleCreateInfo::builder()
+                          .code(bytecode.code())
+                          .code_size(bytecode.code_size());
+
+    let module = unsafe {
+      device.create_shader_module(&module_info, None)
+    }?;
+
+    Ok(module)
+  }
+
+  #[allow(unsafe_code)]
+  fn render(&mut self, window_id: WindowId) -> Result<()> {
+    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 = &permanent.device;
+      let frame_index = self.frame_index;
+      let concurrency = &mut window_dressing.concurrency;
+      let image_available_semaphore
+              = &concurrency.image_available_semaphores[frame_index];
+      let rendering_finished_semaphore
+              = &concurrency.rendering_finished_semaphores[frame_index];
+      let frame_fence = &concurrency.frame_fences[frame_index];
+
+      unsafe { device.wait_for_fences(&[*frame_fence], true, u64::MAX) }?;
+
+      let image_index = unsafe {
+        device.acquire_next_image_khr(window_dressing.swapchain.swapchain,
+                                      u64::MAX, *image_available_semaphore,
+                                      vk::Fence::null())
+      }?.0 as usize;
+
+      let image_fence = &concurrency.image_fences[image_index];
+      if !image_fence.is_null() {
+        unsafe { device.wait_for_fences(&[*image_fence], true, u64::MAX) }?;
+      }
+
+      concurrency.image_fences[image_index] = *frame_fence;
+
+      let first_semaphores = [*image_available_semaphore];
+      let second_semaphores = [*rendering_finished_semaphore];
+
+      let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT];
+      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)
+                            .command_buffers(&command_buffers)
+                            .signal_semaphores(&second_semaphores);
+      unsafe { device.reset_fences(&[*frame_fence]) }?;
+      unsafe {
+        device.queue_submit(permanent.graphics_queue,
+                            &[submit_info],
+                            *frame_fence)
+      }?;
+
+      let swapchains = [window_dressing.swapchain.swapchain];
+      let image_indices = [image_index as u32];
+      let present_info = vk::PresentInfoKHR::builder()
+                             .wait_semaphores(&second_semaphores)
+                             .swapchains(&swapchains)
+                             .image_indices(&image_indices);
+
+      unsafe {
+        device.queue_present_khr(permanent.presentation_queue, &present_info)
+      }?;
+
+      self.frame_index = (frame_index + 1) % N_SIMULTANEOUS_FRAMES;
+    }
+
+    Ok(())
+  }
+}
+
+impl Drop for Surreality {
+  #[allow(unsafe_code)]
+  fn drop(&mut self) {
+    if let Some(permanent) = self.permanent.replace(None) {
+      unsafe { permanent.device.device_wait_idle() }.unwrap();
+
+      if let Some(window_dressing) = self.window_dressing.replace(None) {
+        window_dressing.destroy(&permanent);
+      }
+
+      let device = permanent.device;
+      let instance = permanent.instance;
+
+      unsafe { device.destroy_device(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) = permanent.debug_messager {
+        unsafe {
+          instance.destroy_debug_utils_messenger_ext(debug_messager, None);
+        }
+      }
+
+      unsafe { instance.destroy_instance(None) };
+    }
+  }
+}
+
+impl WindowDressing {
+  fn new(permanent: &PermanentGraphicsState,
+          physical_device: vk::PhysicalDevice,
+          indices: QueueFamilyIndices)
+      -> Result<Self>
   {
     let window = &permanent.window;
     let instance = &permanent.instance;
@@ -568,8 +900,7 @@ impl Surreality {
     let swapchain = Self::init_swapchain(
             window, instance, surface, &physical_device, device, &indices)?;
 
-    let render_pass = Surreality::init_render_pass(device,
-                                                   &swapchain.format)?;
+    let render_pass = Self::init_render_pass(device, &swapchain.format)?;
 
     let (pipeline_layout, pipeline)
             = Self::init_pipeline(device, &swapchain.extent, &render_pass)?;
@@ -596,6 +927,39 @@ impl Surreality {
   }
 
   #[allow(unsafe_code)]
+  fn destroy(self, permanent: &PermanentGraphicsState) {
+    let device = &permanent.device;
+
+    for semaphore in self.concurrency.image_available_semaphores {
+      unsafe { device.destroy_semaphore(semaphore, None) };
+    }
+
+    for semaphore in self.concurrency.rendering_finished_semaphores {
+      unsafe { device.destroy_semaphore(semaphore, None) };
+    }
+
+    for fence in self.concurrency.frame_fences {
+      unsafe { device.destroy_fence(fence, None) };
+    }
+
+    unsafe { device.destroy_command_pool(self.command_pool, None) };
+
+    for framebuffer in self.framebuffers {
+      unsafe { device.destroy_framebuffer(framebuffer, None) };
+    }
+
+    unsafe { device.destroy_pipeline(self.pipeline, None) };
+    unsafe { device.destroy_render_pass(self.render_pass, None) };
+    unsafe { device.destroy_pipeline_layout(self.pipeline_layout, None) };
+
+    for view in self.swapchain.image_views {
+      unsafe { device.destroy_image_view(view, None) };
+    }
+
+    unsafe { device.destroy_swapchain_khr(self.swapchain.swapchain, None) };
+  }
+
+  #[allow(unsafe_code)]
   fn init_swapchain(window: &Window, instance: &Instance,
                     surface: &vk::SurfaceKHR,
                     physical_device: &vk::PhysicalDevice, device: &Device,
@@ -603,7 +967,7 @@ impl Surreality {
       -> Result<Swapchain>
   {
     let (capabilities, formats, presentation_modes)
-            = Self::find_device_swapchain_features(
+            = Surreality::find_device_swapchain_features(
                   instance, surface, physical_device)?.require()?;
 
     let format = Self::pick_surface_format(&formats)?;
@@ -756,9 +1120,9 @@ impl Surreality {
             concat!(env!("OUT_DIR"), "/shader.frag.spv"));
 
     let vertex_module
-            = Self::load_spirv_shader_module(device, vertex_binary)?;
+            = Surreality::load_spirv_shader_module(device, vertex_binary)?;
     let fragment_module
-            = Self::load_spirv_shader_module(device, fragment_binary)?;
+            = Surreality::load_spirv_shader_module(device, fragment_binary)?;
 
     let vertex_stage_info = vk::PipelineShaderStageCreateInfo::builder()
                                 .stage(vk::ShaderStageFlags::VERTEX)
@@ -1010,227 +1374,6 @@ impl Surreality {
     })
   }
 
-  //   To Vulkan, a "physical" device is the actual GPU, and a "logical"
-  // device is per-process state that represents a connection to the GPU.
-  // Before we can create a logical device, we must choose which physical
-  // device to connect it to.
-  #[allow(unsafe_code)]
-  fn pick_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR)
-      -> Result<(vk::PhysicalDevice, QueueFamilyIndices)>
-  {
-    let mut best_device = None;
-    let mut best_score = None;
-    let mut best_indices = None;
-    let mut rejected = BTreeMap::new();
-
-    for device in unsafe { instance.enumerate_physical_devices() }? {
-      match Self::score_vulkan_device(instance, surface, &device)? {
-        Acceptable::Accepted((new_score, new_indices)) => {
-          if let Some(old_score) = best_score {
-            if new_score > old_score {
-              best_device = Some(device);
-              best_score = Some(new_score);
-              best_indices = Some(new_indices);
-            }
-          } else {
-            best_device = Some(device);
-            best_score = Some(new_score);
-            best_indices = Some(new_indices);
-          }
-        }
-        Acceptable::Rejected(reason) => {
-          let properties = unsafe {
-            instance.get_physical_device_properties(device)
-          };
-
-          let name = properties.device_name.to_string_lossy().into_owned();
-
-          rejected.insert(properties.device_id, (name, reason));
-        }
-      }
-    }
-
-    if let (Some(device), Some(indices)) = (best_device, best_indices) {
-      Ok((device, indices))
-    } else if rejected.is_empty() {
-      Err(Error {
-        message: "The system has no GPUs of any kind.".to_string()
-      })
-    } else {
-      for (_, (name, reason)) in rejected {
-        eprintln!("Can't run on {} because: {}", name, reason);
-      }
-
-      Err(Error {
-        message: "The system has GPUs, but none are acceptable (see above)."
-                 .to_string()
-      })
-    }
-  }
-
-  //   We're doing two tasks: Quantifying how strongly we prefer a device, and
-  // deciding whether it's acceptable at all. If it's unacceptable, it's
-  // possible there will be no acceptable devices, and in that case our caller
-  // will want to print explanations, but otherwise it'll want to be quiet. So
-  // the outer Result is whether we successfully evaluated the device, and the
-  // inner Acceptable is whether we approve of it.
-  //
-  //   In the event that we find the device acceptable, we also return the
-  // queue family indices we'd be using if we ultimately go with it. While
-  // this is not strictly necessary, it's better to return them from here
-  // than to recompute them later on the assumption it'll work out the same.
-  #[allow(unsafe_code)]
-  fn score_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR,
-                         physical_device: &vk::PhysicalDevice)
-      -> Result<Acceptable<(u64, QueueFamilyIndices)>>
-  {
-    //   Not all devices support graphics, and not all devices support
-    // presenting to any given surface. We check whether this one is suitable
-    // by looking up the indices of the queue families we would use. If we
-    // ultimately use this device, we'll need these, so we make sure to return
-    // them.
-    let indices = match Self::find_device_queue_family_indices(
-                            instance, surface, physical_device)?
-    {
-      Acceptable::Rejected(rationale) => {
-        return Ok(Acceptable::Rejected(rationale));
-      }
-      Acceptable::Accepted(indices) => indices
-    };
-
-    //   At this point we know the device meets our high-level requirements,
-    // so it's just a question of scoring.
-    let properties = unsafe {
-      instance.get_physical_device_properties(*physical_device)
-    };
-
-    let mut score = 0;
-    if properties.device_type == vk::PhysicalDeviceType::DISCRETE_GPU {
-      // If the user has a fancy GPU, they prefer it.
-      score += 128;
-    } else if properties.device_type
-                  == vk::PhysicalDeviceType::INTEGRATED_GPU
-    {
-      // It's still hardware rendering.
-      score += 96;
-    } else if properties.device_type == vk::PhysicalDeviceType::VIRTUAL_GPU {
-      // Whatever it is, the user went to some trouble to set it up.
-      score += 64;
-    } else if properties.device_type == vk::PhysicalDeviceType::CPU {
-      // Software rendering is slow, but at least it's a known quantity.
-      score += 32;
-    }
-    // If it's none of those, we don't have enough information to know if
-    // that's good or bad, so we assume it's bad.
-
-    //   Some of our scoring will depend on what extensions the device
-    // supports, so we enumerate those.
-    let mut available_extensions = HashSet::new();
-    for extension in unsafe {
-      instance.enumerate_device_extension_properties(*physical_device, None)
-    }? {
-      available_extensions.insert(extension.extension_name);
-    }
-    let available_extensions = available_extensions;
-
-    if available_extensions.contains(&vk::KHR_SWAPCHAIN_EXTENSION.name) {
-      //   Double buffering is both quite a nice feature to have, and a good
-      // indicator that this is a "real" graphics card rather than some
-      // trivial weird thing.
-      //
-      //   With that said, however, it only counts if we're able to actually
-      // use it on the surface we have. Let's find out...
-      if let Acceptable::Accepted(_) = Self::find_device_swapchain_features(
-                 instance, surface, physical_device)?
-      {
-        //   We don't count it for enough points to override a device type
-        // bracket, but it's good for a lot within the bracket.
-        score += 16;
-      }
-
-      //   This isn't disqualifying, so we don't worry about tracking the
-      // rationale. We'll deal with that later, if the device actually gets
-      // selected.
-    }
-
-    Ok(Acceptable::Accepted((score, indices)))
-  }
-
-  #[allow(unsafe_code)]
-  fn find_device_queue_family_indices(instance: &Instance,
-                                      surface: &vk::SurfaceKHR,
-                                      device: &vk::PhysicalDevice)
-      -> Result<Acceptable<QueueFamilyIndices>>
-  {
-    //   We need a queue family that supports graphics drawing commands, and a
-    // queue family that supports presentation commands. These may or may not
-    // be the same family.
-    let mut graphics = None;
-    let mut presentation = None;
-
-    for (index, queue_family) in (unsafe {
-      instance.get_physical_device_queue_family_properties(*device)
-    }).into_iter().enumerate() {
-      if graphics.is_none()
-         && queue_family.queue_flags.contains(vk::QueueFlags::GRAPHICS)
-      {
-        graphics = Some(index as u32);
-      }
-
-      if presentation.is_none() && unsafe {
-        instance.get_physical_device_surface_support_khr(
-            *device, index as u32, *surface)
-      }? {
-        presentation = Some(index as u32);
-      }
-    }
-
-    if let Some(graphics) = graphics {
-      if let Some(presentation) = presentation {
-        Ok(Acceptable::Accepted(QueueFamilyIndices {
-          graphics, presentation
-        }))
-      } else {
-        Ok(Acceptable::Rejected(
-            "Doesn't support presenting to our window.".to_string()))
-      }
-    } else {
-      Ok(Acceptable::Rejected("Doesn't support graphics.".to_string()))
-    }
-  }
-
-  //   We expect our caller to have already verified that the device supports
-  // the swapchain extension.
-  #[allow(unsafe_code)]
-  fn find_device_swapchain_features(instance: &Instance,
-                                    surface: &vk::SurfaceKHR,
-                                    physical_device: &vk::PhysicalDevice)
-      -> Result<Acceptable<(vk::SurfaceCapabilitiesKHR,
-                            Vec<vk::SurfaceFormatKHR>,
-                            Vec<vk::PresentModeKHR>)>>
-  {
-    let capabilities = unsafe {
-      instance.get_physical_device_surface_capabilities_khr(
-          *physical_device, *surface)
-    }?;
-    let formats = unsafe {
-      instance.get_physical_device_surface_formats_khr(
-          *physical_device, *surface)
-    }?;
-    let presentation_modes = unsafe {
-      instance.get_physical_device_surface_present_modes_khr(
-          *physical_device, *surface)
-    }?;
-
-    if formats.is_empty() {
-      Ok(Acceptable::Rejected("No matching surface formats.".to_string()))
-    } else if presentation_modes.is_empty() {
-      Ok(Acceptable::Rejected("No matching presentation modes.".to_string()))
-    } else {
-      Ok(Acceptable::Accepted((capabilities, formats, presentation_modes)))
-    }
-  }
-
   fn pick_surface_format(available_formats: &Vec<vk::SurfaceFormatKHR>)
       -> Result<vk::SurfaceFormatKHR>
   {
@@ -1273,156 +1416,6 @@ impl Surreality {
       Ok(vk::Extent2D::builder().width(width).height(height).build())
     }
   }
-
-  #[allow(unsafe_code)]
-  fn load_spirv_shader_module(device: &Device, binary: &[u8])
-      -> Result<vk::ShaderModule>
-  {
-    let bytecode = Bytecode::new(binary)?;
-
-    let module_info = vk::ShaderModuleCreateInfo::builder()
-                          .code(bytecode.code())
-                          .code_size(bytecode.code_size());
-
-    let module = unsafe {
-      device.create_shader_module(&module_info, None)
-    }?;
-
-    Ok(module)
-  }
-
-  #[allow(unsafe_code)]
-  fn render(&mut self, window_id: WindowId) -> Result<()> {
-    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 = &permanent.device;
-      let frame_index = self.frame_index;
-      let concurrency = &mut window_dressing.concurrency;
-      let image_available_semaphore
-              = &concurrency.image_available_semaphores[frame_index];
-      let rendering_finished_semaphore
-              = &concurrency.rendering_finished_semaphores[frame_index];
-      let frame_fence = &concurrency.frame_fences[frame_index];
-
-      unsafe { device.wait_for_fences(&[*frame_fence], true, u64::MAX) }?;
-
-      let image_index = unsafe {
-        device.acquire_next_image_khr(window_dressing.swapchain.swapchain,
-                                      u64::MAX, *image_available_semaphore,
-                                      vk::Fence::null())
-      }?.0 as usize;
-
-      let image_fence = &concurrency.image_fences[image_index];
-      if !image_fence.is_null() {
-        unsafe { device.wait_for_fences(&[*image_fence], true, u64::MAX) }?;
-      }
-
-      concurrency.image_fences[image_index] = *frame_fence;
-
-      let first_semaphores = [*image_available_semaphore];
-      let second_semaphores = [*rendering_finished_semaphore];
-
-      let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT];
-      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)
-                            .command_buffers(&command_buffers)
-                            .signal_semaphores(&second_semaphores);
-      unsafe { device.reset_fences(&[*frame_fence]) }?;
-      unsafe {
-        device.queue_submit(permanent.graphics_queue,
-                            &[submit_info],
-                            *frame_fence)
-      }?;
-
-      let swapchains = [window_dressing.swapchain.swapchain];
-      let image_indices = [image_index as u32];
-      let present_info = vk::PresentInfoKHR::builder()
-                             .wait_semaphores(&second_semaphores)
-                             .swapchains(&swapchains)
-                             .image_indices(&image_indices);
-
-      unsafe {
-        device.queue_present_khr(permanent.presentation_queue, &present_info)
-      }?;
-
-      self.frame_index = (frame_index + 1) % N_SIMULTANEOUS_FRAMES;
-    }
-
-    Ok(())
-  }
-}
-
-impl Drop for Surreality {
-  #[allow(unsafe_code)]
-  fn drop(&mut self) {
-    if let Some(permanent) = self.permanent.replace(None) {
-      unsafe { permanent.device.device_wait_idle() }.unwrap();
-
-      if let Some(window_dressing) = self.window_dressing.replace(None) {
-        window_dressing.destroy(&permanent);
-      }
-
-      let device = permanent.device;
-      let instance = permanent.instance;
-
-      unsafe { device.destroy_device(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) = permanent.debug_messager {
-        unsafe {
-          instance.destroy_debug_utils_messenger_ext(debug_messager, None);
-        }
-      }
-
-      unsafe { instance.destroy_instance(None) };
-    }
-  }
-}
-
-impl WindowDressing {
-  #[allow(unsafe_code)]
-  fn destroy(self, permanent: &PermanentGraphicsState) {
-    let device = &permanent.device;
-
-    for semaphore in self.concurrency.image_available_semaphores {
-      unsafe { device.destroy_semaphore(semaphore, None) };
-    }
-
-    for semaphore in self.concurrency.rendering_finished_semaphores {
-      unsafe { device.destroy_semaphore(semaphore, None) };
-    }
-
-    for fence in self.concurrency.frame_fences {
-      unsafe { device.destroy_fence(fence, None) };
-    }
-
-    unsafe { device.destroy_command_pool(self.command_pool, None) };
-
-    for framebuffer in self.framebuffers {
-      unsafe { device.destroy_framebuffer(framebuffer, None) };
-    }
-
-    unsafe { device.destroy_pipeline(self.pipeline, None) };
-    unsafe { device.destroy_render_pass(self.render_pass, None) };
-    unsafe { device.destroy_pipeline_layout(self.pipeline_layout, None) };
-
-    for view in self.swapchain.image_views {
-      unsafe { device.destroy_image_view(view, None) };
-    }
-
-    unsafe { device.destroy_swapchain_khr(self.swapchain.swapchain, None) };
-  }
 }
 
 impl ApplicationHandler for Surreality {