Index: vulkan-game.cpp
===================================================================
--- vulkan-game.cpp	(revision 7f60b28d36ec26221af91af3a69b8a68d7b9b7c1)
+++ vulkan-game.cpp	(revision 3f32dfd9a09b20768e80b46b2a5ee4aea024fdc4)
@@ -18,4 +18,7 @@
 
 using namespace std;
+
+// TODO: Update all instances of the "... != VK_SUCCESS" check to something similar to
+// the agp error checking function, which prints an appropriate error message based on the error code
 
 // TODO: Update all occurances of instance variables to use this-> (Actually, not sure if I really want to do this)
@@ -44,9 +47,15 @@
 }
 
-VulkanGame::VulkanGame(int maxFramesInFlight) : MAX_FRAMES_IN_FLIGHT(maxFramesInFlight) {
+VulkanGame::VulkanGame() {
+   // TODO: Double-check whether initialization should happen in the header, where the variables are declared, or here
+   // Also, decide whether to use this-> for all instance variables, or only when necessary
+
+   this->debugMessenger = VK_NULL_HANDLE;
+
    this->gui = nullptr;
    this->window = nullptr;
 
-   this->debugMessenger = VK_NULL_HANDLE;
+   this->swapChainPresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
+   this->swapChainMinImageCount = 0;
 
    this->currentFrame = 0;
@@ -200,7 +209,9 @@
    pickPhysicalDevice(deviceExtensions);
    createLogicalDevice(validationLayers, deviceExtensions);
+   chooseSwapChainProperties();
    createSwapChain();
    createImageViews();
    createRenderPass();
+   createResourceCommandPool();
    createCommandPool();
 
@@ -226,5 +237,5 @@
    //ImGui::StyleColorsClassic();
 
-   // TODO: Make call this once and save the results since it's also called when creating the logical device
+   // TODO: Maybe call this once and save the results since it's also called when creating the logical device
    QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
 
@@ -234,9 +245,10 @@
    init_info.PhysicalDevice = this->physicalDevice;
    init_info.Device = this->device;
-   init_info.PipelineCache = VK_NULL_HANDLE;
+   init_info.QueueFamily = indices.graphicsFamily.value();
+   init_info.Queue = graphicsQueue;
    init_info.DescriptorPool = this->imguiDescriptorPool; // TODO: Create a descriptor pool for IMGUI
    init_info.Allocator = nullptr;
-   init_info.MinImageCount = this->swapChainImageCount;
-   init_info.ImageCount = this->swapChainImages.size();
+   init_info.MinImageCount = this->swapChainMinImageCount;
+   init_info.ImageCount = this->swapChainImageCount;
    init_info.CheckVkResultFn = check_vk_result;
    ImGui_ImplVulkan_Init(&init_info, this->renderPass);
@@ -251,6 +263,4 @@
       VkResult err;
 
-      // Use any command queue
-      VkCommandPool command_pool = this->commandPool; // TODO: No need to create a separate variable. Just use this->commandPool directly
       VkCommandBuffer command_buffer;
 
@@ -258,5 +268,5 @@
       VkCommandBufferAllocateInfo info = {};
       info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
-      info.commandPool = command_pool;
+      info.commandPool = resourceCommandPool;
       info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
       info.commandBufferCount = 1;
@@ -288,5 +298,5 @@
 
       // This should make the command pool reusable for later
-      err = vkResetCommandPool(this->device, command_pool, 0);
+      err = vkResetCommandPool(this->device, resourceCommandPool, 0);
       check_vk_result(err);
    }
@@ -918,4 +928,6 @@
 
       // Copy the UI image to a vulkan texture
+      // TODO: I'm pretty sure this severely slows down the pipeline since this functions waits for the copy to be
+      // complete before continuing. See if I can find a more efficient method.
       VulkanUtils::populateVulkanImageFromSDLTexture(device, physicalDevice, commandPool, uiOverlay, renderer,
          sdlOverlayImage, graphicsQueue);
@@ -923,7 +935,4 @@
       renderScene();
    }
-
-   // TODO: Should probably check the returned result
-   vkDeviceWaitIdle(device);
 }
 
@@ -931,5 +940,5 @@
 // which are already handled by updateObject(). Move this code to a different place,
 // where it will run just once per frame
-void VulkanGame::updateScene(uint32_t currentImage) {
+void VulkanGame::updateScene() {
    for (SceneObject<ModelVertex, SSBO_ModelObject>& model : this->modelObjects) {
       model.model_transform =
@@ -1110,25 +1119,21 @@
    explosion_UBO.cur_time = curTime;
 
-   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_modelPipeline[currentImage], 0, object_VP_mats);
-
-   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_shipPipeline[currentImage], 0, ship_VP_mats);
-
-   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_asteroidPipeline[currentImage], 0, asteroid_VP_mats);
-
-   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_laserPipeline[currentImage], 0, laser_VP_mats);
-
-   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_explosionPipeline[currentImage], 0, explosion_UBO);
+   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_modelPipeline[imageIndex], 0, object_VP_mats);
+
+   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_shipPipeline[imageIndex], 0, ship_VP_mats);
+
+   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_asteroidPipeline[imageIndex], 0, asteroid_VP_mats);
+
+   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_laserPipeline[imageIndex], 0, laser_VP_mats);
+
+   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_explosionPipeline[imageIndex], 0, explosion_UBO);
 }
 
 // TODO: Maybe move all/most of this to the base Screen class
 void VulkanGame::renderScene() {
-   vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, numeric_limits<uint64_t>::max());
-
-   uint32_t imageIndex;
-
    // TODO: Recreate the swap chain here if the user went to a new screen
 
    VkResult result = vkAcquireNextImageKHR(device, swapChain, numeric_limits<uint64_t>::max(),
-      imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
+      imageAcquiredSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
 
    if (result == VK_ERROR_OUT_OF_DATE_KHR) {
@@ -1139,15 +1144,19 @@
    }
 
-   // TODO: Figure out a more elegant way to only do updates and render the UI once per scene render
-   // Probably move some of the renderScene() code into a higher function that updates the UI, and renders
-   // the UI and scene
-   updateScene(imageIndex);
+   if (vkWaitForFences(device, 1, &inFlightFences[imageIndex], VK_TRUE, numeric_limits<uint64_t>::max()) != VK_SUCCESS) {
+      throw runtime_error("failed waiting for fence!");
+   }
+   if (vkResetFences(device, 1, &inFlightFences[imageIndex]) != VK_SUCCESS) {
+      throw runtime_error("failed to reset fence!");
+   }
+
+   updateScene();
+
+   VkSemaphore waitSemaphores[] = { imageAcquiredSemaphores[currentFrame] };
+   VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
+   VkSemaphore signalSemaphores[] = { renderCompleteSemaphores[currentFrame] };
 
    VkSubmitInfo submitInfo = {};
    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-
-   VkSemaphore waitSemaphores[] = { imageAvailableSemaphores[currentFrame] };
-   VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
-
    submitInfo.waitSemaphoreCount = 1;
    submitInfo.pWaitSemaphores = waitSemaphores;
@@ -1155,13 +1164,8 @@
    submitInfo.commandBufferCount = 1;
    submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
-
-   VkSemaphore signalSemaphores[] = { renderFinishedSemaphores[currentFrame] };
-
    submitInfo.signalSemaphoreCount = 1;
    submitInfo.pSignalSemaphores = signalSemaphores;
 
-   vkResetFences(device, 1, &inFlightFences[currentFrame]);
-
-   if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) {
+   if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[imageIndex]) != VK_SUCCESS) {
       throw runtime_error("failed to submit draw command buffer!");
    }
@@ -1171,8 +1175,6 @@
    presentInfo.waitSemaphoreCount = 1;
    presentInfo.pWaitSemaphores = signalSemaphores;
-
-   VkSwapchainKHR swapChains[] = { swapChain };
    presentInfo.swapchainCount = 1;
-   presentInfo.pSwapchains = swapChains;
+   presentInfo.pSwapchains = &swapChain;
    presentInfo.pImageIndices = &imageIndex;
    presentInfo.pResults = nullptr;
@@ -1187,13 +1189,16 @@
    }
 
-   currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
-   currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
+   currentFrame = (currentFrame + 1) % swapChainImageCount;
 }
 
 void VulkanGame::cleanup() {
+   // TODO: Should probably check the returned result
+   vkDeviceWaitIdle(device);
+
    ImGui_ImplVulkan_Shutdown();
    ImGui_ImplSDL2_Shutdown();
    ImGui::DestroyContext();
 
+   // TODO: Probably move this into cleanupSwapChain once I finish the integration
    destroyImguiDescriptorPool();
 
@@ -1213,11 +1218,7 @@
    explosionPipeline.cleanupBuffers();
 
-   for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
-      vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
-      vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
-      vkDestroyFence(device, inFlightFences[i], nullptr);
-   }
-
+   vkDestroyCommandPool(device, resourceCommandPool, nullptr);
    vkDestroyCommandPool(device, commandPool, nullptr);
+
    vkDestroyDevice(device, nullptr);
    vkDestroySurfaceKHR(instance, surface, nullptr);
@@ -1379,6 +1380,8 @@
 
    if (extensionsSupported) {
-      SwapChainSupportDetails swapChainSupport = VulkanUtils::querySwapChainSupport(physicalDevice, surface);
-      swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
+      vector<VkSurfaceFormatKHR> formats = VulkanUtils::querySwapChainFormats(physicalDevice, surface);
+      vector<VkPresentModeKHR> presentModes = VulkanUtils::querySwapChainPresentModes(physicalDevice, surface);
+
+      swapChainAdequate = !formats.empty() && !presentModes.empty();
    }
 
@@ -1445,26 +1448,56 @@
 }
 
+void VulkanGame::chooseSwapChainProperties() {
+   vector<VkSurfaceFormatKHR> availableFormats = VulkanUtils::querySwapChainFormats(physicalDevice, surface);
+   vector<VkPresentModeKHR> availablePresentModes = VulkanUtils::querySwapChainPresentModes(physicalDevice, surface);
+
+   swapChainSurfaceFormat = VulkanUtils::chooseSwapSurfaceFormat(availableFormats,
+      { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM },
+      VK_COLOR_SPACE_SRGB_NONLINEAR_KHR);
+
+   vector<VkPresentModeKHR> presentModes{
+      VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR
+   };
+   //vector<VkPresentModeKHR> presentModes{ VK_PRESENT_MODE_FIFO_KHR };
+
+   swapChainPresentMode = VulkanUtils::chooseSwapPresentMode(availablePresentModes, presentModes);
+
+   cout << "[vulkan] Selected PresentMode = " << swapChainPresentMode << endl;
+
+   VkSurfaceCapabilitiesKHR capabilities = VulkanUtils::querySwapChainCapabilities(physicalDevice, surface);
+
+   if (swapChainPresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
+      swapChainMinImageCount = 3;
+   } else if (swapChainPresentMode == VK_PRESENT_MODE_FIFO_KHR || swapChainPresentMode == VK_PRESENT_MODE_FIFO_RELAXED_KHR) {
+      swapChainMinImageCount = 2;
+   } else if (swapChainPresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
+      swapChainMinImageCount = 1;
+   } else {
+      throw runtime_error("unexpected present mode!");
+   }
+
+  if (swapChainMinImageCount < capabilities.minImageCount) {
+      swapChainMinImageCount = capabilities.minImageCount;
+   } else if (capabilities.maxImageCount != 0 && swapChainMinImageCount > capabilities.maxImageCount) {
+      swapChainMinImageCount = capabilities.maxImageCount;
+   }
+}
+
 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());
-
-   swapChainImageCount = swapChainSupport.capabilities.minImageCount + 1;
-   if (swapChainSupport.capabilities.maxImageCount > 0 && swapChainImageCount > swapChainSupport.capabilities.maxImageCount) {
-      swapChainImageCount = swapChainSupport.capabilities.maxImageCount;
-   }
+   VkSurfaceCapabilitiesKHR capabilities = VulkanUtils::querySwapChainCapabilities(physicalDevice, surface);
+
+   swapChainExtent = VulkanUtils::chooseSwapExtent(capabilities, gui->getWindowWidth(), gui->getWindowHeight());
 
    VkSwapchainCreateInfoKHR createInfo = {};
    createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
    createInfo.surface = surface;
-   createInfo.minImageCount = swapChainImageCount;
-   createInfo.imageFormat = surfaceFormat.format;
-   createInfo.imageColorSpace = surfaceFormat.colorSpace;
-   createInfo.imageExtent = extent;
+   createInfo.minImageCount = swapChainMinImageCount;
+   createInfo.imageFormat = swapChainSurfaceFormat.format;
+   createInfo.imageColorSpace = swapChainSurfaceFormat.colorSpace;
+   createInfo.imageExtent = swapChainExtent;
    createInfo.imageArrayLayers = 1;
    createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
 
+   // TODO: Maybe save this result so I don't have to recalculate it every time
    QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
    uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value() };
@@ -1480,7 +1513,7 @@
    }
 
-   createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
+   createInfo.preTransform = capabilities.currentTransform;
    createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
-   createInfo.presentMode = presentMode;
+   createInfo.presentMode = swapChainPresentMode;
    createInfo.clipped = VK_TRUE;
    createInfo.oldSwapchain = VK_NULL_HANDLE;
@@ -1490,17 +1523,19 @@
    }
 
-   vkGetSwapchainImagesKHR(device, swapChain, &swapChainImageCount, nullptr);
+   if (vkGetSwapchainImagesKHR(device, swapChain, &swapChainImageCount, nullptr) != VK_SUCCESS) {
+      throw runtime_error("failed to get swap chain image count!");
+   }
+
    swapChainImages.resize(swapChainImageCount);
-   vkGetSwapchainImagesKHR(device, swapChain, &swapChainImageCount, swapChainImages.data());
-
-   swapChainImageFormat = surfaceFormat.format;
-   swapChainExtent = extent;
+   if (vkGetSwapchainImagesKHR(device, swapChain, &swapChainImageCount, swapChainImages.data()) != VK_SUCCESS) {
+      throw runtime_error("failed to get swap chain images!");
+   }
 }
 
 void VulkanGame::createImageViews() {
-   swapChainImageViews.resize(swapChainImages.size());
-
-   for (size_t i = 0; i < swapChainImages.size(); i++) {
-      swapChainImageViews[i] = VulkanUtils::createImageView(device, swapChainImages[i], swapChainImageFormat,
+   swapChainImageViews.resize(swapChainImageCount);
+
+   for (size_t i = 0; i < swapChainImageCount; i++) {
+      swapChainImageViews[i] = VulkanUtils::createImageView(device, swapChainImages[i], swapChainSurfaceFormat.format,
          VK_IMAGE_ASPECT_COLOR_BIT);
    }
@@ -1509,5 +1544,5 @@
 void VulkanGame::createRenderPass() {
    VkAttachmentDescription colorAttachment = {};
-   colorAttachment.format = swapChainImageFormat;
+   colorAttachment.format = swapChainSurfaceFormat.format;
    colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
    colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
@@ -1574,6 +1609,19 @@
 }
 
+void VulkanGame::createResourceCommandPool() {
+   QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
+
+   VkCommandPoolCreateInfo poolInfo = {};
+   poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+   poolInfo.queueFamilyIndex = indices.graphicsFamily.value();
+   poolInfo.flags = 0;
+
+   if (vkCreateCommandPool(device, &poolInfo, nullptr, &resourceCommandPool) != VK_SUCCESS) {
+      throw runtime_error("failed to create resource command pool!");
+   }
+}
+
 void VulkanGame::createCommandPool() {
-   QueueFamilyIndices queueFamilyIndices = VulkanUtils::findQueueFamilies(physicalDevice, surface);;
+   QueueFamilyIndices queueFamilyIndices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
 
    VkCommandPoolCreateInfo poolInfo = {};
@@ -1588,5 +1636,5 @@
 
 void VulkanGame::createImageResources() {
-   VulkanUtils::createDepthImage(device, physicalDevice, commandPool, findDepthFormat(), swapChainExtent,
+   VulkanUtils::createDepthImage(device, physicalDevice, resourceCommandPool, findDepthFormat(), swapChainExtent,
       depthImage, graphicsQueue);
 
@@ -1602,5 +1650,5 @@
    sdlOverlayImageDescriptor.sampler = textureSampler;
 
-   VulkanUtils::createVulkanImageFromFile(device, physicalDevice, commandPool, "textures/texture.jpg",
+   VulkanUtils::createVulkanImageFromFile(device, physicalDevice, resourceCommandPool, "textures/texture.jpg",
       floorTextureImage, graphicsQueue);
 
@@ -1610,5 +1658,5 @@
    floorTextureImageDescriptor.sampler = textureSampler;
 
-   VulkanUtils::createVulkanImageFromFile(device, physicalDevice, commandPool, "textures/laser.png",
+   VulkanUtils::createVulkanImageFromFile(device, physicalDevice, resourceCommandPool, "textures/laser.png",
       laserTextureImage, graphicsQueue);
 
@@ -1646,7 +1694,14 @@
 
 void VulkanGame::createFramebuffers() {
-   swapChainFramebuffers.resize(swapChainImageViews.size());
-
-   for (size_t i = 0; i < swapChainImageViews.size(); i++) {
+   swapChainFramebuffers.resize(swapChainImageCount);
+
+   VkFramebufferCreateInfo framebufferInfo = {};
+   framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+   framebufferInfo.renderPass = renderPass;
+   framebufferInfo.width = swapChainExtent.width;
+   framebufferInfo.height = swapChainExtent.height;
+   framebufferInfo.layers = 1;
+
+   for (uint32_t i = 0; i < swapChainImageCount; i++) {
       array<VkImageView, 2> attachments = {
          swapChainImageViews[i],
@@ -1654,12 +1709,6 @@
       };
 
-      VkFramebufferCreateInfo framebufferInfo = {};
-      framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
-      framebufferInfo.renderPass = renderPass;
       framebufferInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
       framebufferInfo.pAttachments = attachments.data();
-      framebufferInfo.width = swapChainExtent.width;
-      framebufferInfo.height = swapChainExtent.height;
-      framebufferInfo.layers = 1;
 
       if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
@@ -1670,5 +1719,5 @@
 
 void VulkanGame::createCommandBuffers() {
-   commandBuffers.resize(swapChainImages.size());
+   commandBuffers.resize(swapChainImageCount);
 
    VkCommandBufferAllocateInfo allocInfo = {};
@@ -1745,4 +1794,31 @@
 }
 
+void VulkanGame::createSyncObjects() {
+   imageAcquiredSemaphores.resize(swapChainImageCount);
+   renderCompleteSemaphores.resize(swapChainImageCount);
+   inFlightFences.resize(swapChainImageCount);
+
+   VkSemaphoreCreateInfo semaphoreInfo = {};
+   semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+
+   VkFenceCreateInfo fenceInfo = {};
+   fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+   fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
+
+   for (size_t i = 0; i < swapChainImageCount; i++) {
+      if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAcquiredSemaphores[i]) != VK_SUCCESS) {
+         throw runtime_error("failed to create image acquired sempahore for a frame!");
+      }
+
+      if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderCompleteSemaphores[i]) != VK_SUCCESS) {
+         throw runtime_error("failed to create render complete sempahore for a frame!");
+      }
+
+      if (vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) {
+         throw runtime_error("failed to create fence for a frame!");
+      }
+   }
+}
+
 void VulkanGame::createImguiDescriptorPool() {
    vector<VkDescriptorPoolSize> pool_sizes{
@@ -1773,25 +1849,4 @@
 void VulkanGame::destroyImguiDescriptorPool() {
    vkDestroyDescriptorPool(device, imguiDescriptorPool, nullptr);
-}
-
-void VulkanGame::createSyncObjects() {
-   imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
-   renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
-   inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
-
-   VkSemaphoreCreateInfo semaphoreInfo = {};
-   semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
-
-   VkFenceCreateInfo fenceInfo = {};
-   fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
-   fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
-
-   for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
-      if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS ||
-            vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS ||
-            vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) {
-         throw runtime_error("failed to create synchronization objects for a frame!");
-      }
-   }
 }
 
@@ -2002,9 +2057,9 @@
 void VulkanGame::createBufferSet(VkDeviceSize bufferSize, VkBufferUsageFlags flags,
       vector<VkBuffer>& buffers, vector<VkDeviceMemory>& buffersMemory, vector<VkDescriptorBufferInfo>& bufferInfoList) {
-   buffers.resize(swapChainImages.size());
-   buffersMemory.resize(swapChainImages.size());
-   bufferInfoList.resize(swapChainImages.size());
-
-   for (size_t i = 0; i < swapChainImages.size(); i++) {
+   buffers.resize(swapChainImageCount);
+   buffersMemory.resize(swapChainImageCount);
+   bufferInfoList.resize(swapChainImageCount);
+
+   for (size_t i = 0; i < swapChainImageCount; i++) {
       VulkanUtils::createBuffer(device, physicalDevice, bufferSize, flags,
          VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
@@ -2073,5 +2128,5 @@
    createRenderPass();
 
-   VulkanUtils::createDepthImage(device, physicalDevice, commandPool, findDepthFormat(), swapChainExtent,
+   VulkanUtils::createDepthImage(device, physicalDevice, resourceCommandPool, findDepthFormat(), swapChainExtent,
       depthImage, graphicsQueue);
    createFramebuffers();
@@ -2125,4 +2180,8 @@
 
    createCommandBuffers();
+
+   createSyncObjects();
+
+   imageIndex = 0;
 }
 
@@ -2168,4 +2227,10 @@
    }
 
+   for (size_t i = 0; i < swapChainImageCount; i++) {
+      vkDestroySemaphore(device, imageAcquiredSemaphores[i], nullptr);
+      vkDestroySemaphore(device, renderCompleteSemaphores[i], nullptr);
+      vkDestroyFence(device, inFlightFences[i], nullptr);
+   }
+
    vkDestroyRenderPass(device, renderPass, nullptr);
 
Index: vulkan-game.hpp
===================================================================
--- vulkan-game.hpp	(revision 7f60b28d36ec26221af91af3a69b8a68d7b9b7c1)
+++ vulkan-game.hpp	(revision 3f32dfd9a09b20768e80b46b2a5ee4aea024fdc4)
@@ -198,5 +198,5 @@
 class VulkanGame {
    public:
-      VulkanGame(int maxFramesInFlight);
+      VulkanGame();
       ~VulkanGame();
 
@@ -234,9 +234,4 @@
          void* pUserData);
 
-      // TODO: Make these consts static
-      // Also, maybe move them into consts.hpp
-
-      const int MAX_FRAMES_IN_FLIGHT;
-
       const float NEAR_CLIP = 0.1f;
       const float FAR_CLIP = 100.0f;
@@ -268,23 +263,34 @@
       VkQueue presentQueue;
 
+      // TODO: Maybe make a swapchain struct for convenience
+      VkSurfaceFormatKHR swapChainSurfaceFormat;
+      VkPresentModeKHR swapChainPresentMode;
+      VkExtent2D swapChainExtent;
+      uint32_t swapChainMinImageCount;
       uint32_t swapChainImageCount;
       VkSwapchainKHR swapChain;
       vector<VkImage> swapChainImages;
-      VkFormat swapChainImageFormat;
-      VkExtent2D swapChainExtent;
       vector<VkImageView> swapChainImageViews;
       vector<VkFramebuffer> swapChainFramebuffers;
 
       VkRenderPass renderPass;
+
+      VkCommandPool resourceCommandPool;
+
       VkCommandPool commandPool;
+      vector<VkCommandPool> commandPools; // This is not used yet, but will be once 
       vector<VkCommandBuffer> commandBuffers;
 
       VulkanImage depthImage;
 
-      vector<VkSemaphore> imageAvailableSemaphores;
-      vector<VkSemaphore> renderFinishedSemaphores;
+      // These are per frame
+      vector<VkSemaphore> imageAcquiredSemaphores;
+      vector<VkSemaphore> renderCompleteSemaphores;
+
+      // These are per swap chain image
       vector<VkFence> inFlightFences;
 
-      size_t currentFrame;
+      uint32_t imageIndex;
+      uint32_t currentFrame;
 
       bool framebufferResized;
@@ -380,5 +386,5 @@
       void initMatrices();
       void mainLoop();
-      void updateScene(uint32_t currentImage);
+      void updateScene();
       void renderScene();
       void cleanup();
@@ -392,15 +398,17 @@
       void createLogicalDevice(const vector<const char*>& validationLayers,
          const vector<const char*>& deviceExtensions);
+      void chooseSwapChainProperties();
       void createSwapChain();
       void createImageViews();
       void createRenderPass();
-      VkFormat findDepthFormat();
+      VkFormat findDepthFormat(); // TODO: Declare/define (in the cpp file) this function in some util functions section
+      void createResourceCommandPool();
       void createCommandPool();
       void createImageResources();
-
-      void createTextureSampler();
       void createFramebuffers();
       void createCommandBuffers();
       void createSyncObjects();
+
+      void createTextureSampler();
 
       void createImguiDescriptorPool();
