summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/graphics_permanent.rs958
-rw-r--r--src/graphics_window_dressing.rs838
2 files changed, 906 insertions, 890 deletions
diff --git a/src/graphics_permanent.rs b/src/graphics_permanent.rs
index 4df6069..d41bbfa 100644
--- a/src/graphics_permanent.rs
+++ b/src/graphics_permanent.rs
@@ -97,7 +97,7 @@ impl PermanentGraphicsState {
       -> Result<(Self, vk::PhysicalDevice, QueueFamilyIndices,
                  EnableSwapchain)>
   {
-    let window = Self::init_window(event_loop)?;
+    let window = init_window(event_loop)?;
 
     //   There are a few Vulkan features (in the informal sense of
     // "feature") that we want to be able to run both with and without.
@@ -108,7 +108,7 @@ impl PermanentGraphicsState {
     // phases; we don't keep them around after that.
     let (entry, instance, debug_messager,
          enable_portability, enable_validation)
-        = Self::init_vulkan(&window)?;
+        = init_vulkan(&window)?;
 
     //   Conveniently, Vulkanalia's "window" feature allows it to get the
     // platform-specific stuff directly out of winit for us. This wrapper does
@@ -125,8 +125,8 @@ impl PermanentGraphicsState {
     let (physical_device, device,
          indices, graphics_queue, presentation_queue,
          enable_swapchain)
-        = Self::init_vulkan_device(&instance, &surface,
-                                   enable_validation, enable_portability)?;
+        = init_vulkan_device(&instance, &surface,
+                             enable_validation, enable_portability)?;
 
     Ok((PermanentGraphicsState {
       window, entry, instance, debug_messager, surface, device,
@@ -154,541 +154,547 @@ impl PermanentGraphicsState {
     unsafe { self.instance.destroy_instance(None) };
   }
 
-  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(), below.
-    let window_attributes = WindowAttributes::default()
-            .with_title("Love, Curiosity, Justice")
-            .with_inner_size(LogicalSize::new(1024, 768));
+  //   We expect our caller to have already verified that the device supports
+  // the swapchain extension.
+  #[allow(unsafe_code)]
+  pub 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)
+    }?;
 
-    Ok(event_loop.create_window(window_attributes)?)
+    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 init_vulkan(window: &Window)
-      -> Result<(Entry, Instance, Option<vk::DebugUtilsMessengerEXT>,
-                 EnablePortability, EnableValidation)>
+  pub fn load_spirv_shader_module(device: &Device, binary: &[u8])
+      -> Result<vk::ShaderModule>
   {
-    let enable_validation = cfg!(feature = "vulkan-validation")
-                            || cfg!(debug_assertions);
-
-    //   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
-    // least, that's the theory, but also see flake.nix for all the
-    // FHS-centric assumptions it makes that we have to correct.
-    //
-    //   Anyway, Vulkanalia offers an integration with libloading, which is a
-    // crate that wraps POSIX dlopen(). We use that; it's enabled by
-    // Vulkanalia's "libloading" feature.
-    let loader = unsafe { LibloadingLoader::new(LIBRARY) }?;
-    let entry = unsafe { Entry::new(loader) }?;
-
-    //   Since there's a lot of factors going into our instance creation
-    // request, we'll build up the parameters mutably.
-    let mut flags = vk::InstanceCreateFlags::empty();
-    let mut extensions = Vec::new();
-    let mut layers = Vec::new();
-
-    //   Before we go any further, use Vulkan's introspection to list off
-    // what's available.
-    let mut available_extensions = HashSet::new();
-    for extension in
-            unsafe { entry.enumerate_instance_extension_properties(None) }?
-    {
-      available_extensions.insert(extension.extension_name);
-    }
-    let available_extensions = available_extensions;
+    let bytecode = Bytecode::new(binary)?;
 
-    let mut available_layers = HashSet::new();
-    for layer in unsafe { entry.enumerate_instance_layer_properties() }? {
-      available_layers.insert(layer.layer_name);
-    }
-    let available_layers = available_layers;
+    let module_info = vk::ShaderModuleCreateInfo::builder()
+                          .code(bytecode.code())
+                          .code_size(bytecode.code_size());
 
-    //   There are certain extensions which are required by the nature of our
-    // windowing system. Happily, vulanaklia knows how to deal with that based
-    // on the type of window we give it.
-    //
-    //   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(
-                         window)
-    {
-      extensions.push(extension.as_ptr());
-    }
+    let module = unsafe {
+      device.create_shader_module(&module_info, None)
+    }?;
 
-    //   Deal with Vulkan's thing about opting in to non-conforming
-    // implementations.
-    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(
-            vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION.name.as_ptr());
-        extensions.push(
-            vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr());
-        flags.insert(vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR);
-
-        EnablePortability(true)
-      } else {
-        EnablePortability(false)
-      }
-    } else {
-      EnablePortability(false)
-    };
+    Ok(module)
+  }
+}
 
-    // Request the LunarG validation layer, when appropriate.
-    let validation_layer_name = vk::ExtensionName::from_bytes(
-                                    b"VK_LAYER_KHRONOS_validation");
-    let enable_validation = if enable_validation {
-      if available_layers.contains(&validation_layer_name) {
-        layers.push(validation_layer_name.as_ptr());
 
-        EnableValidation(true)
-      } else {
-        eprintln!("Vulkan validation requested at build time, \
-                   but no validation layer available.");
+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(), below.
+  let window_attributes = WindowAttributes::default()
+          .with_title("Love, Curiosity, Justice")
+          .with_inner_size(LogicalSize::new(1024, 768));
+
+  Ok(event_loop.create_window(window_attributes)?)
+}
 
-        EnableValidation(false)
-      }
-    } else {
-      EnableValidation(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
-    // extension is in the list we ask for.
-    let debug_extension_name = vk::EXT_DEBUG_UTILS_EXTENSION.name;
-    if available_extensions.contains(&debug_extension_name) {
-      extensions.push(debug_extension_name.as_ptr());
+#[allow(unsafe_code)]
+fn init_vulkan(window: &Window)
+    -> Result<(Entry, Instance, Option<vk::DebugUtilsMessengerEXT>,
+               EnablePortability, EnableValidation)>
+{
+  let enable_validation = cfg!(feature = "vulkan-validation")
+                          || cfg!(debug_assertions);
+
+  //   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
+  // least, that's the theory, but also see flake.nix for all the
+  // FHS-centric assumptions it makes that we have to correct.
+  //
+  //   Anyway, Vulkanalia offers an integration with libloading, which is a
+  // crate that wraps POSIX dlopen(). We use that; it's enabled by
+  // Vulkanalia's "libloading" feature.
+  let loader = unsafe { LibloadingLoader::new(LIBRARY) }?;
+  let entry = unsafe { Entry::new(loader) }?;
+
+  //   Since there's a lot of factors going into our instance creation
+  // request, we'll build up the parameters mutably.
+  let mut flags = vk::InstanceCreateFlags::empty();
+  let mut extensions = Vec::new();
+  let mut layers = Vec::new();
+
+  //   Before we go any further, use Vulkan's introspection to list off
+  // what's available.
+  let mut available_extensions = HashSet::new();
+  for extension in
+          unsafe { entry.enumerate_instance_extension_properties(None) }?
+  {
+    available_extensions.insert(extension.extension_name);
+  }
+  let available_extensions = available_extensions;
+
+  let mut available_layers = HashSet::new();
+  for layer in unsafe { entry.enumerate_instance_layer_properties() }? {
+    available_layers.insert(layer.layer_name);
+  }
+  let available_layers = available_layers;
+
+  //   There are certain extensions which are required by the nature of our
+  // windowing system. Happily, vulanaklia knows how to deal with that based
+  // on the type of window we give it.
+  //
+  //   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(
+                       window)
+  {
+    extensions.push(extension.as_ptr());
+  }
+
+  //   Deal with Vulkan's thing about opting in to non-conforming
+  // implementations.
+  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(
+          vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION.name.as_ptr());
+      extensions.push(
+          vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr());
+      flags.insert(vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR);
+
+      EnablePortability(true)
     } else {
-      eprintln!("Vulkan debug extension not available; \
-                 this may mean other messages don't show up.");
+      EnablePortability(false)
     }
+  } else {
+    EnablePortability(false)
+  };
 
-    let application_info = ApplicationInfo::builder()
-            .application_name(b"Surreality\0")
-            .application_version(vk::make_version(1, 0, 0))
-            .engine_name(b"Surreality\0")
-            .engine_version(vk::make_version(1, 0, 0))
-            .api_version(vk::make_version(1, 0, 0));
-
-    //   Deceptively, this DOES get mutated later, but Vulkanalia doesn't see
-    // it that way.
-    let instance_create_info = InstanceCreateInfo::builder()
-            .application_info(&application_info)
-            .flags(flags)
-            .enabled_extension_names(&extensions)
-            .enabled_layer_names(&layers);
-
-    //   Configure the debug extension. This is the middle of three bits of
-    // code that deal with this, and has the responsibility of making sure
-    // the callback will be available during instance creation and
-    // destruction, which is done in a special way that doesn't rely on having
-    // a messager, since there can't be one for those steps.
-    let debug_info = if available_extensions.contains(&debug_extension_name) {
-      let mut debug_info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
-              .message_severity(vk::DebugUtilsMessageSeverityFlagsEXT::all())
-              .message_type(vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
-                            | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
-                            | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE)
-              .user_callback(Some(debug_messager_callback));
-
-      //   Please notice that the reference we pass here will escape Rust's
-      // lifetime checking, since push_next() casts it to a pointer. We don't
-      // get nearly as strong a safety guarantee as one might hope (and as [1]
-      // naively reassures us we do). If we did, the thing we're doing would
-      // actually be forbidden!
-      //
-      // [1] https://kylemayes.github.io/vulkanalia/
-      instance_create_info.push_next(&mut debug_info);
-
-      Some(debug_info)
-    } else { None };
-
-    let instance = unsafe {
-      //   We're promising that every struct referenced here is still alive.
-      // Since it's all pointers, that's... not a thing we statically know. Be
-      // aware. Only you can prevent segfaults.
-      entry.create_instance(&instance_create_info, None)
-    }?;
+  // Request the LunarG validation layer, when appropriate.
+  let validation_layer_name = vk::ExtensionName::from_bytes(
+                                  b"VK_LAYER_KHRONOS_validation");
+  let enable_validation = if enable_validation {
+    if available_layers.contains(&validation_layer_name) {
+      layers.push(validation_layer_name.as_ptr());
 
-    //   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.
-    let debug_messager = if let Some(debug_info) = debug_info {
-      #[allow(unsafe_code)]
-      Some(unsafe {
-        instance.create_debug_utils_messenger_ext(&debug_info, None)
-      }?)
+      EnableValidation(true)
     } else {
-      None
-    };
+      eprintln!("Vulkan validation requested at build time, \
+                 but no validation layer available.");
 
-    Ok((entry, instance, debug_messager,
-        enable_portability, enable_validation))
+      EnableValidation(false)
+    }
+  } else {
+    EnableValidation(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
+  // extension is in the list we ask for.
+  let debug_extension_name = vk::EXT_DEBUG_UTILS_EXTENSION.name;
+  if available_extensions.contains(&debug_extension_name) {
+    extensions.push(debug_extension_name.as_ptr());
+  } else {
+    eprintln!("Vulkan debug extension not available; \
+               this may mean other messages don't show up.");
   }
 
-  #[allow(unsafe_code)]
-  fn init_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR,
-                        enable_validation: EnableValidation,
-                        enable_portability: EnablePortability)
-      -> Result<(vk::PhysicalDevice, Device, QueueFamilyIndices, vk::Queue,
-                 vk::Queue, EnableSwapchain)>
-  {
-    let (physical_device, indices)
-            = Self::pick_vulkan_device(instance, surface)?;
-
-    //   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 enable_validation.0 {
-      //   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 application_info = ApplicationInfo::builder()
+          .application_name(b"Surreality\0")
+          .application_version(vk::make_version(1, 0, 0))
+          .engine_name(b"Surreality\0")
+          .engine_version(vk::make_version(1, 0, 0))
+          .api_version(vk::make_version(1, 0, 0));
+
+  //   Deceptively, this DOES get mutated later, but Vulkanalia doesn't see
+  // it that way.
+  let instance_create_info = InstanceCreateInfo::builder()
+          .application_info(&application_info)
+          .flags(flags)
+          .enabled_extension_names(&extensions)
+          .enabled_layer_names(&layers);
+
+  //   Configure the debug extension. This is the middle of three bits of
+  // code that deal with this, and has the responsibility of making sure
+  // the callback will be available during instance creation and
+  // destruction, which is done in a special way that doesn't rely on having
+  // a messager, since there can't be one for those steps.
+  let debug_info = if available_extensions.contains(&debug_extension_name) {
+    let mut debug_info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
+            .message_severity(vk::DebugUtilsMessageSeverityFlagsEXT::all())
+            .message_type(vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
+                          | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
+                          | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE)
+            .user_callback(Some(debug_messager_callback));
+
+    //   Please notice that the reference we pass here will escape Rust's
+    // lifetime checking, since push_next() casts it to a pointer. We don't
+    // get nearly as strong a safety guarantee as one might hope (and as [1]
+    // naively reassures us we do). If we did, the thing we're doing would
+    // actually be forbidden!
+    //
+    // [1] https://kylemayes.github.io/vulkanalia/
+    instance_create_info.push_next(&mut debug_info);
+
+    Some(debug_info)
+  } else { None };
+
+  let instance = unsafe {
+    //   We're promising that every struct referenced here is still alive.
+    // Since it's all pointers, that's... not a thing we statically know. Be
+    // aware. Only you can prevent segfaults.
+    entry.create_instance(&instance_create_info, None)
+  }?;
+
+  //   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.
+  let debug_messager = if let Some(debug_info) = debug_info {
+    #[allow(unsafe_code)]
+    Some(unsafe {
+      instance.create_debug_utils_messenger_ext(&debug_info, None)
+    }?)
+  } else {
+    None
+  };
+
+  Ok((entry, instance, debug_messager,
+      enable_portability, enable_validation))
+}
+
+
+#[allow(unsafe_code)]
+fn init_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR,
+                      enable_validation: EnableValidation,
+                      enable_portability: EnablePortability)
+    -> Result<(vk::PhysicalDevice, Device, QueueFamilyIndices, vk::Queue,
+               vk::Queue, EnableSwapchain)>
+{
+  let (physical_device, indices) = pick_vulkan_device(instance, surface)?;
+
+  //   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 enable_validation.0 {
+    //   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 portability_extension_name = vk::ExtensionName::from_bytes(
-                                         b"VK_KHR_portability_subset");
-    if enable_portability.0 {
-      //   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 portability_extension_name = vk::ExtensionName::from_bytes(
+                                       b"VK_KHR_portability_subset");
+  if enable_portability.0 {
+    //   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)
+  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(_)
+           = PermanentGraphicsState::find_device_swapchain_features(
+                 &instance, &surface, &physical_device)?
     {
-      //   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(_)
-             = PermanentGraphicsState::find_device_swapchain_features(
-                   &instance, &surface, &physical_device)?
-      {
-        extensions.push(swapchain_extension_name.as_ptr());
-
-        EnableSwapchain(true)
-      } else {
-        EnableSwapchain(false)
-      }
+      extensions.push(swapchain_extension_name.as_ptr());
+
+      EnableSwapchain(true)
     } else {
       EnableSwapchain(false)
-    };
-
-    //   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]));
     }
+  } else {
+    EnableSwapchain(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(physical_device, &device_info, None)
-    }?;
+  let device_info = vk::DeviceCreateInfo::builder()
+          .queue_create_infos(&queues)
+          .enabled_layer_names(&layers)
+          .enabled_extension_names(&extensions)
+          .enabled_features(&features);
+
+  let device = unsafe {
+    instance.create_device(physical_device, &device_info, None)
+  }?;
+
+  //   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)
+  };
 
-    //   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 presentation_queue = unsafe {
+    device.get_device_queue(indices.presentation, 0)
+  };
 
-    let presentation_queue = unsafe {
-      device.get_device_queue(indices.presentation, 0)
-    };
+  Ok((physical_device, device,
+      indices, graphics_queue, presentation_queue,
+      enable_swapchain))
+}
 
-    Ok((physical_device, device,
-        indices, graphics_queue, presentation_queue,
-        enable_swapchain))
-  }
 
-  //   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 {
+//   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 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)
-          };
+      }
+      Acceptable::Rejected(reason) => {
+        let properties = unsafe {
+          instance.get_physical_device_properties(device)
+        };
 
-          let name = properties.device_name.to_string_lossy().into_owned();
+        let name = properties.device_name.to_string_lossy().into_owned();
 
-          rejected.insert(properties.device_id, (name, reason));
-        }
+        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()
-      })
+  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)>>
+
+//   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 find_device_queue_family_indices(
+                          instance, surface, physical_device)?
   {
-    //   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
-    };
+    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)
-    };
+  //   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(_)
-             = PermanentGraphicsState::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;
-      }
+  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;
 
-      //   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.
+  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(_)
+           = PermanentGraphicsState::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;
     }
 
-    Ok(Acceptable::Accepted((score, indices)))
+    //   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.
   }
 
-  #[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);
-      }
+  Ok(Acceptable::Accepted((score, indices)))
+}
 
-      if presentation.is_none() && unsafe {
-        instance.get_physical_device_surface_support_khr(
-            *device, index as u32, *surface)
-      }? {
-        presentation = Some(index as u32);
-      }
+
+#[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 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()))
+    if presentation.is_none() && unsafe {
+      instance.get_physical_device_surface_support_khr(
+          *device, index as u32, *surface)
+    }? {
+      presentation = Some(index as u32);
     }
   }
 
-  //   We expect our caller to have already verified that the device supports
-  // the swapchain extension.
-  #[allow(unsafe_code)]
-  pub 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()))
+  if let Some(graphics) = graphics {
+    if let Some(presentation) = presentation {
+      Ok(Acceptable::Accepted(QueueFamilyIndices {
+        graphics, presentation
+      }))
     } else {
-      Ok(Acceptable::Accepted((capabilities, formats, presentation_modes)))
+      Ok(Acceptable::Rejected(
+          "Doesn't support presenting to our window.".to_string()))
     }
-  }
-
-  #[allow(unsafe_code)]
-  pub 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)
+  } else {
+    Ok(Acceptable::Rejected("Doesn't support graphics.".to_string()))
   }
 }
 
diff --git a/src/graphics_window_dressing.rs b/src/graphics_window_dressing.rs
index 6ffab41..e35332f 100644
--- a/src/graphics_window_dressing.rs
+++ b/src/graphics_window_dressing.rs
@@ -82,22 +82,22 @@ impl WindowDressing {
     let surface = &permanent.surface;
     let device = &permanent.device;
 
-    let swapchain = Self::init_swapchain(
+    let swapchain = init_swapchain(
             window, instance, surface, &physical_device, device, &indices)?;
 
-    let render_pass = Self::init_render_pass(device, &swapchain.format)?;
+    let render_pass = init_render_pass(device, &swapchain.format)?;
 
     let (pipeline_layout, pipeline)
-            = Self::init_pipeline(device, &swapchain.extent, &render_pass)?;
+            = init_pipeline(device, &swapchain.extent, &render_pass)?;
 
-    let framebuffers = Self::init_framebuffers(
+    let framebuffers = 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)?;
+            = init_commands(device, &swapchain.extent, &framebuffers,
+                            &render_pass, &pipeline, &indices)?;
 
-    let concurrency = Self::init_concurrency(device, &swapchain.images)?;
+    let concurrency = init_concurrency(device, &swapchain.images)?;
 
     Ok(WindowDressing {
       swapchain,
@@ -143,462 +143,472 @@ impl WindowDressing {
 
     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,
-                    indices: &QueueFamilyIndices)
-      -> Result<Swapchain>
-  {
-    let (capabilities, formats, presentation_modes)
-            = PermanentGraphicsState::find_device_swapchain_features(
-                  instance, surface, physical_device)?.require()?;
-
-    let format = Self::pick_surface_format(&formats)?;
-
-    let presentation_mode
-            = Self::pick_presentation_mode(&presentation_modes)?;
-    let extent = Self::pick_image_extent(window, capabilities)?;
-
-    let mut image_count = capabilities.min_image_count + 1;
-    if capabilities.max_image_count != 0 {
-      image_count
-          = image_count.clamp(0, 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);
-
-    //   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(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)
-    }?;
+#[allow(unsafe_code)]
+fn init_swapchain(window: &Window, instance: &Instance,
+                  surface: &vk::SurfaceKHR,
+                  physical_device: &vk::PhysicalDevice, device: &Device,
+                  indices: &QueueFamilyIndices)
+    -> Result<Swapchain>
+{
+  let (capabilities, formats, presentation_modes)
+          = PermanentGraphicsState::find_device_swapchain_features(
+                instance, surface, physical_device)?.require()?;
 
-    let images = unsafe {
-      device.get_swapchain_images_khr(swapchain)
-    }?;
+  let format = pick_surface_format(&formats)?;
 
-    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 presentation_mode
+          = pick_presentation_mode(&presentation_modes)?;
+  let extent = pick_image_extent(window, capabilities)?;
 
-    Ok(Swapchain {
-      swapchain, images, image_views,
-      format: format.format,
-      extent
-    })
+  let mut image_count = capabilities.min_image_count + 1;
+  if capabilities.max_image_count != 0 {
+    image_count
+        = image_count.clamp(0, capabilities.max_image_count);
   }
 
-  #[allow(unsafe_code)]
-  fn init_render_pass(device: &Device, format: &vk::Format)
-      -> Result<vk::RenderPass>
+  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
   {
-    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)
+    (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(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 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)
     }?;
 
-    Ok(render_pass)
+    image_views.push(view);
   }
 
-  #[allow(unsafe_code)]
-  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 = PermanentGraphicsState::load_spirv_shader_module(
-            device, vertex_binary)?;
-    let fragment_module = PermanentGraphicsState::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");
+  Ok(Swapchain {
+    swapchain, images, image_views,
+    format: format.format,
+    extent
+  })
+}
 
-    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];
+#[allow(unsafe_code)]
+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(render_pass)
+}
 
-    unsafe {
-      device.destroy_shader_module(vertex_module, None);
-      device.destroy_shader_module(fragment_module, None);
-    };
 
-    Ok((pipeline_layout, pipeline))
-  }
+#[allow(unsafe_code)]
+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 = PermanentGraphicsState::load_spirv_shader_module(
+          device, vertex_binary)?;
+  let fragment_module = PermanentGraphicsState::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");
 
-  #[allow(unsafe_code)]
-  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();
+  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];
+
+  unsafe {
+    device.destroy_shader_module(vertex_module, None);
+    device.destroy_shader_module(fragment_module, None);
+  };
+
+  Ok((pipeline_layout, pipeline))
+}
 
-    for image_view in swapchain_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);
+#[allow(unsafe_code)]
+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();
 
-      let framebuffer = unsafe {
-        device.create_framebuffer(&framebuffer_info, None)
-      }?;
+  for image_view in swapchain_image_views {
+    let attachments = [*image_view];
 
-      framebuffers.push(framebuffer);
-    }
+    let framebuffer_info = vk::FramebufferCreateInfo::builder()
+                               .render_pass(*render_pass)
+                               .attachments(&attachments)
+                               .width(extent.width)
+                               .height(extent.height)
+                               .layers(1);
 
-    Ok(framebuffers)
+    let framebuffer = unsafe {
+      device.create_framebuffer(&framebuffer_info, None)
+    }?;
+
+    framebuffers.push(framebuffer);
   }
 
-  #[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.
+  Ok(framebuffers)
+}
 
-    let command_pool_info = vk::CommandPoolCreateInfo::builder()
-                                .flags(vk::CommandPoolCreateFlags::empty())
-                                .queue_family_index(indices.graphics);
 
-    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.
+
+  let command_pool_info = vk::CommandPoolCreateInfo::builder()
+                              .flags(vk::CommandPoolCreateFlags::empty())
+                              .queue_family_index(indices.graphics);
+
+  let command_pool = unsafe {
+    device.create_command_pool(&command_pool_info, None)
+  }?;
+
+  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)
+  }?;
+
+  for (index, framebuffer) in framebuffers.iter().enumerate() {
+    let command_buffer = command_buffers[index];
+
+    let inheritance_info = vk::CommandBufferInheritanceInfo::builder();
+
+    let command_buffer_begin_info
+            = vk::CommandBufferBeginInfo::builder()
+                  .flags(vk::CommandBufferUsageFlags::empty())
+                  .inheritance_info(&inheritance_info);
 
-    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)
+    unsafe {
+      device.begin_command_buffer(command_buffer,
+                                  &command_buffer_begin_info)
     }?;
 
-    for (index, framebuffer) in framebuffers.iter().enumerate() {
-      let command_buffer = command_buffers[index];
+    let render_area = vk::Rect2D::builder()
+                          .offset(vk::Offset2D::default())
+                          .extent(*extent);
 
-      let inheritance_info = vk::CommandBufferInheritanceInfo::builder();
-
-      let command_buffer_begin_info
-              = vk::CommandBufferBeginInfo::builder()
-                    .flags(vk::CommandBufferUsageFlags::empty())
-                    .inheritance_info(&inheritance_info);
+    let clear_value = vk::ClearValue {
+      color: vk::ClearColorValue {
+        float32: [0.0, 0.0, 0.0, 1.0]
+      }
+    };
+    let clear_values = [clear_value];
 
-      unsafe {
-        device.begin_command_buffer(command_buffer,
-                                    &command_buffer_begin_info)
-      }?;
+    let begin_pass_info = vk::RenderPassBeginInfo::builder()
+                              .render_pass(*render_pass)
+                              .framebuffer(*framebuffer)
+                              .render_area(render_area)
+                              .clear_values(&clear_values);
 
-      let render_area = vk::Rect2D::builder()
-                            .offset(vk::Offset2D::default())
-                            .extent(*extent);
+    unsafe {
+      device.cmd_begin_render_pass(command_buffer, &begin_pass_info,
+                                   vk::SubpassContents::INLINE)
+    };
 
-      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_bind_pipeline(command_buffer,
+                               vk::PipelineBindPoint::GRAPHICS,
+                               *pipeline)
+    };
 
-      let begin_pass_info = vk::RenderPassBeginInfo::builder()
-                                .render_pass(*render_pass)
-                                .framebuffer(*framebuffer)
-                                .render_area(render_area)
-                                .clear_values(&clear_values);
+    unsafe { device.cmd_draw(command_buffer, 3, 1, 0, 0) };
 
-      unsafe {
-        device.cmd_begin_render_pass(command_buffer, &begin_pass_info,
-                                     vk::SubpassContents::INLINE)
-      };
+    unsafe { device.cmd_end_render_pass(command_buffer) };
 
-      unsafe {
-        device.cmd_bind_pipeline(command_buffer,
-                                 vk::PipelineBindPoint::GRAPHICS,
-                                 *pipeline)
-      };
+    unsafe { device.end_command_buffer(command_buffer) }?;
+  }
 
-      unsafe { device.cmd_draw(command_buffer, 3, 1, 0, 0) };
+  Ok((command_pool, command_buffers))
+}
 
-      unsafe { device.cmd_end_render_pass(command_buffer) };
 
-      unsafe { device.end_command_buffer(command_buffer) }?;
-    }
+#[allow(unsafe_code)]
+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);
+
+  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)
+    }?);
+
+    rendering_finished_semaphores.push(unsafe {
+      device.create_semaphore(&semaphore_info, None)
+    }?);
+
+    frame_fences.push(unsafe {
+      device.create_fence(&fence_info, None)
+    }?);
+  }
 
-    Ok((command_pool, command_buffers))
+  let mut image_fences = Vec::new();
+  for _ in 0 .. swapchain_images.len() {
+    image_fences.push(vk::Fence::null());
   }
 
-  #[allow(unsafe_code)]
-  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);
-
-    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)
-      }?);
-
-      rendering_finished_semaphores.push(unsafe {
-        device.create_semaphore(&semaphore_info, None)
-      }?);
-
-      frame_fences.push(unsafe {
-        device.create_fence(&fence_info, None)
-      }?);
-    }
+  Ok(Concurrency {
+    image_available_semaphores,
+    rendering_finished_semaphores,
+    frame_fences,
+    image_fences: image_fences,
+  })
+}
 
-    let mut image_fences = Vec::new();
-    for _ in 0 .. swapchain_images.len() {
-      image_fences.push(vk::Fence::null());
-    }
 
-    Ok(Concurrency {
-      image_available_semaphores,
-      rendering_finished_semaphores,
-      frame_fences,
-      image_fences: image_fences,
-    })
+fn pick_surface_format(available_formats: &Vec<vk::SurfaceFormatKHR>)
+    -> Result<vk::SurfaceFormatKHR>
+{
+  for format in available_formats {
+    if format.format == vk::Format::B8G8R8A8_SRGB
+       && format.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR
+    {
+      return Ok(format.clone());
+    }
   }
 
-  fn pick_surface_format(available_formats: &Vec<vk::SurfaceFormatKHR>)
-      -> Result<vk::SurfaceFormatKHR>
-  {
-    for format in available_formats {
-      if format.format == vk::Format::B8G8R8A8_SRGB
-         && format.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR
-      {
-        return Ok(format.clone());
-      }
-    }
+  return Ok(available_formats[0].clone());
+}
 
-    return Ok(available_formats[0].clone());
-  }
 
-  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_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(window: &Window,
-                       capabilities: vk::SurfaceCapabilitiesKHR)
-      -> Result<vk::Extent2D>
+
+fn pick_image_extent(window: &Window,
+                     capabilities: vk::SurfaceCapabilitiesKHR)
+    -> Result<vk::Extent2D>
+{
+  if capabilities.current_extent.width != u32::MAX
+     && capabilities.current_extent.height != u32::MAX
   {
-    if capabilities.current_extent.width != u32::MAX
-       && capabilities.current_extent.height != u32::MAX
-    {
-      Ok(capabilities.current_extent)
-    } else {
-      let window_size = window.inner_size();
-
-      let width = window_size.width
-                             .clamp(capabilities.min_image_extent.width,
-                                    capabilities.max_image_extent.width);
-      let height = window_size.height
-                              .clamp(capabilities.min_image_extent.height,
-                                     capabilities.max_image_extent.height);
-
-      Ok(vk::Extent2D::builder().width(width).height(height).build())
-    }
+    Ok(capabilities.current_extent)
+  } else {
+    let window_size = window.inner_size();
+
+    let width = window_size.width
+                           .clamp(capabilities.min_image_extent.width,
+                                  capabilities.max_image_extent.width);
+    let height = window_size.height
+                            .clamp(capabilities.min_image_extent.height,
+                                   capabilities.max_image_extent.height);
+
+    Ok(vk::Extent2D::builder().width(width).height(height).build())
   }
 }
+