Index: main-vulkan.cpp
===================================================================
--- main-vulkan.cpp	(revision 603b5bc69c413a1767dc42b7921374fc1c992f31)
+++ main-vulkan.cpp	(revision 34bdf3ab3957de6744017a27609ea5f1be36d7ae)
@@ -17,7 +17,9 @@
 
 int __main(int argc, char* argv[]) {
+   const int MAX_FRAMES_IN_FLIGHT = 2;
+
    cout << "Starting Vulkan Game..." << endl;
 
-   VulkanGame game;
+   VulkanGame game(MAX_FRAMES_IN_FLIGHT);
 
    try {
Index: vulkan-game.cpp
===================================================================
--- vulkan-game.cpp	(revision 603b5bc69c413a1767dc42b7921374fc1c992f31)
+++ vulkan-game.cpp	(revision 34bdf3ab3957de6744017a27609ea5f1be36d7ae)
@@ -18,5 +18,5 @@
 };
 
-VulkanGame::VulkanGame() {
+VulkanGame::VulkanGame(int maxFramesInFlight) : MAX_FRAMES_IN_FLIGHT(maxFramesInFlight) {
    gui = nullptr;
    window = nullptr;
@@ -169,10 +169,12 @@
    graphicsPipelines.back().createDescriptorSets(swapChainImages);
 
-   createCommandBuffers();
-
    // TODO: Creating the descriptor pool and descriptor sets might need to be redone when the
    // swap chain is recreated
 
    cout << "Created " << graphicsPipelines.size() << " graphics pipelines" << endl;
+
+   createCommandBuffers();
+
+   createSyncObjects();
 }
 
@@ -250,4 +252,10 @@
    }
 
+   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, commandPool, nullptr);
    vkDestroyDevice(device, nullptr);
@@ -741,4 +749,25 @@
 }
 
+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!");
+      }
+   }
+}
+
 void VulkanGame::cleanupSwapChain() {
    VulkanUtils::destroyVulkanImage(device, depthImage);
Index: vulkan-game.hpp
===================================================================
--- vulkan-game.hpp	(revision 603b5bc69c413a1767dc42b7921374fc1c992f31)
+++ vulkan-game.hpp	(revision 34bdf3ab3957de6744017a27609ea5f1be36d7ae)
@@ -30,5 +30,5 @@
 class VulkanGame {
    public:
-      VulkanGame();
+      VulkanGame(int maxFramesInFlight);
       ~VulkanGame();
 
@@ -36,4 +36,6 @@
 
    private:
+      const int MAX_FRAMES_IN_FLIGHT;
+
       GameGui* gui;
 
@@ -85,4 +87,8 @@
       VkDescriptorImageInfo sdlOverlayImageDescriptor;
 
+      vector<VkSemaphore> imageAvailableSemaphores;
+      vector<VkSemaphore> renderFinishedSemaphores;
+      vector<VkFence> inFlightFences;
+
       bool framebufferResized = false;
 
@@ -114,4 +120,5 @@
       void createUniformBuffers();
       void createCommandBuffers();
+      void createSyncObjects();
 
       void cleanupSwapChain();
Index: vulkan-ref.cpp
===================================================================
--- vulkan-ref.cpp	(revision 603b5bc69c413a1767dc42b7921374fc1c992f31)
+++ vulkan-ref.cpp	(revision 34bdf3ab3957de6744017a27609ea5f1be36d7ae)
@@ -27,4 +27,5 @@
 using namespace glm;
 
+/*** START OF REFACTORED CODE ***/
 const int SCREEN_WIDTH = 800;
 const int SCREEN_HEIGHT = 600;
@@ -32,5 +33,4 @@
 const int MAX_FRAMES_IN_FLIGHT = 2;
 
-/*** START OF REFACTORED CODE ***/
 #ifdef NDEBUG
    const bool enableValidationLayers = false;
@@ -219,9 +219,9 @@
       GraphicsPipelineInfo scenePipeline;
       GraphicsPipelineInfo overlayPipeline;
-/*** END OF REFACTORED CODE ***/
 
       vector<VkSemaphore> imageAvailableSemaphores;
       vector<VkSemaphore> renderFinishedSemaphores;
       vector<VkFence> inFlightFences;
+/*** END OF REFACTORED CODE ***/
 
       size_t currentFrame = 0;
@@ -400,5 +400,4 @@
 
          createBufferResources();
-/*** END OF REFACTORED CODE ***/
 
          createSyncObjects();
@@ -475,5 +474,4 @@
       }
 
-/*** START OF REFACTORED CODE ***/
       vector<const char*> getRequiredExtensions() {
          vector<const char*> extensions = gui->getRequiredExtensions();
@@ -1696,5 +1694,4 @@
 /*** START OF REFACTORED CODE ***/
       }
-/*** END OF REFACTORED CODE ***/
 
       void createSyncObjects() {
@@ -1718,4 +1715,5 @@
          }
       }
+/*** END OF REFACTORED CODE ***/
 
       bool addObjectToScene(GraphicsPipelineInfo& info,
@@ -1970,5 +1968,4 @@
          cleanupPipelineBuffers(scenePipeline);
          cleanupPipelineBuffers(overlayPipeline);
- /*** END OF REFACTORED CODE ***/
 
          for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
@@ -1978,5 +1975,4 @@
          }
 
-/*** START OF REFACTORED CODE ***/
          vkDestroyCommandPool(device, commandPool, nullptr);
          vkDestroyDevice(device, nullptr);
