Index: vulkan-game.cpp
===================================================================
--- vulkan-game.cpp	(revision c1c20210c81af4cba67acbd3a93c3583d12501b6)
+++ vulkan-game.cpp	(revision 502bd0b00535639bbb2b56379b77d0c05e799a35)
@@ -100,4 +100,5 @@
    pickPhysicalDevice(deviceExtensions);
    createLogicalDevice(validationLayers, deviceExtensions);
+   createSwapChain();
 }
 
@@ -177,4 +178,5 @@
 
 void VulkanGame::cleanupSwapChain() {
+   vkDestroySwapchainKHR(device, swapChain, nullptr);
 }
 
@@ -357,2 +359,56 @@
    vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
 }
+
+void VulkanGame::createSwapChain() {
+   SwapChainSupportDetails swapChainSupport = VulkanUtils::querySwapChainSupport(physicalDevice, surface);
+
+   VkSurfaceFormatKHR surfaceFormat = VulkanUtils::chooseSwapSurfaceFormat(swapChainSupport.formats);
+   VkPresentModeKHR presentMode = VulkanUtils::chooseSwapPresentMode(swapChainSupport.presentModes);
+   VkExtent2D extent = VulkanUtils::chooseSwapExtent(swapChainSupport.capabilities, gui->getWindowWidth(), gui->getWindowHeight());
+
+   uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
+   if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
+      imageCount = swapChainSupport.capabilities.maxImageCount;
+   }
+
+   VkSwapchainCreateInfoKHR createInfo = {};
+   createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+   createInfo.surface = surface;
+   createInfo.minImageCount = imageCount;
+   createInfo.imageFormat = surfaceFormat.format;
+   createInfo.imageColorSpace = surfaceFormat.colorSpace;
+   createInfo.imageExtent = extent;
+   createInfo.imageArrayLayers = 1;
+   createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+   QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
+   uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value() };
+
+   if (indices.graphicsFamily != indices.presentFamily) {
+      createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
+      createInfo.queueFamilyIndexCount = 2;
+      createInfo.pQueueFamilyIndices = queueFamilyIndices;
+   }
+   else {
+      createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+      createInfo.queueFamilyIndexCount = 0;
+      createInfo.pQueueFamilyIndices = nullptr;
+   }
+
+   createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
+   createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+   createInfo.presentMode = presentMode;
+   createInfo.clipped = VK_TRUE;
+   createInfo.oldSwapchain = VK_NULL_HANDLE;
+
+   if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
+      throw runtime_error("failed to create swap chain!");
+   }
+
+   vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
+   swapChainImages.resize(imageCount);
+   vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
+
+   swapChainImageFormat = surfaceFormat.format;
+   swapChainExtent = extent;
+}
Index: vulkan-game.hpp
===================================================================
--- vulkan-game.hpp	(revision c1c20210c81af4cba67acbd3a93c3583d12501b6)
+++ vulkan-game.hpp	(revision 502bd0b00535639bbb2b56379b77d0c05e799a35)
@@ -33,4 +33,9 @@
       VkQueue presentQueue;
 
+      VkSwapchainKHR swapChain;
+      vector<VkImage> swapChainImages;
+      VkFormat swapChainImageFormat;
+      VkExtent2D swapChainExtent;
+
       bool initWindow(int width, int height, unsigned char guiFlags);
       void initVulkan();
@@ -49,4 +54,5 @@
          const vector<const char*> validationLayers,
          const vector<const char*>& deviceExtensions);
+      void createSwapChain();
       void cleanupSwapChain();
 
Index: vulkan-ref.cpp
===================================================================
--- vulkan-ref.cpp	(revision c1c20210c81af4cba67acbd3a93c3583d12501b6)
+++ vulkan-ref.cpp	(revision 502bd0b00535639bbb2b56379b77d0c05e799a35)
@@ -168,5 +168,4 @@
       VkQueue graphicsQueue;
       VkQueue presentQueue;
-/*** END OF REFACTORED CODE ***/
 
       VkSwapchainKHR swapChain;
@@ -174,4 +173,5 @@
       VkFormat swapChainImageFormat;
       VkExtent2D swapChainExtent;
+/*** END OF REFACTORED CODE ***/
       vector<VkImageView> swapChainImageViews;
       vector<VkFramebuffer> swapChainFramebuffers;
@@ -608,5 +608,4 @@
          vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
       }
-/*** END OF REFACTORED CODE ***/
 
       void createSwapChain() {
@@ -663,5 +662,4 @@
       }
 
-/*** START OF REFACTORED CODE ***/
       SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {
          SwapChainSupportDetails details;
@@ -1948,5 +1946,7 @@
          }
 
+/*** START OF REFACTORED CODE ***/
          vkDestroySwapchainKHR(device, swapChain, nullptr);
+/*** END OF REFACTORED CODE ***/
 
          for (size_t i = 0; i < swapChainImages.size(); i++) {
Index: vulkan-utils.cpp
===================================================================
--- vulkan-utils.cpp	(revision c1c20210c81af4cba67acbd3a93c3583d12501b6)
+++ vulkan-utils.cpp	(revision 502bd0b00535639bbb2b56379b77d0c05e799a35)
@@ -125,2 +125,43 @@
    return details;
 }
+
+VkSurfaceFormatKHR VulkanUtils::chooseSwapSurfaceFormat(const vector<VkSurfaceFormatKHR>& availableFormats) {
+   for (const auto& availableFormat : availableFormats) {
+      if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
+         return availableFormat;
+      }
+   }
+
+   return availableFormats[0];
+}
+
+VkPresentModeKHR VulkanUtils::chooseSwapPresentMode(const vector<VkPresentModeKHR>& availablePresentModes) {
+   VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR;
+
+   for (const auto& availablePresentMode : availablePresentModes) {
+      if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
+         return availablePresentMode;
+      }
+      else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
+         bestMode = availablePresentMode;
+      }
+   }
+
+   return bestMode;
+}
+
+VkExtent2D VulkanUtils::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, int width, int height) {
+   if (capabilities.currentExtent.width != numeric_limits<uint32_t>::max()) {
+      return capabilities.currentExtent;
+   } else {
+      VkExtent2D actualExtent = {
+         static_cast<uint32_t>(width),
+         static_cast<uint32_t>(height)
+      };
+
+      actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
+      actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
+
+      return actualExtent;
+   }
+}
Index: vulkan-utils.hpp
===================================================================
--- vulkan-utils.hpp	(revision c1c20210c81af4cba67acbd3a93c3583d12501b6)
+++ vulkan-utils.hpp	(revision 502bd0b00535639bbb2b56379b77d0c05e799a35)
@@ -40,4 +40,7 @@
       static bool checkDeviceExtensionSupport(VkPhysicalDevice physicalDevice, const vector<const char*>& deviceExtensions);
       static SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface);
+      static VkSurfaceFormatKHR chooseSwapSurfaceFormat(const vector<VkSurfaceFormatKHR>& availableFormats);
+      static VkPresentModeKHR chooseSwapPresentMode(const vector<VkPresentModeKHR>& availablePresentModes);
+      static VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, int width, int height);
 };
 
