summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs1474
1 files changed, 722 insertions, 752 deletions
diff --git a/src/main.rs b/src/main.rs
index 7c04245..3bba33b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,7 @@
 #![deny(unsafe_code)]
 use crate::error::*;
 
-use std::cell::OnceCell;
+use std::cell::RefCell;
 use std::collections::{ BTreeMap, BTreeSet, HashSet };
 use std::ffi::{ c_void, CStr };
 use vulkanalia::{ Device, Entry, Instance, Version };
@@ -52,6 +52,13 @@ impl<T> Acceptable<T> {
       panic!("Unwrapped a rejected Acceptable.");
     }
   }
+
+  fn require(self) -> Result<T> {
+    match self {
+      Acceptable::Accepted(value) => Ok(value),
+      Acceptable::Rejected(message) => Err(Error { message }),
+    }
+  }
 }
 
 #[derive(Debug)]
@@ -73,46 +80,35 @@ struct Surreality {
   // 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: OnceCell<Window>,
-
-  //   There are a few Vulkan features (in the informal sense of "feature")
-  // that we want to be able to run both with and without. Here, we have
-  // booleans describing which we're doing. These are computed during instance
-  // and device initialization.
-  //
-  //   In the cases of validation and portability, the booleans are only used
-  // to communicate between initialization phases, and aren't actually needed
-  // during rendering. We keep them around anyway though because they're small
-  // and it's more convenient to have them all in one place.
-  enable_validation: OnceCell<bool>,
-  enable_portability: OnceCell<bool>,
-  enable_swapchain: OnceCell<bool>,
+  window: RefCell<Option<Window>>,
 
   //   The Vulkan "entry" is the part of the Vulkan library ecosystem that's
-  // responsible for finding and loading the other parts.
-  entry: OnceCell<Entry>,
+  // 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>>,
 
   //   The Vulkan "instance" is the bulk of the Vulkan library, with most of
   // the high-level responsibilities around lifecycle management.
-  instance: OnceCell<Instance>,
+  instance: RefCell<Option<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: OnceCell<vk::DebugUtilsMessengerEXT>,
+  debug_messager: RefCell<Option<vk::DebugUtilsMessengerEXT>>,
 
   //   The Vulkan "surface" is the destination that rendering happens into.
   // It is connected to the window but distinct from it.
-  surface: OnceCell<vk::SurfaceKHR>,
+  surface: RefCell<Option<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 track both.
-  // We'll be referencing the logical device a lot, so we follow Vulkan's lead
-  // and let it have a short variable name.
-  physical_device: OnceCell<vk::PhysicalDevice>,
-  device: OnceCell<Device>,
+  // 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>>,
 
   //   Vulkan has a first-class concept of command queues. We have two of
   // them, one for graphics drawing commands and one for presentation.
@@ -125,31 +121,59 @@ struct Surreality {
   //
   //   Yes, this means the compiler has to deal with pointer aliasing
   // concerns, which have a tendency to defeat optimizations.
-  graphics_queue: OnceCell<vk::Queue>,
-  presentation_queue: OnceCell<vk::Queue>,
+  graphics_queue: RefCell<Option<vk::Queue>>,
+  presentation_queue: RefCell<Option<vk::Queue>>,
+
+  swapchain: RefCell<Option<Swapchain>>,
 
-  //   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
-  // now, we use at most one of it. We also support running without one.
-  swapchain: OnceCell<vk::SwapchainKHR>,
-  swapchain_images: OnceCell<Vec<vk::Image>>,
-  swapchain_image_views: OnceCell<Vec<vk::ImageView>>,
-  format: OnceCell<vk::Format>,
-  extent: OnceCell<vk::Extent2D>,
+  render_pass: RefCell<Option<vk::RenderPass>>,
 
-  render_pass: OnceCell<vk::RenderPass>,
+  pipeline: RefCell<Option<vk::Pipeline>>,
+  pipeline_layout: RefCell<Option<vk::PipelineLayout>>,
 
-  pipeline: OnceCell<vk::Pipeline>,
-  pipeline_layout: OnceCell<vk::PipelineLayout>,
+  framebuffers: RefCell<Option<Vec<vk::Framebuffer>>>,
 
-  framebuffers: OnceCell<Vec<vk::Framebuffer>>,
+  command_pool: RefCell<Option<vk::CommandPool>>,
+  command_buffers: RefCell<Option<Vec<vk::CommandBuffer>>>,
 
-  command_pool: OnceCell<vk::CommandPool>,
-  command_buffers: OnceCell<Vec<vk::CommandBuffer>>,
+  concurrency: RefCell<Option<Concurrency>>,
 
-  image_available_semaphores: OnceCell<Vec<vk::Semaphore>>,
-  rendering_finished_semaphores: OnceCell<Vec<vk::Semaphore>>,
+  frame_index: usize,
+}
+
+struct InstanceCreation {
+  instance: Instance,
+  debug_messager: Option<vk::DebugUtilsMessengerEXT>,
+  enable_portability: bool,
+  enable_validation: bool,
+}
+
+struct DeviceCreation {
+  physical_device: vk::PhysicalDevice,
+  device: Device,
+  indices: QueueFamilyIndices,
+  graphics_queue: vk::Queue,
+  presentation_queue: vk::Queue,
+  enable_swapchain: bool,
+}
+
+//   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
+// now, we use at most one of it. We also support running without one.
+#[derive(Debug)]
+struct Swapchain {
+  swapchain: vk::SwapchainKHR,
+  images: Vec<vk::Image>,
+  image_views: Vec<vk::ImageView>,
+  format: vk::Format,
+  extent: vk::Extent2D,
+}
+
+#[derive(Debug)]
+struct Concurrency {
+  image_available_semaphores: Vec<vk::Semaphore>,
+  rendering_finished_semaphores: Vec<vk::Semaphore>,
 
   //   Okay, the lifetime management on the fences is really subtle. There is
   // one fence for each frame, and frame_fences holds the authoritative
@@ -163,99 +187,104 @@ struct Surreality {
   // of the frame fence. This happens during rendering of the frame, so the
   // frame fence is in the "signaled" state. It will be reset right before
   // submitting the queue, then signaled again when the submission completes.
-  frame_fences: OnceCell<Vec<vk::Fence>>,
-  image_fences: Vec<vk::Fence>,
-
-  frame_index: usize,
+  frame_fences: Vec<vk::Fence>,
+  image_fences: RefCell<Vec<vk::Fence>>,
 }
 
 impl Surreality {
   fn new() -> Self {
     Surreality {
-      window: OnceCell::new(),
-      enable_validation: OnceCell::new(),
-      enable_portability: OnceCell::new(),
-      enable_swapchain: OnceCell::new(),
-      entry: OnceCell::new(),
-      instance: OnceCell::new(),
-      debug_messager: OnceCell::new(),
-      surface: OnceCell::new(),
-      physical_device: OnceCell::new(),
-      device: OnceCell::new(),
-      graphics_queue: OnceCell::new(),
-      presentation_queue: OnceCell::new(),
-      swapchain: OnceCell::new(),
-      swapchain_images: OnceCell::new(),
-      swapchain_image_views: OnceCell::new(),
-      format: OnceCell::new(),
-      extent: OnceCell::new(),
-      render_pass: OnceCell::new(),
-      pipeline: OnceCell::new(),
-      pipeline_layout: OnceCell::new(),
-      framebuffers: OnceCell::new(),
-      command_pool: OnceCell::new(),
-      command_buffers: OnceCell::new(),
-      image_available_semaphores: OnceCell::new(),
-      rendering_finished_semaphores: OnceCell::new(),
-      frame_fences: OnceCell::new(),
-      image_fences: Vec::new(),
+      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),
+      swapchain: RefCell::new(None),
+      render_pass: RefCell::new(None),
+      pipeline: RefCell::new(None),
+      pipeline_layout: RefCell::new(None),
+      framebuffers: RefCell::new(None),
+      command_pool: RefCell::new(None),
+      command_buffers: RefCell::new(None),
+      concurrency: RefCell::new(None),
       frame_index: 0,
     }
   }
 
   fn init(&mut self, event_loop: &ActiveEventLoop) -> Result<()> {
-    // TODO refactor all these to not be methods, for better isolation
+    let window = Self::init_window(event_loop)?;
+    let entry = Self::init_vulkan_entry()?;
 
-    if self.window.get().is_none() {
-      self.init_window(event_loop)?;
-    }
+    let InstanceCreation {
+      instance,
+      debug_messager,
 
-    if self.entry.get().is_none() {
-      self.init_vulkan_entry()?;
-    }
-
-    if self.instance.get().is_none() {
-      self.init_vulkan_instance()?;
-    }
-
-    if self.surface.get().is_none() {
-      self.init_vulkan_surface()?;
-    }
-
-    if self.device.get().is_none() {
-      self.init_vulkan_device()?;
-    }
-
-    if self.swapchain.get().is_none()
-       && *self.enable_swapchain.get().unwrap()
-    {
-      self.init_vulkan_swapchain()?;
-    }
-
-    if self.render_pass.get().is_none() {
-      self.init_render_pass()?;
-    }
-
-    if self.pipeline.get().is_none() {
-      self.init_pipeline()?;
-    }
-
-    if self.framebuffers.get().is_none() {
-      self.init_framebuffers()?;
-    }
-
-    if self.command_buffers.get().is_none() {
-      self.init_commands()?;
+      //   There are a few Vulkan features (in the informal sense of
+      // "feature") that we want to be able to run both with and without.
+      // Here, we have booleans describing which we're doing.
+      //
+      //   These are only used to communicate between initialization phases;
+      // we don't keep them around after that.
+      enable_portability,
+      enable_validation
+    } = Self::init_vulkan_instance(&window, &entry)?;
+
+    let surface = Self::init_surface(&window, &instance)?;
+
+    let DeviceCreation {
+      physical_device, device, indices, graphics_queue, presentation_queue,
+      enable_swapchain
+    } = Self::init_vulkan_device(&instance, &surface,
+                                 enable_validation, enable_portability)?;
+
+    if enable_swapchain {
+      let swapchain = Self::init_swapchain(
+              &window, &instance, &surface, &physical_device, &device,
+              &indices)?;
+
+      let render_pass = Surreality::init_render_pass(&device,
+                                                     &swapchain.format)?;
+
+      let (pipeline_layout, pipeline)
+              = Self::init_pipeline(&device, &swapchain.extent,
+                                    &render_pass)?;
+
+      let framebuffers = Self::init_framebuffers(
+              &device, &swapchain.extent, &swapchain.image_views,
+              &render_pass)?;
+
+      let (command_pool, command_buffers)
+              = Self::init_commands(&device, &swapchain.extent, &framebuffers,
+                                    &render_pass, &pipeline, &indices)?;
+
+      let concurrency = Self::init_concurrency(&device, &swapchain.images)?;
+
+      *self.swapchain.get_mut() = Some(swapchain);
+      *self.render_pass.get_mut() = Some(render_pass);
+      *self.pipeline.get_mut() = Some(pipeline);
+      *self.pipeline_layout.get_mut() = Some(pipeline_layout);
+      *self.framebuffers.get_mut() = Some(framebuffers);
+      *self.command_pool.borrow_mut() = Some(command_pool);
+      *self.command_buffers.borrow_mut() = Some(command_buffers);
+      *self.concurrency.get_mut() = Some(concurrency);
     }
 
-    if self.image_available_semaphores.get().is_none() {
-      self.init_concurrency()?;
-    }
+    *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);
 
     Ok(())
   }
 
-  fn init_window(&mut self, event_loop: &ActiveEventLoop) -> Result<()> {
+  fn init_window(event_loop: &ActiveEventLoop) -> Result<Window> {
     //   Notice that we do this before having a Vulkan instance. The window is
     // actually a parameter needed to create the instance; see
     // init_vulkan_instance(), below.
@@ -263,15 +292,13 @@ impl Surreality {
             .with_title("Love, Curiosity, Justice")
             .with_inner_size(LogicalSize::new(1024, 768));
 
-    let window: Window = event_loop.create_window(window_attributes)?;
-
-    self.window.set(window).unwrap();
-
-    Ok(())
+    Ok(event_loop.create_window(window_attributes)?)
   }
 
+  // TODO this is another candidate for rolling into its parent
+  // (in addition to init_surface, which is below. what is time)
   #[allow(unsafe_code)]
-  fn init_vulkan_entry(&mut self) -> Result<()> {
+  fn init_vulkan_entry() -> Result<Entry> {
     //   Okay, so, a Vulkan "entry" is a small set of functions which are used
     // to dynamically load all the rest of Vulkan. It's our responsibility to
     // know how to load the entry, then it will take care of the rest. At
@@ -284,15 +311,13 @@ impl Surreality {
     let loader = unsafe { LibloadingLoader::new(LIBRARY) }?;
     let entry = unsafe { Entry::new(loader) }?;
 
-    self.entry.set(entry).unwrap();
-
-    Ok(())
+    Ok(entry)
   }
 
   #[allow(unsafe_code)]
-  fn init_vulkan_instance(&mut self) -> Result<()> {
-    let entry = self.entry.get().unwrap();
-
+  fn init_vulkan_instance(window: &Window, entry: &Entry)
+      -> Result<InstanceCreation>
+  {
     let enable_validation = cfg!(feature = "vulkan-validation")
                             || cfg!(debug_assertions);
 
@@ -325,14 +350,16 @@ impl Surreality {
     //   This is possible because of an integration between Vulkanalia and
     // winit, which is enabled by Vulkanalia's "window" feature.
     for extension in vulkanalia::window::get_required_instance_extensions(
-                         self.window.get().unwrap())
+                         window)
     {
       extensions.push(extension.as_ptr());
     }
 
     //   Deal with Vulkan's thing about opting in to non-conforming
     // implementations.
-    if entry.version()? >= VULKAN_FIRST_PORTABILITY_VERSION {
+    let enable_portability = if entry.version()?
+                                >= VULKAN_FIRST_PORTABILITY_VERSION
+    {
       if cfg!(target_os = "macos") {
         // Vulkan on the Mac is not fully conforming.
         extensions.push(
@@ -341,31 +368,31 @@ impl Surreality {
             vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr());
         flags.insert(vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR);
 
-        self.enable_portability.set(true).unwrap();
+        true
       } else {
-        self.enable_portability.set(false).unwrap();
+        false
       }
     } else {
-      self.enable_portability.set(false).unwrap();
-    }
+      false
+    };
 
     // Request the LunarG validation layer, when appropriate.
     let validation_layer_name = vk::ExtensionName::from_bytes(
                                     b"VK_LAYER_KHRONOS_validation");
-    if enable_validation {
+    let enable_validation = if enable_validation {
       if available_layers.contains(&validation_layer_name) {
         layers.push(validation_layer_name.as_ptr());
 
-        self.enable_validation.set(enable_validation).unwrap();
+        true
       } else {
         eprintln!("Vulkan validation requested at build time, \
                    but no validation layer available.");
 
-        self.enable_validation.set(false).unwrap();
+        false
       }
     } else {
-      self.enable_validation.set(false).unwrap();
-    }
+      false
+    };
 
     //   Request the debug extension. This is the first of three bits of code
     // that deal with this, and has the resonsibility of making sure the
@@ -428,27 +455,28 @@ impl Surreality {
     //   Configure the debug extension. This is the last of three bits of code
     // that deal with this, and has the responsibility of asking the instance,
     // which now exists, to create the debug messager.
-    if let Some(debug_info) = debug_info
-       && self.debug_messager.get().is_none()
-    {
+    let debug_messager = if let Some(debug_info) = debug_info {
       #[allow(unsafe_code)]
-      let debug_messager = unsafe {
+      Some(unsafe {
         instance.create_debug_utils_messenger_ext(&debug_info, None)
-      }?;
-
-      self.debug_messager.set(debug_messager).unwrap();
-    }
-
-    self.instance.set(instance).unwrap();
+      }?)
+    } else {
+      None
+    };
 
-    Ok(())
+    Ok(InstanceCreation {
+      instance,
+      debug_messager,
+      enable_portability,
+      enable_validation,
+    })
   }
 
+  // TODO this is so short that it can likely be eliminated
   #[allow(unsafe_code)]
-  fn init_vulkan_surface(&mut self) -> Result<()> {
-    let window = self.window.get().unwrap();
-    let instance = self.instance.get().unwrap();
-
+  fn init_surface(window: &Window, instance: &Instance)
+      -> Result<vk::SurfaceKHR>
+  {
     //   Conveniently, Vulkanalia's "window" feature allows it to get the
     // platform-specific stuff directly out of winit for us. This wrapper does
     // not correspond 1:1 to a Vulkan function; rather, it picks the Vulkan
@@ -461,561 +489,517 @@ impl Surreality {
       vulkanalia::window::create_surface(&instance, &window, &window)
     }?;
 
-    self.surface.set(surface).unwrap();
-
-    Ok(())
+    Ok(surface)
   }
 
   #[allow(unsafe_code)]
-  fn init_vulkan_device(&mut self) -> Result<()> {
-    if self.physical_device.get().is_none() {
-      let physical_device = self.pick_vulkan_device()?;
-
-      self.physical_device.set(physical_device).unwrap();
+  fn init_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR,
+                        enable_validation: bool, enable_portability: bool)
+      -> Result<DeviceCreation>
+  {
+    let physical_device = Self::pick_vulkan_device(instance, surface)?;
+
+    //   We already did the check in score_vulkan_device(), so if it fails
+    // this second time, that's our own bug and we don't need to explain it
+    // to our users.
+    // TODO looks sus though
+    let indices = Self::find_device_queue_family_indices(
+                      instance, surface, &physical_device)?.unwrap();
+
+    //   We enumerate the device extensions here so they can inform
+    // configuration. We already did this in score_vulkan_device(), but here
+    // it is again.
+    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 self.device.get().is_none() {
-      //   Usually we're content to borrow these, but here, that would give us
-      // ownership problems. In reality they are smart pointer objects that do
-      // not directly contain their substantive pieces, so we can freely clone
-      // them, and in this case it's convenient to do that.
-      let instance = self.instance.get().unwrap().clone();
-      let physical_device = self.physical_device.get().unwrap().clone();
-
-      //   We already did the check in score_vulkan_device(), so if it fails
-      // this second time, that's our own bug and we don't need to explain it
-      // to our users.
-      let indices = self.find_device_queue_family_indices(&physical_device)?
-                        .unwrap();
-
-      //   We enumerate the device extensions here so they can inform
-      // configuration. We already did this in score_vulkan_device(), but here
-      // it is again.
-      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;
-
-      //   Old versions of Vulkan want layers to be enabled at the device
-      // level as well. Newer ones will ignore this and just use the instance
-      // layers.
-      let features = vk::PhysicalDeviceFeatures::builder();
-      let mut extensions = Vec::new();
-      let mut layers = Vec::new();
-
-      let validation_layer_name = vk::ExtensionName::from_bytes(
-                                      b"VK_LAYER_KHRONOS_validation");
-      if *self.enable_validation.get().unwrap() {
-        //   It's not concerning if this isn't supported, because device
-        // layers are ignored on recent versions, they're purely historical.
-        if available_extensions.contains(&validation_layer_name) {
-          layers.push(validation_layer_name.as_ptr());
-        }
-      }
+    //   Old versions of Vulkan want layers to be enabled at the device
+    // level as well. Newer ones will ignore this and just use the instance
+    // layers.
+    let features = vk::PhysicalDeviceFeatures::builder();
+    let mut extensions = Vec::new();
+    let mut layers = Vec::new();
 
-      let portability_extension_name = vk::ExtensionName::from_bytes(
-                                           b"VK_KHR_portability_subset");
-      if *self.enable_portability.get().unwrap() {
-        //   This is untested, since the only scenario where it would come up
-        // is on a Mac, which we don't actually support. Sorry, and good luck.
-        if available_extensions.contains(&portability_extension_name) {
-          extensions.push(portability_extension_name.as_ptr());
-        }
+    let validation_layer_name = vk::ExtensionName::from_bytes(
+                                    b"VK_LAYER_KHRONOS_validation");
+    if enable_validation {
+      //   It's not concerning if this isn't supported, because device
+      // layers are ignored on recent versions, they're purely historical.
+      if available_extensions.contains(&validation_layer_name) {
+        layers.push(validation_layer_name.as_ptr());
       }
+    }
 
-      let swapchain_extension_name = vk::KHR_SWAPCHAIN_EXTENSION.name;
-      if available_extensions.contains(&swapchain_extension_name) {
-        //   It's important that we not call the swapchain extension
-        // functions until we've verified the extension is supported. To
-        // emphasize that, we do it on a separate line.
-        //
-        //   We've done this check once already, in scoring, and now here
-        // we are discarding its results a second time. We'll do it for the
-        // third and last time in swapchain creation.
-        if let Acceptable::Accepted(_)
-               = self.find_device_swapchain_features(&physical_device)?
-        {
-          extensions.push(swapchain_extension_name.as_ptr());
-
-          self.enable_swapchain.set(true).unwrap();
-        } else {
-          self.enable_swapchain.set(false).unwrap();
-        }
-      } else {
-        self.enable_swapchain.set(false).unwrap();
+    let portability_extension_name = vk::ExtensionName::from_bytes(
+                                         b"VK_KHR_portability_subset");
+    if enable_portability {
+      //   This is untested, since the only scenario where it would come up
+      // is on a Mac, which we don't actually support. Sorry, and good luck.
+      if available_extensions.contains(&portability_extension_name) {
+        extensions.push(portability_extension_name.as_ptr());
       }
+    }
+
+    let swapchain_extension_name = vk::KHR_SWAPCHAIN_EXTENSION.name;
+    let enable_swapchain = if available_extensions.contains(
+                                  &swapchain_extension_name)
+    {
+      //   It's important that we not call the swapchain extension
+      // functions until we've verified the extension is supported. To
+      // emphasize that, we do it on a separate line.
+      //
+      //   We've done this check once already, in scoring, and now here
+      // we are discarding its results a second time. We'll do it for the
+      // third and last time in swapchain creation.
+      if let Acceptable::Accepted(_) = Self::find_device_swapchain_features(
+                 &instance, &surface, &physical_device)?
+      {
+        extensions.push(swapchain_extension_name.as_ptr());
 
-      //   We have one or more queue family indices; we don't know a priori
-      // how many, because it's possible some of them are the same. We only
-      // want to create one queue per distinct family, so we find the unique
-      // indices...
-      let mut unique_queue_family_indices = BTreeSet::new();
-      unique_queue_family_indices.insert(indices.graphics);
-      unique_queue_family_indices.insert(indices.presentation);
-
-      // ... then add a queue create info struct for each.
-      let mut queues = Vec::new();
-      for index in unique_queue_family_indices {
-        //   Passing the priorities vector also implicitly sets the count of
-        // how many queues we are creating within the family. This nicety is
-        // one of the fun things Vulkanalia's builders do for us.
-        queues.push(vk::DeviceQueueCreateInfo::builder()
-                        .queue_family_index(index)
-                        .queue_priorities(&[1.0]));
+        true
+      } else {
+        false
       }
+    } else {
+      false
+    };
 
-      let device_info = vk::DeviceCreateInfo::builder()
-              .queue_create_infos(&queues)
-              .enabled_layer_names(&layers)
-              .enabled_extension_names(&extensions)
-              .enabled_features(&features);
+    //   We have one or more queue family indices; we don't know a priori
+    // how many, because it's possible some of them are the same. We only
+    // want to create one queue per distinct family, so we find the unique
+    // indices...
+    let mut unique_queue_family_indices = BTreeSet::new();
+    unique_queue_family_indices.insert(indices.graphics);
+    unique_queue_family_indices.insert(indices.presentation);
+
+    // ... then add a queue create info struct for each.
+    let mut queues = Vec::new();
+    for index in unique_queue_family_indices {
+      //   Passing the priorities vector also implicitly sets the count of
+      // how many queues we are creating within the family. This nicety is
+      // one of the fun things Vulkanalia's builders do for us.
+      queues.push(vk::DeviceQueueCreateInfo::builder()
+                      .queue_family_index(index)
+                      .queue_priorities(&[1.0]));
+    }
 
-      let device = unsafe {
-        instance.create_device(*self.physical_device.get().unwrap(),
-                               &device_info, None)
-      }?;
+    let device_info = vk::DeviceCreateInfo::builder()
+            .queue_create_infos(&queues)
+            .enabled_layer_names(&layers)
+            .enabled_extension_names(&extensions)
+            .enabled_features(&features);
 
-      //   So, this is a little confusing. Queues are found in queue families.
-      // The family has an index within the device, and the queue has an index
-      // within the family. We computed the family index above, and when we
-      // created the device we told it to create just a single queue in that
-      // family. Now we pass both indices to find the actual queue object.
-      let graphics_queue = unsafe {
-        device.get_device_queue(indices.graphics, 0)
-      };
+    let device = unsafe {
+      instance.create_device(physical_device, &device_info, None)
+    }?;
 
-      let presentation_queue = unsafe {
-        device.get_device_queue(indices.presentation, 0)
-      };
+    //   So, this is a little confusing. Queues are found in queue families.
+    // The family has an index within the device, and the queue has an index
+    // within the family. We computed the family index above, and when we
+    // created the device we told it to create just a single queue in that
+    // family. Now we pass both indices to find the actual queue object.
+    let graphics_queue = unsafe {
+      device.get_device_queue(indices.graphics, 0)
+    };
 
-      self.device.set(device).unwrap();
-      self.graphics_queue.set(graphics_queue).unwrap();
-      self.presentation_queue.set(presentation_queue).unwrap();
-    }
+    let presentation_queue = unsafe {
+      device.get_device_queue(indices.presentation, 0)
+    };
 
-    Ok(())
+    Ok(DeviceCreation {
+      physical_device,
+      device,
+      indices,
+      graphics_queue,
+      presentation_queue,
+      enable_swapchain
+    })
   }
 
   #[allow(unsafe_code)]
-  fn init_vulkan_swapchain(&mut self) -> Result<()> {
-    // Here, too, we need to clone the smart pointer to simplify ownership.
-    let physical_device = self.physical_device.get().unwrap().clone();
+  fn init_swapchain(window: &Window, instance: &Instance,
+                    surface: &vk::SurfaceKHR,
+                    physical_device: &vk::PhysicalDevice, device: &Device,
+                    indices: &QueueFamilyIndices)
+      -> Result<Swapchain>
+  {
+    let features = Self::find_device_swapchain_features(
+            instance, surface, physical_device)?.require()?;
 
-    if let Acceptable::Accepted(features)
-           = self.find_device_swapchain_features(&physical_device)?
-    {
-      let physical_device = self.physical_device.get().unwrap().clone();
-      let device = self.device.get().unwrap().clone();
-      let surface = self.surface.get().unwrap().clone();
+    let format = Self::pick_surface_format(&features.formats)?;
 
-      let format = self.pick_surface_format(&features.formats)?;
+    let presentation_mode
+            = Self::pick_presentation_mode(&features.presentation_modes)?;
+    let extent = Self::pick_image_extent(window, features.capabilities)?;
 
-      let presentation_mode
-              = self.pick_presentation_mode(&features.presentation_modes)?;
-      let extent = self.pick_image_extent(features.capabilities)?;
+    let mut image_count = features.capabilities.min_image_count + 1;
+    if features.capabilities.max_image_count != 0 {
+      image_count
+          = image_count.clamp(0, features.capabilities.max_image_count);
+    }
 
-      let mut image_count = features.capabilities.min_image_count + 1;
-      if features.capabilities.max_image_count != 0 {
-        image_count
-            = image_count.clamp(0, features.capabilities.max_image_count);
-      }
+    let mut unique_queue_family_indices = BTreeSet::new();
+    unique_queue_family_indices.insert(indices.graphics);
+    unique_queue_family_indices.insert(indices.presentation);
 
-      //   We call this yet again. It needs to return the same thing here
-      // that it did before; fortunately it's simple enough that that's a safe
-      // assumption.
-      let indices = self.find_device_queue_family_indices(&physical_device)?
-                        .unwrap();
-
-      let mut unique_queue_family_indices = BTreeSet::new();
-      unique_queue_family_indices.insert(indices.graphics);
-      unique_queue_family_indices.insert(indices.presentation);
-
-      //   If there's only one queue, we use exclusive sharing mode, which
-      // will allow things to work without locks. Otherwise we use concurrent
-      // mode.
-      let (ordered_indices, sharing_mode)
-              = if unique_queue_family_indices.len() < 2
-      {
-        (vec![indices.graphics], vk::SharingMode::EXCLUSIVE)
-      } else {
-        (vec![indices.graphics, indices.presentation],
-         vk::SharingMode::CONCURRENT)
-      };
+    //   If there's only one queue, we use exclusive sharing mode, which
+    // will allow things to work without locks. Otherwise we use concurrent
+    // mode.
+    let (ordered_indices, sharing_mode)
+            = if unique_queue_family_indices.len() < 2
+    {
+      (vec![indices.graphics], vk::SharingMode::EXCLUSIVE)
+    } else {
+      (vec![indices.graphics, indices.presentation],
+       vk::SharingMode::CONCURRENT)
+    };
 
-      let swapchain_info = vk::SwapchainCreateInfoKHR::builder()
-              .surface(surface)
-              .min_image_count(image_count)
-              .image_format(format.format)
-              .image_color_space(format.color_space)
-              .image_extent(extent)
-              .image_array_layers(1)
-              .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
-              .image_sharing_mode(sharing_mode)
-              .queue_family_indices(&ordered_indices)
-              .pre_transform(features.capabilities.current_transform)
-              .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
-              .present_mode(presentation_mode)
-              .clipped(true)
-              .old_swapchain(vk::SwapchainKHR::null());
-
-      let swapchain = unsafe {
-        device.create_swapchain_khr(&swapchain_info, None)
-      }?;
+    let swapchain_info = vk::SwapchainCreateInfoKHR::builder()
+            .surface(*surface)
+            .min_image_count(image_count)
+            .image_format(format.format)
+            .image_color_space(format.color_space)
+            .image_extent(extent)
+            .image_array_layers(1)
+            .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
+            .image_sharing_mode(sharing_mode)
+            .queue_family_indices(&ordered_indices)
+            .pre_transform(features.capabilities.current_transform)
+            .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
+            .present_mode(presentation_mode)
+            .clipped(true)
+            .old_swapchain(vk::SwapchainKHR::null());
+
+    let swapchain = unsafe {
+      device.create_swapchain_khr(&swapchain_info, None)
+    }?;
 
-      let images = unsafe {
-        device.get_swapchain_images_khr(swapchain)
-      }?;
+    let images = unsafe {
+      device.get_swapchain_images_khr(swapchain)
+    }?;
 
-      let mut image_views = Vec::new();
-      for image in &images {
-        let components = vk::ComponentMapping::builder()
-                             .r(vk::ComponentSwizzle::IDENTITY)
-                             .g(vk::ComponentSwizzle::IDENTITY)
-                             .b(vk::ComponentSwizzle::IDENTITY)
-                             .a(vk::ComponentSwizzle::IDENTITY);
-
-        let subresource_range = vk::ImageSubresourceRange::builder()
-                                    .aspect_mask(vk::ImageAspectFlags::COLOR)
-                                    .base_mip_level(0)
-                                    .level_count(1)
-                                    .base_array_layer(0)
-                                    .layer_count(1);
-
-        let view_info = vk::ImageViewCreateInfo::builder()
-                            .image(*image)
-                            .view_type(vk::ImageViewType::_2D)
-                            .format(format.format)
-                            .components(components)
-                            .subresource_range(subresource_range);
-
-        let view = unsafe {
-          device.create_image_view(&view_info, None)
-        }?;
-
-        image_views.push(view);
-      }
+    let mut image_views = Vec::new();
+    for image in &images {
+      let components = vk::ComponentMapping::builder()
+                           .r(vk::ComponentSwizzle::IDENTITY)
+                           .g(vk::ComponentSwizzle::IDENTITY)
+                           .b(vk::ComponentSwizzle::IDENTITY)
+                           .a(vk::ComponentSwizzle::IDENTITY);
+
+      let subresource_range = vk::ImageSubresourceRange::builder()
+                                  .aspect_mask(vk::ImageAspectFlags::COLOR)
+                                  .base_mip_level(0)
+                                  .level_count(1)
+                                  .base_array_layer(0)
+                                  .layer_count(1);
+
+      let view_info = vk::ImageViewCreateInfo::builder()
+                          .image(*image)
+                          .view_type(vk::ImageViewType::_2D)
+                          .format(format.format)
+                          .components(components)
+                          .subresource_range(subresource_range);
+
+      let view = unsafe {
+        device.create_image_view(&view_info, None)
+      }?;
 
-      self.swapchain.set(swapchain).unwrap();
-      self.swapchain_images.set(images).unwrap();
-      self.swapchain_image_views.set(image_views).unwrap();
-      self.format.set(format.format).unwrap();
-      self.extent.set(extent).unwrap();
+      image_views.push(view);
     }
 
-    Ok(())
+    Ok(Swapchain {
+      swapchain, images, image_views,
+      format: format.format,
+      extent
+    })
   }
 
   #[allow(unsafe_code)]
-  fn init_render_pass(&mut self) -> Result<()> {
-    if self.render_pass.get().is_none() {
-      let device = self.device.get().unwrap();
-      let format = self.format.get().unwrap();
-
-      let color_attachment
-              = vk::AttachmentDescription::builder()
-                    .format(*format)
-                    .samples(vk::SampleCountFlags::_1)
-                    .load_op(vk::AttachmentLoadOp::CLEAR)
-                    .store_op(vk::AttachmentStoreOp::STORE)
-                    .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
-                    .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
-                    .initial_layout(vk::ImageLayout::UNDEFINED)
-                    .final_layout(vk::ImageLayout::PRESENT_SRC_KHR);
-
-      let color_attachment_reference
-              = vk::AttachmentReference::builder()
-                    .attachment(0)
-                    .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
-
-      let subpass_attachments = [color_attachment_reference];
-      let subpass = vk::SubpassDescription::builder()
-                        .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
-                        .color_attachments(&subpass_attachments);
-
-      let dependency
-            = vk::SubpassDependency::builder()
-                  .src_subpass(vk::SUBPASS_EXTERNAL)
-                  .src_stage_mask(
-                       vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT)
-                  .src_access_mask(vk::AccessFlags::empty())
-                  .dst_subpass(0)
-                  .dst_stage_mask(
-                       vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT)
-                  .dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE);
-
-      let render_attachments = [color_attachment];
-      let subpasses = [subpass];
-      let dependencies = [dependency];
-      let render_pass_info = vk::RenderPassCreateInfo::builder()
-                                 .attachments(&render_attachments)
-                                 .subpasses(&subpasses)
-                                 .dependencies(&dependencies);
-
-      let render_pass = unsafe {
-        device.create_render_pass(&render_pass_info, None)
-      }?;
-
-      self.render_pass.set(render_pass).unwrap();
-    }
+  fn init_render_pass(device: &Device, format: &vk::Format)
+      -> Result<vk::RenderPass>
+  {
+    let color_attachment
+            = vk::AttachmentDescription::builder()
+                  .format(*format)
+                  .samples(vk::SampleCountFlags::_1)
+                  .load_op(vk::AttachmentLoadOp::CLEAR)
+                  .store_op(vk::AttachmentStoreOp::STORE)
+                  .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
+                  .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
+                  .initial_layout(vk::ImageLayout::UNDEFINED)
+                  .final_layout(vk::ImageLayout::PRESENT_SRC_KHR);
+
+    let color_attachment_reference
+            = vk::AttachmentReference::builder()
+                  .attachment(0)
+                  .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
+
+    let subpass_attachments = [color_attachment_reference];
+    let subpass = vk::SubpassDescription::builder()
+                      .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
+                      .color_attachments(&subpass_attachments);
+
+    let dependency
+          = vk::SubpassDependency::builder()
+                .src_subpass(vk::SUBPASS_EXTERNAL)
+                .src_stage_mask(
+                     vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT)
+                .src_access_mask(vk::AccessFlags::empty())
+                .dst_subpass(0)
+                .dst_stage_mask(
+                     vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT)
+                .dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE);
+
+    let render_attachments = [color_attachment];
+    let subpasses = [subpass];
+    let dependencies = [dependency];
+    let render_pass_info = vk::RenderPassCreateInfo::builder()
+                               .attachments(&render_attachments)
+                               .subpasses(&subpasses)
+                               .dependencies(&dependencies);
+
+    let render_pass = unsafe {
+      device.create_render_pass(&render_pass_info, None)
+    }?;
 
-    Ok(())
+    Ok(render_pass)
   }
 
   #[allow(unsafe_code)]
-  fn init_pipeline(&mut self) -> Result<()> {
-    if self.pipeline.get().is_none() {
-      let device = self.device.get().unwrap().clone();
-      let extent = self.extent.get().unwrap().clone();
-      let render_pass = self.render_pass.get().unwrap().clone();
-
-      let vertex_binary = include_bytes!(
-              concat!(env!("OUT_DIR"), "/shader.vert.spv"));
-      let fragment_binary = include_bytes!(
-              concat!(env!("OUT_DIR"), "/shader.frag.spv"));
-
-      let vertex_module = self.load_spirv_shader_module(vertex_binary)?;
-      let fragment_module = self.load_spirv_shader_module(fragment_binary)?;
-
-      let vertex_stage_info = vk::PipelineShaderStageCreateInfo::builder()
-                                  .stage(vk::ShaderStageFlags::VERTEX)
-                                  .module(vertex_module)
+  fn init_pipeline(device: &Device, extent: &vk::Extent2D,
+                   render_pass: &vk::RenderPass)
+      -> Result<(vk::PipelineLayout, vk::Pipeline)>
+  {
+    let vertex_binary = include_bytes!(
+            concat!(env!("OUT_DIR"), "/shader.vert.spv"));
+    let fragment_binary = include_bytes!(
+            concat!(env!("OUT_DIR"), "/shader.frag.spv"));
+
+    let vertex_module
+            = Self::load_spirv_shader_module(device, vertex_binary)?;
+    let fragment_module
+            = Self::load_spirv_shader_module(device, fragment_binary)?;
+
+    let vertex_stage_info = vk::PipelineShaderStageCreateInfo::builder()
+                                .stage(vk::ShaderStageFlags::VERTEX)
+                                .module(vertex_module)
+                                .name(b"main\0");
+
+    let fragment_stage_info = vk::PipelineShaderStageCreateInfo::builder()
+                                  .stage(vk::ShaderStageFlags::FRAGMENT)
+                                  .module(fragment_module)
                                   .name(b"main\0");
 
-      let fragment_stage_info = vk::PipelineShaderStageCreateInfo::builder()
-                                    .stage(vk::ShaderStageFlags::FRAGMENT)
-                                    .module(fragment_module)
-                                    .name(b"main\0");
-
-      let vertex_input_state_info
-              = vk::PipelineVertexInputStateCreateInfo::builder();
-
-      let input_assembly_state_info
-              = vk::PipelineInputAssemblyStateCreateInfo::builder()
-                    .topology(vk::PrimitiveTopology::TRIANGLE_LIST)
-                    .primitive_restart_enable(false);
-
-      let viewport = vk::Viewport::builder()
-                         .x(0.0)
-                         .y(0.0)
-                         .width(extent.width as f32)
-                         .height(extent.height as f32)
-                         .min_depth(0.0)
-                         .max_depth(1.0);
-      let viewports = [viewport];
-
-      let scissor = vk::Rect2D::builder()
-                         .offset(vk::Offset2D { x: 0, y: 0 })
-                         .extent(extent);
-      let scissor_list = [scissor];
-
-      let viewport_state_info = vk::PipelineViewportStateCreateInfo::builder()
-                         .viewports(&viewports)
-                         .scissors(&scissor_list);
-
-      let rasterizer_state_info
-              = vk::PipelineRasterizationStateCreateInfo::builder()
-                    .depth_clamp_enable(false)
-                    .rasterizer_discard_enable(false)
-                    .polygon_mode(vk::PolygonMode::FILL)
-                    .line_width(1.0)
-                    .cull_mode(vk::CullModeFlags::BACK)
-                    .front_face(vk::FrontFace::CLOCKWISE)
-                    .depth_bias_enable(false);
-
-      let multisample_state_info
-              = vk::PipelineMultisampleStateCreateInfo::builder()
-                    .sample_shading_enable(false)
-                    .rasterization_samples(vk::SampleCountFlags::_1);
-
-      let blend_attachment_info
-              = vk::PipelineColorBlendAttachmentState::builder()
-                    .color_write_mask(vk::ColorComponentFlags::all())
-                    .blend_enable(false)
-                    .src_color_blend_factor(vk::BlendFactor::ONE)
-                    .dst_color_blend_factor(vk::BlendFactor::ZERO)
-                    .color_blend_op(vk::BlendOp::ADD)
-                    .src_alpha_blend_factor(vk::BlendFactor::ONE)
-                    .dst_alpha_blend_factor(vk::BlendFactor::ZERO)
-                    .alpha_blend_op(vk::BlendOp::ADD);
-      let blend_attachments = [blend_attachment_info];
-
-      let blend_info = vk::PipelineColorBlendStateCreateInfo::builder()
-                           .logic_op_enable(false)
-                           .logic_op(vk::LogicOp::COPY)
-                           .attachments(&blend_attachments)
-                           .blend_constants([0.0, 0.0, 0.0, 0.0]);
-
-      let pipeline_layout_info = vk::PipelineLayoutCreateInfo::builder();
-
-      let pipeline_layout = unsafe {
-        device.create_pipeline_layout(&pipeline_layout_info, None)
-      }?;
-
-      let stages = [vertex_stage_info, fragment_stage_info];
-      let pipeline_info
-              = vk::GraphicsPipelineCreateInfo::builder()
-                    .stages(&stages)
-                    .vertex_input_state(&vertex_input_state_info)
-                    .input_assembly_state(&input_assembly_state_info)
-                    .viewport_state(&viewport_state_info)
-                    .rasterization_state(&rasterizer_state_info)
-                    .multisample_state(&multisample_state_info)
-                    .color_blend_state(&blend_info)
-                    .layout(pipeline_layout)
-                    .render_pass(render_pass)
-                    .subpass(0);
-
-      let pipeline = unsafe {
-        device.create_graphics_pipelines(vk::PipelineCache::null(),
-                                         &[pipeline_info], None)
-      }?.0[0];
-
-      self.pipeline_layout.set(pipeline_layout).unwrap();
-      self.pipeline.set(pipeline).unwrap();
+    let vertex_input_state_info
+            = vk::PipelineVertexInputStateCreateInfo::builder();
+
+    let input_assembly_state_info
+            = vk::PipelineInputAssemblyStateCreateInfo::builder()
+                  .topology(vk::PrimitiveTopology::TRIANGLE_LIST)
+                  .primitive_restart_enable(false);
+
+    let viewport = vk::Viewport::builder()
+                       .x(0.0)
+                       .y(0.0)
+                       .width(extent.width as f32)
+                       .height(extent.height as f32)
+                       .min_depth(0.0)
+                       .max_depth(1.0);
+    let viewports = [viewport];
+
+    let scissor = vk::Rect2D::builder()
+                       .offset(vk::Offset2D { x: 0, y: 0 })
+                       .extent(*extent);
+    let scissor_list = [scissor];
+
+    let viewport_state_info = vk::PipelineViewportStateCreateInfo::builder()
+                       .viewports(&viewports)
+                       .scissors(&scissor_list);
+
+    let rasterizer_state_info
+            = vk::PipelineRasterizationStateCreateInfo::builder()
+                  .depth_clamp_enable(false)
+                  .rasterizer_discard_enable(false)
+                  .polygon_mode(vk::PolygonMode::FILL)
+                  .line_width(1.0)
+                  .cull_mode(vk::CullModeFlags::BACK)
+                  .front_face(vk::FrontFace::CLOCKWISE)
+                  .depth_bias_enable(false);
+
+    let multisample_state_info
+            = vk::PipelineMultisampleStateCreateInfo::builder()
+                  .sample_shading_enable(false)
+                  .rasterization_samples(vk::SampleCountFlags::_1);
+
+    let blend_attachment_info
+            = vk::PipelineColorBlendAttachmentState::builder()
+                  .color_write_mask(vk::ColorComponentFlags::all())
+                  .blend_enable(false)
+                  .src_color_blend_factor(vk::BlendFactor::ONE)
+                  .dst_color_blend_factor(vk::BlendFactor::ZERO)
+                  .color_blend_op(vk::BlendOp::ADD)
+                  .src_alpha_blend_factor(vk::BlendFactor::ONE)
+                  .dst_alpha_blend_factor(vk::BlendFactor::ZERO)
+                  .alpha_blend_op(vk::BlendOp::ADD);
+    let blend_attachments = [blend_attachment_info];
+
+    let blend_info = vk::PipelineColorBlendStateCreateInfo::builder()
+                         .logic_op_enable(false)
+                         .logic_op(vk::LogicOp::COPY)
+                         .attachments(&blend_attachments)
+                         .blend_constants([0.0, 0.0, 0.0, 0.0]);
+
+    let pipeline_layout_info = vk::PipelineLayoutCreateInfo::builder();
+
+    let pipeline_layout = unsafe {
+      device.create_pipeline_layout(&pipeline_layout_info, None)
+    }?;
 
-      unsafe {
-        device.destroy_shader_module(vertex_module, None);
-        device.destroy_shader_module(fragment_module, None);
-      };
-    }
+    let stages = [vertex_stage_info, fragment_stage_info];
+    let pipeline_info
+            = vk::GraphicsPipelineCreateInfo::builder()
+                  .stages(&stages)
+                  .vertex_input_state(&vertex_input_state_info)
+                  .input_assembly_state(&input_assembly_state_info)
+                  .viewport_state(&viewport_state_info)
+                  .rasterization_state(&rasterizer_state_info)
+                  .multisample_state(&multisample_state_info)
+                  .color_blend_state(&blend_info)
+                  .layout(pipeline_layout)
+                  .render_pass(*render_pass)
+                  .subpass(0);
+
+    let pipeline = unsafe {
+      device.create_graphics_pipelines(vk::PipelineCache::null(),
+                                       &[pipeline_info], None)
+    }?.0[0];
+
+    unsafe {
+      device.destroy_shader_module(vertex_module, None);
+      device.destroy_shader_module(fragment_module, None);
+    };
 
-    Ok(())
+    Ok((pipeline_layout, pipeline))
   }
 
   #[allow(unsafe_code)]
-  fn init_framebuffers(&mut self) -> Result<()> {
-    if self.framebuffers.get().is_none() {
-      let device = self.device.get().unwrap().clone();
-      let extent = self.extent.get().unwrap().clone();
-      let image_views = self.swapchain_image_views.get().unwrap();
-      let render_pass = self.render_pass.get().unwrap();
-
-      let mut framebuffers = Vec::new();
-
-      for image_view in image_views {
-        let attachments = [*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)
-        }?;
-
-        framebuffers.push(framebuffer);
-      }
+  fn init_framebuffers(device: &Device, extent: &vk::Extent2D,
+                       swapchain_image_views: &Vec<vk::ImageView>,
+                       render_pass: &vk::RenderPass)
+      -> Result<Vec<vk::Framebuffer>>
+  {
+    let mut framebuffers = Vec::new();
 
-      self.framebuffers.set(framebuffers).unwrap();
-    }
+    for image_view in swapchain_image_views {
+      let attachments = [*image_view];
 
-    Ok(())
-  }
+      let framebuffer_info = vk::FramebufferCreateInfo::builder()
+                                 .render_pass(*render_pass)
+                                 .attachments(&attachments)
+                                 .width(extent.width)
+                                 .height(extent.height)
+                                 .layers(1);
 
-  #[allow(unsafe_code)]
-  fn init_commands(&mut self) -> Result<()> {
-    if self.command_pool.get().is_none() {
-      let physical_device = self.physical_device.get().unwrap().clone();
-      let device = self.device.get().unwrap().clone();
+      let framebuffer = unsafe {
+        device.create_framebuffer(&framebuffer_info, None)
+      }?;
 
-      // We call this one last time. It's kind of a problem.
-      let indices = self.find_device_queue_family_indices(&physical_device)?
-                        .unwrap();
+      framebuffers.push(framebuffer);
+    }
 
-      let command_pool_info = vk::CommandPoolCreateInfo::builder()
-                                  .flags(vk::CommandPoolCreateFlags::empty())
-                                  .queue_family_index(indices.graphics);
+    Ok(framebuffers)
+  }
 
-      let command_pool = unsafe {
-        device.create_command_pool(&command_pool_info, None)
-      }?;
+  #[allow(unsafe_code)]
+  fn init_commands(device: &Device,
+                   extent: &vk::Extent2D,
+                   framebuffers: &Vec<vk::Framebuffer>,
+                   render_pass: &vk::RenderPass,
+                   pipeline: &vk::Pipeline,
+                   indices: &QueueFamilyIndices)
+      -> Result<(vk::CommandPool, Vec<vk::CommandBuffer>)>
+  {
+    // We call this one last time. It's kind of a problem.
 
-      self.command_pool.set(command_pool).unwrap();
-    }
+    let command_pool_info = vk::CommandPoolCreateInfo::builder()
+                                .flags(vk::CommandPoolCreateFlags::empty())
+                                .queue_family_index(indices.graphics);
 
-    if self.command_buffers.get().is_none() {
-      let device = self.device.get().unwrap();
-      let extent = self.extent.get().unwrap();
-      let framebuffers = self.framebuffers.get().unwrap();
-      let render_pass = self.render_pass.get().unwrap();
-      let pipeline = self.pipeline.get().unwrap();
-      let command_pool = self.command_pool.get().unwrap();
-
-      let command_buffer_allocation_info
-              = vk::CommandBufferAllocateInfo::builder()
-                    .command_pool(*command_pool)
-                    .level(vk::CommandBufferLevel::PRIMARY)
-                    .command_buffer_count(framebuffers.len() as u32);
-      let command_buffers = unsafe {
-        device.allocate_command_buffers(&command_buffer_allocation_info)
-      }?;
+    let command_pool = unsafe {
+      device.create_command_pool(&command_pool_info, None)
+    }?;
 
-      for (index, framebuffer) in framebuffers.iter().enumerate() {
-        let command_buffer = command_buffers[index];
+    let command_buffer_allocation_info
+            = vk::CommandBufferAllocateInfo::builder()
+                  .command_pool(command_pool)
+                  .level(vk::CommandBufferLevel::PRIMARY)
+                  .command_buffer_count(framebuffers.len() as u32);
+    let command_buffers = unsafe {
+      device.allocate_command_buffers(&command_buffer_allocation_info)
+    }?;
 
-        let inheritance_info = vk::CommandBufferInheritanceInfo::builder();
+    for (index, framebuffer) in framebuffers.iter().enumerate() {
+      let command_buffer = command_buffers[index];
 
-        let command_buffer_begin_info
-                = vk::CommandBufferBeginInfo::builder()
-                      .flags(vk::CommandBufferUsageFlags::empty())
-                      .inheritance_info(&inheritance_info);
+      let inheritance_info = vk::CommandBufferInheritanceInfo::builder();
 
-        unsafe {
-          device.begin_command_buffer(command_buffer,
-                                      &command_buffer_begin_info)
-        }?;
+      let command_buffer_begin_info
+              = vk::CommandBufferBeginInfo::builder()
+                    .flags(vk::CommandBufferUsageFlags::empty())
+                    .inheritance_info(&inheritance_info);
 
-        let render_area = vk::Rect2D::builder()
-                              .offset(vk::Offset2D::default())
-                              .extent(*extent);
+      unsafe {
+        device.begin_command_buffer(command_buffer,
+                                    &command_buffer_begin_info)
+      }?;
 
-        let clear_value = vk::ClearValue {
-          color: vk::ClearColorValue {
-            float32: [0.0, 0.0, 0.0, 1.0]
-          }
-        };
-        let clear_values = [clear_value];
+      let render_area = vk::Rect2D::builder()
+                            .offset(vk::Offset2D::default())
+                            .extent(*extent);
 
-        let begin_pass_info = vk::RenderPassBeginInfo::builder()
-                                  .render_pass(*render_pass)
-                                  .framebuffer(*framebuffer)
-                                  .render_area(render_area)
-                                  .clear_values(&clear_values);
+      let clear_value = vk::ClearValue {
+        color: vk::ClearColorValue {
+          float32: [0.0, 0.0, 0.0, 1.0]
+        }
+      };
+      let clear_values = [clear_value];
 
-        unsafe {
-          device.cmd_begin_render_pass(command_buffer, &begin_pass_info,
-                                       vk::SubpassContents::INLINE)
-        };
+      let begin_pass_info = vk::RenderPassBeginInfo::builder()
+                                .render_pass(*render_pass)
+                                .framebuffer(*framebuffer)
+                                .render_area(render_area)
+                                .clear_values(&clear_values);
 
-        unsafe {
-          device.cmd_bind_pipeline(command_buffer,
-                                   vk::PipelineBindPoint::GRAPHICS,
-                                   *pipeline)
-        };
+      unsafe {
+        device.cmd_begin_render_pass(command_buffer, &begin_pass_info,
+                                     vk::SubpassContents::INLINE)
+      };
 
-        unsafe { device.cmd_draw(command_buffer, 3, 1, 0, 0) };
+      unsafe {
+        device.cmd_bind_pipeline(command_buffer,
+                                 vk::PipelineBindPoint::GRAPHICS,
+                                 *pipeline)
+      };
 
-        unsafe { device.cmd_end_render_pass(command_buffer) };
+      unsafe { device.cmd_draw(command_buffer, 3, 1, 0, 0) };
 
-        unsafe { device.end_command_buffer(command_buffer) }?;
-      }
+      unsafe { device.cmd_end_render_pass(command_buffer) };
 
-      self.command_buffers.set(command_buffers).unwrap();
+      unsafe { device.end_command_buffer(command_buffer) }?;
     }
 
-    Ok(())
+    Ok((command_pool, command_buffers))
   }
 
   #[allow(unsafe_code)]
-  fn init_concurrency(&mut self) -> Result<()> {
-    let device = self.device.get().unwrap();
-    let swapchain_images = self.swapchain_images.get().unwrap();
+  fn init_concurrency(device: &Device,
+                      swapchain_images: &Vec<vk::Image>)
+      -> Result<Concurrency>
+  {
     let semaphore_info = vk::SemaphoreCreateInfo::builder();
     let fence_info = vk::FenceCreateInfo::builder()
                          .flags(vk::FenceCreateFlags::SIGNALED);
@@ -1023,7 +1007,6 @@ impl Surreality {
     let mut image_available_semaphores = Vec::new();
     let mut rendering_finished_semaphores = Vec::new();
     let mut frame_fences = Vec::new();
-
     for _ in 0 .. N_SIMULTANEOUS_FRAMES {
       image_available_semaphores.push(unsafe {
         device.create_semaphore(&semaphore_info, None)
@@ -1038,17 +1021,17 @@ impl Surreality {
       }?);
     }
 
-    self.image_available_semaphores
-        .set(image_available_semaphores).unwrap();
-    self.rendering_finished_semaphores
-        .set(rendering_finished_semaphores).unwrap();
-    self.frame_fences.set(frame_fences).unwrap();
-
+    let mut image_fences = Vec::new();
     for _ in 0 .. swapchain_images.len() {
-      self.image_fences.push(vk::Fence::null());
+      image_fences.push(vk::Fence::null());
     }
 
-    Ok(())
+    Ok(Concurrency {
+      image_available_semaphores,
+      rendering_finished_semaphores,
+      frame_fences,
+      image_fences: RefCell::new(image_fences),
+    })
   }
 
   //   To Vulkan, a "physical" device is the actual GPU, and a "logical"
@@ -1056,15 +1039,15 @@ impl Surreality {
   // Before we can create a logical device, we must choose which physical
   // device to connect it to.
   #[allow(unsafe_code)]
-  fn pick_vulkan_device(&mut self) -> Result<vk::PhysicalDevice> {
+  fn pick_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR)
+      -> Result<vk::PhysicalDevice>
+  {
     let mut best_device = None;
     let mut best_score = None;
     let mut rejected = BTreeMap::new();
 
-    for device in unsafe {
-      self.instance.get().unwrap().enumerate_physical_devices()
-    }? {
-      match self.score_vulkan_device(&device)? {
+    for device in unsafe { instance.enumerate_physical_devices() }? {
+      match Self::score_vulkan_device(instance, surface, &device)? {
         Acceptable::Accepted(new_score) => {
           if let Some(old_score) = best_score {
             if new_score > old_score {
@@ -1078,8 +1061,7 @@ impl Surreality {
         }
         Acceptable::Rejected(reason) => {
           let properties = unsafe {
-            self.instance.get().unwrap()
-                .get_physical_device_properties(device)
+            instance.get_physical_device_properties(device)
           };
 
           let name = properties.device_name.to_string_lossy().into_owned();
@@ -1114,7 +1096,8 @@ impl Surreality {
   // the outer Result is whether we successfully evaluated the device, and the
   // inner Acceptable is whether we approve of it.
   #[allow(unsafe_code)]
-  fn score_vulkan_device(&mut self, device: &vk::PhysicalDevice)
+  fn score_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR,
+                         physical_device: &vk::PhysicalDevice)
       -> Result<Acceptable<u64>>
   {
     //   Not all devices support graphics, and not all devices support
@@ -1122,17 +1105,16 @@ impl Surreality {
     // by looking up the indices of the queue families we would use, though
     // we ignore the actual values and recompute them later.
     if let Acceptable::Rejected(rationale)
-           = self.find_device_queue_family_indices(device)?
+           = Self::find_device_queue_family_indices(
+                 instance, surface, physical_device)?
     {
       return Ok(Acceptable::Rejected(rationale));
     }
 
-    let instance = self.instance.get().unwrap();
-
     //   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(*device)
+      instance.get_physical_device_properties(*physical_device)
     };
 
     let mut score = 0;
@@ -1158,7 +1140,7 @@ impl Surreality {
     // supports, so we enumerate those.
     let mut available_extensions = HashSet::new();
     for extension in unsafe {
-      instance.enumerate_device_extension_properties(*device, None)
+      instance.enumerate_device_extension_properties(*physical_device, None)
     }? {
       available_extensions.insert(extension.extension_name);
     }
@@ -1171,8 +1153,8 @@ impl Surreality {
       //
       //   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(device)?
+      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.
@@ -1187,14 +1169,12 @@ impl Surreality {
     Ok(Acceptable::Accepted(score))
   }
 
-  // TODO: save the result of this somewhere and only call it once
   #[allow(unsafe_code)]
-  fn find_device_queue_family_indices(&mut self, device: &vk::PhysicalDevice)
+  fn find_device_queue_family_indices(instance: &Instance,
+                                      surface: &vk::SurfaceKHR,
+                                      device: &vk::PhysicalDevice)
       -> Result<Acceptable<QueueFamilyIndices>>
   {
-    let instance = self.instance.get().unwrap();
-    let surface = self.surface.get().unwrap();
-
     //   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.
@@ -1235,23 +1215,22 @@ impl Surreality {
   //   We expect our caller to have already verified that the device supports
   // the swapchain extension.
   #[allow(unsafe_code)]
-  fn find_device_swapchain_features(&mut self, device: &vk::PhysicalDevice)
+  fn find_device_swapchain_features(instance: &Instance,
+                                    surface: &vk::SurfaceKHR,
+                                    physical_device: &vk::PhysicalDevice)
       -> Result<Acceptable<SwapchainFeatures>>
   {
-    let instance = self.instance.get().unwrap();
-    let surface = self.surface.get().unwrap();
-
     let capabilities = unsafe {
       instance.get_physical_device_surface_capabilities_khr(
-          *device, *surface)
+          *physical_device, *surface)
     }?;
     let formats = unsafe {
       instance.get_physical_device_surface_formats_khr(
-          *device, *surface)
+          *physical_device, *surface)
     }?;
     let presentation_modes = unsafe {
       instance.get_physical_device_surface_present_modes_khr(
-          *device, *surface)
+          *physical_device, *surface)
     }?;
 
     if formats.is_empty() {
@@ -1265,8 +1244,7 @@ impl Surreality {
     }
   }
 
-  fn pick_surface_format(&mut self,
-                         available_formats: &Vec<vk::SurfaceFormatKHR>)
+  fn pick_surface_format(available_formats: &Vec<vk::SurfaceFormatKHR>)
       -> Result<vk::SurfaceFormatKHR>
   {
     for format in available_formats {
@@ -1280,15 +1258,15 @@ impl Surreality {
     return Ok(available_formats[0].clone());
   }
 
-  fn pick_presentation_mode(&mut self,
-                            _available_modes: &Vec<vk::PresentModeKHR>)
+  fn pick_presentation_mode(_available_modes: &Vec<vk::PresentModeKHR>)
       -> Result<vk::PresentModeKHR>
   {
     // It's guaranteed to have this one.
     return Ok(vk::PresentModeKHR::FIFO);
   }
 
-  fn pick_image_extent(&mut self, capabilities: vk::SurfaceCapabilitiesKHR)
+  fn pick_image_extent(window: &Window,
+                       capabilities: vk::SurfaceCapabilitiesKHR)
       -> Result<vk::Extent2D>
   {
     if capabilities.current_extent.width != u32::MAX
@@ -1296,7 +1274,6 @@ impl Surreality {
     {
       Ok(capabilities.current_extent)
     } else {
-      let window = self.window.get().unwrap();
       let window_size = window.inner_size();
 
       let width = window_size.width
@@ -1311,11 +1288,9 @@ impl Surreality {
   }
 
   #[allow(unsafe_code)]
-  fn load_spirv_shader_module(&mut self, binary: &[u8])
+  fn load_spirv_shader_module(device: &Device, binary: &[u8])
       -> Result<vk::ShaderModule>
   {
-    let device = self.device.get().unwrap();
-
     let bytecode = Bytecode::new(binary)?;
 
     let module_info = vk::ShaderModuleCreateInfo::builder()
@@ -1331,42 +1306,51 @@ impl Surreality {
 
   #[allow(unsafe_code)]
   fn render(&mut self, window_id: WindowId) -> Result<()> {
-    if let Some(window) = self.window.get()
+    if let Some(window) = self.window.borrow().as_ref()
        && window_id == window.id()
     {
-      let device = self.device.get().unwrap();
-      let graphics_queue = self.graphics_queue.get().unwrap();
-      let presentation_queue = self.presentation_queue.get().unwrap();
-      let swapchain = self.swapchain.get().unwrap();
-      let command_buffers = self.command_buffers.get().unwrap();
+      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 swapchain = self.swapchain.borrow();
+      let swapchain = swapchain.as_ref().unwrap().swapchain;
+      let command_buffers = self.command_buffers.borrow();
       let frame_index = self.frame_index;
       let image_available_semaphore
-              = self.image_available_semaphores.get().unwrap()[frame_index];
+              = self.concurrency.borrow().as_ref().unwrap()
+                    .image_available_semaphores[frame_index];
       let rendering_finished_semaphore
-              = self.rendering_finished_semaphores.get()
-                    .unwrap()[frame_index];
-      let frame_fence = self.frame_fences.get().unwrap()[frame_index];
+              = self.concurrency.borrow().as_ref().unwrap()
+                    .rendering_finished_semaphores[frame_index];
+      let frame_fence = self.concurrency.borrow().as_ref().unwrap()
+                            .frame_fences[frame_index];
 
       unsafe { device.wait_for_fences(&[frame_fence], true, u64::MAX) }?;
 
       let image_index = unsafe {
-        device.acquire_next_image_khr(*swapchain, u64::MAX,
+        device.acquire_next_image_khr(swapchain, u64::MAX,
                                       image_available_semaphore,
                                       vk::Fence::null())
       }?.0 as usize;
 
-      let image_fence = self.image_fences[image_index];
+      let image_fence = self.concurrency.borrow().as_ref().unwrap()
+                            .image_fences.borrow()[image_index];
       if !image_fence.is_null() {
         unsafe { device.wait_for_fences(&[image_fence], true, u64::MAX) }?;
       }
 
-      self.image_fences[image_index] = frame_fence;
+      if let Some(concurrency) = self.concurrency.borrow().as_ref() {
+        concurrency.image_fences.borrow_mut()[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 = [command_buffers[image_index]];
+      let command_buffers = [command_buffers.as_ref().unwrap()[image_index]];
       let submit_info = vk::SubmitInfo::builder()
                             .wait_semaphores(&first_semaphores)
                             .wait_dst_stage_mask(&wait_stages)
@@ -1379,7 +1363,7 @@ impl Surreality {
                             frame_fence)
       }?;
 
-      let swapchains = [*swapchain];
+      let swapchains = [swapchain];
       let image_indices = [image_index as u32];
       let present_info = vk::PresentInfoKHR::builder()
                              .wait_semaphores(&second_semaphores)
@@ -1400,89 +1384,75 @@ impl Surreality {
 impl Drop for Surreality {
   #[allow(unsafe_code)]
   fn drop(&mut self) {
-    if let Some(device) = self.device.get() {
+    if let Some(device) = self.device.borrow().as_ref() {
       unsafe { device.device_wait_idle() }.unwrap();
     }
 
-    if let Some(image_available_semaphores)
-               = self.image_available_semaphores.get()
-       && let Some(device) = self.device.get()
+    if let Some(concurrency) = self.concurrency.replace(None)
+       && let Some(device) = self.device.borrow().as_ref()
     {
-      for semaphore in image_available_semaphores {
-        unsafe { device.destroy_semaphore(*semaphore, None) };
+      for semaphore in concurrency.image_available_semaphores {
+        unsafe { device.destroy_semaphore(semaphore, None) };
       }
-    }
 
-    if let Some(rendering_finished_semaphores)
-               = self.rendering_finished_semaphores.get()
-       && let Some(device) = self.device.get()
-    {
-      for semaphore in rendering_finished_semaphores {
-        unsafe { device.destroy_semaphore(*semaphore, None) };
+      for semaphore in concurrency.rendering_finished_semaphores {
+        unsafe { device.destroy_semaphore(semaphore, None) };
       }
-    }
 
-    if let Some(frame_fences) = self.frame_fences.get()
-       && let Some(device) = self.device.get()
-    {
-      for fence in frame_fences {
-        unsafe { device.destroy_fence(*fence, None) };
+      for fence in concurrency.frame_fences {
+        unsafe { device.destroy_fence(fence, None) };
       }
     }
 
-    if let Some(command_pool) = self.command_pool.get()
-       && let Some(device) = self.device.get()
+    if let Some(command_pool) = self.command_pool.replace(None)
+       && let Some(device) = self.device.borrow().as_ref()
     {
-      unsafe { device.destroy_command_pool(*command_pool, None) };
+      unsafe { device.destroy_command_pool(command_pool, None) };
     }
 
-    if let Some(framebuffers) = self.framebuffers.get()
-       && let Some(device) = self.device.get()
+    if let Some(framebuffers) = self.framebuffers.replace(None)
+       && let Some(device) = self.device.borrow().as_ref()
     {
       for framebuffer in framebuffers {
-        unsafe { device.destroy_framebuffer(*framebuffer, None) };
+        unsafe { device.destroy_framebuffer(framebuffer, None) };
       }
     }
 
-    if let Some(pipeline) = self.pipeline.get()
-       && let Some(device) = self.device.get()
+    if let Some(pipeline) = self.pipeline.replace(None)
+       && let Some(device) = self.device.borrow().as_ref()
     {
-      unsafe { device.destroy_pipeline(*pipeline, None) };
+      unsafe { device.destroy_pipeline(pipeline, None) };
     }
 
-    if let Some(render_pass) = self.render_pass.get()
-       && let Some(device) = self.device.get()
+    if let Some(render_pass) = self.render_pass.replace(None)
+       && let Some(device) = self.device.borrow().as_ref()
     {
-      unsafe { device.destroy_render_pass(*render_pass, None) };
+      unsafe { device.destroy_render_pass(render_pass, None) };
     }
 
-    if let Some(pipeline_layout) = self.pipeline_layout.get()
-       && let Some(device) = self.device.get()
+    if let Some(pipeline_layout) = self.pipeline_layout.replace(None)
+       && let Some(device) = self.device.borrow().as_ref()
     {
-      unsafe { device.destroy_pipeline_layout(*pipeline_layout, None) };
+      unsafe { device.destroy_pipeline_layout(pipeline_layout, None) };
     }
 
-    if let Some(image_views) = self.swapchain_image_views.get()
-       && let Some(device) = self.device.get()
+    if let Some(swapchain) = self.swapchain.replace(None)
+       && let Some(device) = self.device.borrow().as_ref()
     {
-      for view in image_views {
-        unsafe { device.destroy_image_view(*view, None) };
+      for view in swapchain.image_views {
+        unsafe { device.destroy_image_view(view, None) };
       }
-    }
 
-    if let Some(swapchain) = self.swapchain.get()
-       && let Some(device) = self.device.get()
-    {
-      unsafe { device.destroy_swapchain_khr(*swapchain, None) };
+      unsafe { device.destroy_swapchain_khr(swapchain.swapchain, None) };
     }
 
-    if let Some(surface) = self.surface.get()
-       && let Some(instance) = self.instance.get()
+    if let Some(surface) = self.surface.replace(None)
+       && let Some(instance) = self.instance.borrow().as_ref()
     {
-      unsafe { instance.destroy_surface_khr(*surface, None) };
+      unsafe { instance.destroy_surface_khr(surface, None) };
     }
 
-    if let Some(device) = self.device.get() {
+    if let Some(device) = self.device.replace(None) {
       unsafe { device.destroy_device(None) };
     }
 
@@ -1491,15 +1461,15 @@ impl Drop for Surreality {
     // 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.get()
-       && let Some(instance) = self.instance.get()
+    if let Some(debug_messager) = self.debug_messager.replace(None)
+       && let Some(instance) = self.instance.borrow().as_ref()
     {
       unsafe {
-        instance.destroy_debug_utils_messenger_ext(*debug_messager, None);
+        instance.destroy_debug_utils_messenger_ext(debug_messager, None);
       }
     }
 
-    if let Some(instance) = self.instance.get() {
+    if let Some(instance) = self.instance.replace(None) {
       unsafe { instance.destroy_instance(None) };
     }
   }