Changeset ce9dc9f in opengl-game for sdl-game.cpp


Ignore:
Timestamp:
Jan 24, 2021, 6:15:32 PM (4 years ago)
Author:
Dmitry Portnoy <dportnoy@…>
Branches:
feature/imgui-sdl
Children:
8b823e7
Parents:
3f32dfd
Message:

Remove all dependencies on VulkanH functions and structures from SDLGame

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sdl-game.cpp

    r3f32dfd rce9dc9f  
    11#include "sdl-game.hpp"
    22
     3#include <array>
    34#include <iostream>
    45#include <set>
    56#include <stdexcept>
    67
     8#include <stdlib.h>         // abort (only used in check_vk_result)
     9
     10#include <SDL2/SDL_vulkan.h>
     11
    712#include "IMGUI/imgui_impl_sdl.h"
    813
    9 #include <stdio.h>          // printf, fprintf
    10 #include <stdlib.h>         // abort
    11 
    12 // dear imgui: standalone example application for SDL2 + Vulkan
    13 // If you are new to dear imgui, see examples/README.txt and documentation at the top of imgui.cpp.
    14 
    15 // Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
    16 // - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
    17 //   You will use those if you want to use this rendering back-end in your engine/app.
    18 // - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
    19 //   the back-end itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
    20 // Read comments in imgui_impl_vulkan.h.
    21 
    22 #include <SDL2/SDL_vulkan.h>
    23 
    2414#include "logger.hpp"
    2515
    26 #include "vulkan-utils.hpp"
    27 
    2816using namespace std;
    2917
    30 //#define IMGUI_UNLIMITED_FRAME_RATE
    31 
    32 static VkAllocationCallbacks* g_Allocator = NULL;
    33 static VkInstance               g_Instance = VK_NULL_HANDLE;
    34 static VkPhysicalDevice         g_PhysicalDevice = VK_NULL_HANDLE;
    35 static VkDevice                 g_Device = VK_NULL_HANDLE;
    36 static VkQueue                  g_GraphicsQueue = VK_NULL_HANDLE;
    37 static VkQueue                  g_PresentQueue = VK_NULL_HANDLE;
    38 static VkPipelineCache          g_PipelineCache = VK_NULL_HANDLE;
    39 
    40 static ImGui_ImplVulkanH_Window g_MainWindowData;
    41 static uint32_t                 g_MinImageCount = 2;
    42 static bool                     g_SwapChainRebuild = false;
    43 
    44 static void check_vk_result(VkResult err)
    45 {
    46    if (err == 0)
     18#define IMGUI_UNLIMITED_FRAME_RATE
     19
     20static bool g_SwapChainRebuild = false;
     21
     22static void check_vk_result(VkResult err) {
     23   if (err == 0) {
    4724      return;
     25   }
    4826   fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err);
    49    if (err < 0)
     27   if (err < 0) {
    5028      abort();
    51 }
    52 
    53 // All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo.
    54 // Your real engine/app may not use them.
    55 
    56 static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, SDL_Window* window) {
    57    // TODO: SetupVulkanWIndow calls vkGetPhysicalDeviceSurfaceSupportKHR to get the present queue. In vulkan-game, I do this in findQueueFamilies.
    58    int width, height;
    59    SDL_GetWindowSize(window, &width, &height);
    60 
    61    wd->Surface = surface;
    62 
    63    // Select Surface Format
    64    const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM };
    65    const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
    66    wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), requestSurfaceColorSpace);
    67 
    68    // Select Present Mode
    69 #ifdef IMGUI_UNLIMITED_FRAME_RATE
    70    VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR };
    71 #else
    72    VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR };
    73 #endif
    74    wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(g_PhysicalDevice, wd->Surface, &present_modes[0], IM_ARRAYSIZE(present_modes));
    75    //printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
    76 
    77    // Create SwapChain, RenderPass, Framebuffer, etc.
    78    IM_ASSERT(g_MinImageCount >= 2);
    79 
    80    QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(g_PhysicalDevice, surface);
    81 
    82    ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, indices.graphicsFamily.value(),
    83       g_Allocator, width, height, g_MinImageCount);
    84 }
    85 
    86 static void CleanupVulkanWindow()
    87 {
    88    ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
    89 }
    90 
    91 static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data)
    92 {
    93    VkResult err;
    94 
    95    VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore;
    96    VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
    97    err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex);
    98    if (err == VK_ERROR_OUT_OF_DATE_KHR)
    99    {
     29   }
     30}
     31
     32void VulkanGame::FrameRender(ImDrawData* draw_data) {
     33   VkResult result = vkAcquireNextImageKHR(device, swapChain, numeric_limits<uint64_t>::max(),
     34      imageAcquiredSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
     35
     36   if (result == VK_ERROR_OUT_OF_DATE_KHR) {
    10037      g_SwapChainRebuild = true;
    10138      return;
    102    }
    103    check_vk_result(err);
    104 
    105    ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex];
    106    {
    107       err = vkWaitForFences(g_Device, 1, &fd->Fence, VK_TRUE, UINT64_MAX);    // wait indefinitely instead of periodically checking
    108       check_vk_result(err);
    109 
    110       err = vkResetFences(g_Device, 1, &fd->Fence);
    111       check_vk_result(err);
    112    }
    113    {
    114       err = vkResetCommandPool(g_Device, fd->CommandPool, 0);
    115       check_vk_result(err);
    116       VkCommandBufferBeginInfo info = {};
    117       info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    118       info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
    119       err = vkBeginCommandBuffer(fd->CommandBuffer, &info);
    120       check_vk_result(err);
    121    }
    122    {
    123       VkRenderPassBeginInfo info = {};
    124       info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
    125       info.renderPass = wd->RenderPass;
    126       info.framebuffer = fd->Framebuffer;
    127       info.renderArea.extent.width = wd->Width;
    128       info.renderArea.extent.height = wd->Height;
    129       info.clearValueCount = 1;
    130       info.pClearValues = &wd->ClearValue;
    131       vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
    132    }
     39   } else if (result != VK_SUCCESS) {
     40      throw runtime_error("failed to acquire swap chain image!");
     41   }
     42
     43   if (vkWaitForFences(device, 1, &inFlightFences[imageIndex], VK_TRUE, numeric_limits<uint64_t>::max()) != VK_SUCCESS) {
     44      throw runtime_error("failed waiting for fence!");
     45   }
     46   if (vkResetFences(device, 1, &inFlightFences[imageIndex]) != VK_SUCCESS) {
     47      throw runtime_error("failed to reset fence!");
     48   }
     49
     50   // START OF NEW CODE
     51   // I don't have analogous code in vulkan-game right now because I record command buffers once
     52   // before the render loop ever starts. I should change this
     53
     54   result = vkResetCommandPool(device, commandPools[imageIndex], 0);
     55   check_vk_result(result);
     56   VkCommandBufferBeginInfo info = {};
     57   info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
     58   info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
     59   result = vkBeginCommandBuffer(commandBuffers[imageIndex], &info);
     60   check_vk_result(result);
     61
     62   VkRenderPassBeginInfo renderPassInfo = {};
     63   renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
     64   renderPassInfo.renderPass = renderPass;
     65   renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex];
     66   renderPassInfo.renderArea.extent = swapChainExtent;
     67
     68   array<VkClearValue, 2> clearValues = {};
     69   clearValues[0].color = { { 0.45f, 0.55f, 0.60f, 1.00f } };
     70   clearValues[1].depthStencil = { 1.0f, 0 };
     71
     72   renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
     73   renderPassInfo.pClearValues = clearValues.data();
     74
     75   vkCmdBeginRenderPass(commandBuffers[imageIndex], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
    13376
    13477   // Record dear imgui primitives into command buffer
    135    ImGui_ImplVulkan_RenderDrawData(draw_data, fd->CommandBuffer);
     78   ImGui_ImplVulkan_RenderDrawData(draw_data, commandBuffers[imageIndex]);
    13679
    13780   // Submit command buffer
    138    vkCmdEndRenderPass(fd->CommandBuffer);
    139    {
    140       VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    141       VkSubmitInfo info = {};
    142       info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    143       info.waitSemaphoreCount = 1;
    144       info.pWaitSemaphores = &image_acquired_semaphore;
    145       info.pWaitDstStageMask = &wait_stage;
    146       info.commandBufferCount = 1;
    147       info.pCommandBuffers = &fd->CommandBuffer;
    148       info.signalSemaphoreCount = 1;
    149       info.pSignalSemaphores = &render_complete_semaphore;
    150 
    151       err = vkEndCommandBuffer(fd->CommandBuffer);
    152       check_vk_result(err);
    153       err = vkQueueSubmit(g_GraphicsQueue, 1, &info, fd->Fence);
    154       check_vk_result(err);
    155    }
    156 }
    157 
    158 static void FramePresent(ImGui_ImplVulkanH_Window* wd)
    159 {
     81   vkCmdEndRenderPass(commandBuffers[imageIndex]);
     82
     83   if (vkEndCommandBuffer(commandBuffers[imageIndex]) != VK_SUCCESS) {
     84      throw runtime_error("failed to record command buffer!");
     85   }
     86
     87   // END OF NEW CODE
     88
     89   VkSemaphore waitSemaphores[] = { imageAcquiredSemaphores[currentFrame] };
     90   VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
     91   VkSemaphore signalSemaphores[] = { renderCompleteSemaphores[currentFrame] };
     92
     93   VkSubmitInfo submitInfo = {};
     94   submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
     95   submitInfo.waitSemaphoreCount = 1;
     96   submitInfo.pWaitSemaphores = waitSemaphores;
     97   submitInfo.pWaitDstStageMask = &wait_stage;
     98   submitInfo.commandBufferCount = 1;
     99   submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
     100   submitInfo.signalSemaphoreCount = 1;
     101   submitInfo.pSignalSemaphores = signalSemaphores;
     102
     103   if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[imageIndex]) != VK_SUCCESS) {
     104      throw runtime_error("failed to submit draw command buffer!");
     105   }
     106}
     107
     108void VulkanGame::FramePresent() {
    160109   if (g_SwapChainRebuild)
    161110      return;
    162    VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
    163    VkPresentInfoKHR info = {};
    164    info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
    165    info.waitSemaphoreCount = 1;
    166    info.pWaitSemaphores = &render_complete_semaphore;
    167    info.swapchainCount = 1;
    168    info.pSwapchains = &wd->Swapchain;
    169    info.pImageIndices = &wd->FrameIndex;
    170    VkResult err = vkQueuePresentKHR(g_PresentQueue, &info);
    171    if (err == VK_ERROR_OUT_OF_DATE_KHR)
    172    {
     111
     112   VkSemaphore signalSemaphores[] = { renderCompleteSemaphores[currentFrame] };
     113
     114   VkPresentInfoKHR presentInfo = {};
     115   presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
     116   presentInfo.waitSemaphoreCount = 1;
     117   presentInfo.pWaitSemaphores = signalSemaphores;
     118   presentInfo.swapchainCount = 1;
     119   presentInfo.pSwapchains = &swapChain;
     120   presentInfo.pImageIndices = &imageIndex;
     121   presentInfo.pResults = nullptr;
     122
     123   VkResult result = vkQueuePresentKHR(presentQueue, &presentInfo);
     124
     125   // In vulkan-game, I also handle VK_SUBOPTIMAL_KHR and framebufferResized. g_SwapChainRebuild is kind of similar
     126   // to framebufferResized, but not quite the same
     127   if (result == VK_ERROR_OUT_OF_DATE_KHR) {
    173128      g_SwapChainRebuild = true;
    174129      return;
    175    }
    176    check_vk_result(err);
    177    wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->ImageCount; // Now we can use the next set of semaphores
     130   } else if (result != VK_SUCCESS) {
     131      throw runtime_error("failed to present swap chain image!");
     132   }
     133
     134   currentFrame = (currentFrame + 1) % swapChainImageCount;
    178135}
    179136
     
    190147}
    191148
    192 VulkanGame::VulkanGame(int maxFramesInFlight) : MAX_FRAMES_IN_FLIGHT(maxFramesInFlight) {
     149VulkanGame::VulkanGame() {
     150   // TODO: Double-check whether initialization should happen in the header, where the variables are declared, or here
     151   // Also, decide whether to use this-> for all instance variables, or only when necessary
     152
     153   this->debugMessenger = VK_NULL_HANDLE;
     154
    193155   this->gui = nullptr;
    194156   this->window = nullptr;
     157
     158   this->swapChainPresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
     159   this->swapChainMinImageCount = 0;
    195160}
    196161
     
    208173
    209174   initVulkan();
    210 
    211    VkResult err;
    212 
    213    // Create Framebuffers
    214    ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
    215    SetupVulkanWindow(wd, surface, window);
    216175
    217176   // Create Descriptor Pool
     
    237196      pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes);
    238197      pool_info.pPoolSizes = pool_sizes;
    239       err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &descriptorPool);
    240       check_vk_result(err);
    241    }
     198      check_vk_result(vkCreateDescriptorPool(device, &pool_info, nullptr, &descriptorPool));
     199   }
     200
     201   // TODO: Do this in one place and save it instead of redoing it every time I need a queue family index
     202   QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
    242203
    243204   // Setup Dear ImGui context
    244205   IMGUI_CHECKVERSION();
    245206   ImGui::CreateContext();
    246    ImGuiIO& io = ImGui::GetIO(); (void)io;
     207   ImGuiIO& io = ImGui::GetIO();
    247208   //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable Keyboard Controls
    248209   //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
     
    255216   ImGui_ImplSDL2_InitForVulkan(window);
    256217   ImGui_ImplVulkan_InitInfo init_info = {};
    257    init_info.Instance = g_Instance;
    258    init_info.PhysicalDevice = g_PhysicalDevice;
    259    init_info.Device = g_Device;
    260    init_info.PipelineCache = g_PipelineCache;
     218   init_info.Instance = instance;
     219   init_info.PhysicalDevice = physicalDevice;
     220   init_info.Device = device;
     221   init_info.QueueFamily = indices.graphicsFamily.value();
     222   init_info.Queue = graphicsQueue;
    261223   init_info.DescriptorPool = descriptorPool;
    262    init_info.Allocator = g_Allocator;
    263    init_info.MinImageCount = g_MinImageCount;
    264    init_info.ImageCount = wd->ImageCount;
     224   init_info.Allocator = nullptr;
     225   init_info.MinImageCount = swapChainMinImageCount;
     226   init_info.ImageCount = swapChainImageCount;
    265227   init_info.CheckVkResultFn = check_vk_result;
    266    ImGui_ImplVulkan_Init(&init_info, wd->RenderPass);
     228   ImGui_ImplVulkan_Init(&init_info, renderPass);
    267229
    268230   // Load Fonts
     
    279241   //io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f);
    280242   //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
    281    //IM_ASSERT(font != NULL);
     243   //assert(font != NULL);
    282244
    283245   // Upload Fonts
    284246   {
    285       // Use any command queue
    286       VkCommandPool command_pool = wd->Frames[wd->FrameIndex].CommandPool;
    287       VkCommandBuffer command_buffer = wd->Frames[wd->FrameIndex].CommandBuffer;
    288 
    289       err = vkResetCommandPool(g_Device, command_pool, 0);
    290       check_vk_result(err);
    291       VkCommandBufferBeginInfo begin_info = {};
    292       begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    293       begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
    294       err = vkBeginCommandBuffer(command_buffer, &begin_info);
    295       check_vk_result(err);
    296 
    297       ImGui_ImplVulkan_CreateFontsTexture(command_buffer);
    298 
    299       VkSubmitInfo end_info = {};
    300       end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    301       end_info.commandBufferCount = 1;
    302       end_info.pCommandBuffers = &command_buffer;
    303       err = vkEndCommandBuffer(command_buffer);
    304       check_vk_result(err);
    305       err = vkQueueSubmit(graphicsQueue, 1, &end_info, VK_NULL_HANDLE);
    306       check_vk_result(err);
    307 
    308       err = vkDeviceWaitIdle(g_Device);
    309       check_vk_result(err);
     247      VkCommandBuffer commandBuffer = VulkanUtils::beginSingleTimeCommands(device, resourceCommandPool);
     248
     249      ImGui_ImplVulkan_CreateFontsTexture(commandBuffer);
     250
     251      VulkanUtils::endSingleTimeCommands(device, resourceCommandPool, commandBuffer, graphicsQueue);
     252
    310253      ImGui_ImplVulkan_DestroyFontUploadObjects();
    311254   }
     
    314257   bool show_demo_window = true;
    315258   bool show_another_window = false;
    316    ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
    317259
    318260   // Main loop
     
    337279         int width, height;
    338280         SDL_GetWindowSize(window, &width, &height);
    339          if (width > 0 && height > 0)
    340          {
    341             ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
    342 
    343             QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(g_PhysicalDevice, surface);
    344 
    345             ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData,
    346                indices.graphicsFamily.value(), g_Allocator, width, height, g_MinImageCount);
    347             g_MainWindowData.FrameIndex = 0;
     281         if (width > 0 && height > 0) {
     282            // TODO: This should be used if the min image count changes, presumably because a new surface was created
     283            // with a different image count or something like that. Maybe I want to add code to query for a new min image count
     284            // during swapchain recreation to take advantage of this
     285            ImGui_ImplVulkan_SetMinImageCount(swapChainMinImageCount);
     286
     287            recreateSwapChain();
     288
     289            imageIndex = 0;
    348290            g_SwapChainRebuild = false;
    349291         }
     
    361303      // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
    362304      {
    363          static float f = 0.0f;
    364305         static int counter = 0;
    365306
     
    369310         ImGui::Checkbox("Demo Window", &show_demo_window);      // Edit bools storing our window open/close state
    370311         ImGui::Checkbox("Another Window", &show_another_window);
    371 
    372          ImGui::SliderFloat("float", &f, 0.0f, 1.0f);            // Edit 1 float using a slider from 0.0f to 1.0f
    373          ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
    374312
    375313         if (ImGui::Button("Button"))                            // Buttons return true when clicked (most widgets return true when edited/activated)
     
    396334      ImDrawData* draw_data = ImGui::GetDrawData();
    397335      const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f);
    398       if (!is_minimized)
    399       {
    400          memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float));
    401          FrameRender(wd, draw_data);
    402          FramePresent(wd);
    403       }
    404    }
    405 
    406    // Cleanup
    407    err = vkDeviceWaitIdle(g_Device);
    408    check_vk_result(err);
    409    ImGui_ImplVulkan_Shutdown();
    410    ImGui_ImplSDL2_Shutdown();
    411    ImGui::DestroyContext();
    412 
    413    CleanupVulkanWindow();
     336      if (!is_minimized) {
     337         FrameRender(draw_data);
     338         FramePresent();
     339      }
     340   }
     341
    414342   cleanup();
    415343
     
    481409   pickPhysicalDevice(deviceExtensions);
    482410   createLogicalDevice(validationLayers, deviceExtensions);
     411   chooseSwapChainProperties();
     412   createSwapChain();
     413   createImageViews();
     414   createRenderPass();
     415   createResourceCommandPool();
     416
     417   createCommandPools();
     418
     419   VulkanUtils::createDepthImage(device, physicalDevice, resourceCommandPool, findDepthFormat(), swapChainExtent,
     420      depthImage, graphicsQueue);
     421
     422   createFramebuffers();
     423
     424   // TODO: Initialize pipelines here
     425
     426   createCommandBuffers();
     427
     428   createSyncObjects();
    483429}
    484430
    485431void VulkanGame::cleanup() {
    486    vkDestroyDescriptorPool(g_Device, descriptorPool, g_Allocator);
     432   // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals)
     433    //vkQueueWaitIdle(g_Queue);
     434   if (vkDeviceWaitIdle(device) != VK_SUCCESS) {
     435      throw runtime_error("failed to wait for device!");
     436   }
     437
     438   ImGui_ImplVulkan_Shutdown();
     439   ImGui_ImplSDL2_Shutdown();
     440   ImGui::DestroyContext();
     441
     442   cleanupSwapChain();
     443
     444   // this would actually be destroyed in the pipeline class
     445   vkDestroyDescriptorPool(device, descriptorPool, nullptr);
     446
     447   vkDestroyCommandPool(device, resourceCommandPool, nullptr);
     448
     449   vkDestroyDevice(device, nullptr);
     450   vkDestroySurfaceKHR(instance, surface, nullptr);
    487451
    488452   if (ENABLE_VALIDATION_LAYERS) {
    489       VulkanUtils::destroyDebugUtilsMessengerEXT(g_Instance, debugMessenger, nullptr);
    490    }
    491 
    492    vkDestroyDevice(g_Device, g_Allocator);
    493    vkDestroyInstance(g_Instance, g_Allocator);
     453      VulkanUtils::destroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
     454   }
     455
     456   vkDestroyInstance(instance, nullptr);
    494457
    495458   gui->destroyWindow();
     
    536499      populateDebugMessengerCreateInfo(debugCreateInfo);
    537500      createInfo.pNext = &debugCreateInfo;
    538    } else {
     501   }
     502   else {
    539503      createInfo.enabledLayerCount = 0;
    540504
     
    542506   }
    543507
    544    if (vkCreateInstance(&createInfo, nullptr, &g_Instance) != VK_SUCCESS) {
     508   if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
    545509      throw runtime_error("failed to create instance!");
    546510   }
     
    555519   populateDebugMessengerCreateInfo(createInfo);
    556520
    557    if (VulkanUtils::createDebugUtilsMessengerEXT(g_Instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
     521   if (VulkanUtils::createDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
    558522      throw runtime_error("failed to set up debug messenger!");
    559523   }
     
    569533
    570534void VulkanGame::createVulkanSurface() {
    571    if (gui->createVulkanSurface(g_Instance, &surface) == RTWO_ERROR) {
     535   if (gui->createVulkanSurface(instance, &surface) == RTWO_ERROR) {
    572536      throw runtime_error("failed to create window surface!");
    573537   }
     
    577541   uint32_t deviceCount = 0;
    578542   // TODO: Check VkResult
    579    vkEnumeratePhysicalDevices(g_Instance, &deviceCount, nullptr);
     543   vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
    580544
    581545   if (deviceCount == 0) {
     
    585549   vector<VkPhysicalDevice> devices(deviceCount);
    586550   // TODO: Check VkResult
    587    vkEnumeratePhysicalDevices(g_Instance, &deviceCount, devices.data());
     551   vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
    588552
    589553   cout << endl << "Graphics cards:" << endl;
    590554   for (const VkPhysicalDevice& device : devices) {
    591555      if (isDeviceSuitable(device, deviceExtensions)) {
    592          g_PhysicalDevice = device;
     556         physicalDevice = device;
    593557         break;
    594558      }
     
    596560   cout << endl;
    597561
    598    if (g_PhysicalDevice == VK_NULL_HANDLE) {
     562   if (physicalDevice == VK_NULL_HANDLE) {
    599563      throw runtime_error("failed to find a suitable GPU!");
    600564   }
     
    612576
    613577   if (extensionsSupported) {
    614       SwapChainSupportDetails swapChainSupport = VulkanUtils::querySwapChainSupport(physicalDevice, surface);
    615       swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
     578      vector<VkSurfaceFormatKHR> formats = VulkanUtils::querySwapChainFormats(physicalDevice, surface);
     579      vector<VkPresentModeKHR> presentModes = VulkanUtils::querySwapChainPresentModes(physicalDevice, surface);
     580
     581      swapChainAdequate = !formats.empty() && !presentModes.empty();
    616582   }
    617583
     
    623589
    624590void VulkanGame::createLogicalDevice(const vector<const char*>& validationLayers,
    625       const vector<const char*>& deviceExtensions) {
    626    QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(g_PhysicalDevice, surface);
     591   const vector<const char*>& deviceExtensions) {
     592   QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
    627593
    628594   if (!indices.isComplete()) {
     
    666632      createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
    667633      createInfo.ppEnabledLayerNames = validationLayers.data();
    668    } else {
     634   }
     635   else {
    669636      createInfo.enabledLayerCount = 0;
    670637   }
    671638
    672    if (vkCreateDevice(g_PhysicalDevice, &createInfo, nullptr, &g_Device) != VK_SUCCESS) {
     639   if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
    673640      throw runtime_error("failed to create logical device!");
    674641   }
    675642
    676    vkGetDeviceQueue(g_Device, indices.graphicsFamily.value(), 0, &graphicsQueue);
    677    vkGetDeviceQueue(g_Device, indices.presentFamily.value(), 0, &presentQueue);
    678 
    679    g_GraphicsQueue = graphicsQueue;
    680    g_PresentQueue = presentQueue;
     643   vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
     644   vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
     645}
     646
     647void VulkanGame::chooseSwapChainProperties() {
     648   vector<VkSurfaceFormatKHR> availableFormats = VulkanUtils::querySwapChainFormats(physicalDevice, surface);
     649   vector<VkPresentModeKHR> availablePresentModes = VulkanUtils::querySwapChainPresentModes(physicalDevice, surface);
     650
     651   // Per Spec Format and View Format are expected to be the same unless VK_IMAGE_CREATE_MUTABLE_BIT was set at image creation
     652   // Assuming that the default behavior is without setting this bit, there is no need for separate Swapchain image and image view format
     653   // Additionally several new color spaces were introduced with Vulkan Spec v1.0.40,
     654   // hence we must make sure that a format with the mostly available color space, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, is found and used.
     655   swapChainSurfaceFormat = VulkanUtils::chooseSwapSurfaceFormat(availableFormats,
     656      { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM },
     657      VK_COLOR_SPACE_SRGB_NONLINEAR_KHR);
     658
     659#ifdef IMGUI_UNLIMITED_FRAME_RATE
     660   vector<VkPresentModeKHR> presentModes{
     661      VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR
     662   };
     663#else
     664   vector<VkPresentModeKHR> presentModes{ VK_PRESENT_MODE_FIFO_KHR };
     665#endif
     666
     667   swapChainPresentMode = VulkanUtils::chooseSwapPresentMode(availablePresentModes, presentModes);
     668
     669   cout << "[vulkan] Selected PresentMode = " << swapChainPresentMode << endl;
     670
     671   VkSurfaceCapabilitiesKHR capabilities = VulkanUtils::querySwapChainCapabilities(physicalDevice, surface);
     672
     673   // If min image count was not specified, request different count of images dependent on selected present mode
     674   if (swapChainMinImageCount == 0) {
     675      if (swapChainPresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
     676         swapChainMinImageCount = 3;
     677      }
     678      else if (swapChainPresentMode == VK_PRESENT_MODE_FIFO_KHR || swapChainPresentMode == VK_PRESENT_MODE_FIFO_RELAXED_KHR) {
     679         swapChainMinImageCount = 2;
     680      }
     681      else if (swapChainPresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
     682         swapChainMinImageCount = 1;
     683      }
     684      else {
     685         throw runtime_error("unexpected present mode!");
     686      }
     687   }
     688
     689   if (swapChainMinImageCount < capabilities.minImageCount) {
     690      swapChainMinImageCount = capabilities.minImageCount;
     691   }
     692   else if (capabilities.maxImageCount != 0 && swapChainMinImageCount > capabilities.maxImageCount) {
     693      swapChainMinImageCount = capabilities.maxImageCount;
     694   }
     695}
     696
     697void VulkanGame::createSwapChain() {
     698   VkSurfaceCapabilitiesKHR capabilities = VulkanUtils::querySwapChainCapabilities(physicalDevice, surface);
     699
     700   swapChainExtent = VulkanUtils::chooseSwapExtent(capabilities, gui->getWindowWidth(), gui->getWindowHeight());
     701
     702   VkSwapchainCreateInfoKHR createInfo = {};
     703   createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
     704   createInfo.surface = surface;
     705   createInfo.minImageCount = swapChainMinImageCount;
     706   createInfo.imageFormat = swapChainSurfaceFormat.format;
     707   createInfo.imageColorSpace = swapChainSurfaceFormat.colorSpace;
     708   createInfo.imageExtent = swapChainExtent;
     709   createInfo.imageArrayLayers = 1;
     710   createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
     711
     712   // TODO: Maybe save this result so I don't have to recalculate it every time
     713   QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
     714   uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value() };
     715
     716   if (indices.graphicsFamily != indices.presentFamily) {
     717      createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
     718      createInfo.queueFamilyIndexCount = 2;
     719      createInfo.pQueueFamilyIndices = queueFamilyIndices;
     720   }
     721   else {
     722      createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
     723      createInfo.queueFamilyIndexCount = 0;
     724      createInfo.pQueueFamilyIndices = nullptr;
     725   }
     726
     727   createInfo.preTransform = capabilities.currentTransform;
     728   createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
     729   createInfo.presentMode = swapChainPresentMode;
     730   createInfo.clipped = VK_TRUE;
     731   createInfo.oldSwapchain = VK_NULL_HANDLE;
     732
     733   if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
     734      throw runtime_error("failed to create swap chain!");
     735   }
     736
     737   if (vkGetSwapchainImagesKHR(device, swapChain, &swapChainImageCount, nullptr) != VK_SUCCESS) {
     738      throw runtime_error("failed to get swap chain image count!");
     739   }
     740
     741   swapChainImages.resize(swapChainImageCount);
     742   if (vkGetSwapchainImagesKHR(device, swapChain, &swapChainImageCount, swapChainImages.data()) != VK_SUCCESS) {
     743      throw runtime_error("failed to get swap chain images!");
     744   }
     745}
     746
     747void VulkanGame::createImageViews() {
     748   swapChainImageViews.resize(swapChainImageCount);
     749
     750   for (uint32_t i = 0; i < swapChainImageViews.size(); i++) {
     751      swapChainImageViews[i] = VulkanUtils::createImageView(device, swapChainImages[i], swapChainSurfaceFormat.format,
     752         VK_IMAGE_ASPECT_COLOR_BIT);
     753   }
     754}
     755
     756void VulkanGame::createRenderPass() {
     757   VkAttachmentDescription colorAttachment = {};
     758   colorAttachment.format = swapChainSurfaceFormat.format;
     759   colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
     760   colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // Set to VK_ATTACHMENT_LOAD_OP_DONT_CARE to disable clearing
     761   colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
     762   colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
     763   colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
     764   colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
     765   colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
     766
     767   VkAttachmentReference colorAttachmentRef = {};
     768   colorAttachmentRef.attachment = 0;
     769   colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
     770
     771   VkAttachmentDescription depthAttachment = {};
     772   depthAttachment.format = findDepthFormat();
     773   depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
     774   depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
     775   depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
     776   depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
     777   depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
     778   depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
     779   depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
     780
     781   VkAttachmentReference depthAttachmentRef = {};
     782   depthAttachmentRef.attachment = 1;
     783   depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
     784
     785   VkSubpassDescription subpass = {};
     786   subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
     787   subpass.colorAttachmentCount = 1;
     788   subpass.pColorAttachments = &colorAttachmentRef;
     789   //subpass.pDepthStencilAttachment = &depthAttachmentRef;
     790
     791   VkSubpassDependency dependency = {};
     792   dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
     793   dependency.dstSubpass = 0;
     794   dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
     795   dependency.srcAccessMask = 0;
     796   dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
     797   dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
     798
     799   array<VkAttachmentDescription, 2> attachments = { colorAttachment, depthAttachment };
     800   VkRenderPassCreateInfo renderPassInfo = {};
     801   renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
     802   renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
     803   renderPassInfo.pAttachments = attachments.data();
     804   renderPassInfo.subpassCount = 1;
     805   renderPassInfo.pSubpasses = &subpass;
     806   renderPassInfo.dependencyCount = 1;
     807   renderPassInfo.pDependencies = &dependency;
     808
     809   if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
     810      throw runtime_error("failed to create render pass!");
     811   }
     812
     813   // We do not create a pipeline by default as this is also used by examples' main.cpp,
     814   // but secondary viewport in multi-viewport mode may want to create one with:
     815   //ImGui_ImplVulkan_CreatePipeline(device, g_Allocator, VK_NULL_HANDLE, g_MainWindowData.RenderPass, VK_SAMPLE_COUNT_1_BIT, &g_MainWindowData.Pipeline);
     816}
     817
     818VkFormat VulkanGame::findDepthFormat() {
     819   return VulkanUtils::findSupportedFormat(
     820      physicalDevice,
     821      { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },
     822      VK_IMAGE_TILING_OPTIMAL,
     823      VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
     824   );
     825}
     826
     827void VulkanGame::createResourceCommandPool() {
     828   QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
     829
     830   VkCommandPoolCreateInfo poolInfo = {};
     831   poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
     832   poolInfo.queueFamilyIndex = indices.graphicsFamily.value();
     833   poolInfo.flags = 0;
     834
     835   if (vkCreateCommandPool(device, &poolInfo, nullptr, &resourceCommandPool) != VK_SUCCESS) {
     836      throw runtime_error("failed to create resource command pool!");
     837   }
     838}
     839
     840void VulkanGame::createCommandPools() {
     841   commandPools.resize(swapChainImageCount);
     842
     843   QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
     844
     845   for (size_t i = 0; i < swapChainImageCount; i++) {
     846      VkCommandPoolCreateInfo poolInfo = {};
     847      poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
     848      poolInfo.queueFamilyIndex = indices.graphicsFamily.value();
     849      poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
     850      if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPools[i]) != VK_SUCCESS) {
     851         throw runtime_error("failed to create graphics command pool!");
     852      }
     853   }
     854}
     855
     856void VulkanGame::createFramebuffers() {
     857   swapChainFramebuffers.resize(swapChainImageCount);
     858
     859   VkFramebufferCreateInfo framebufferInfo = {};
     860   framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
     861   framebufferInfo.renderPass = renderPass;
     862   framebufferInfo.width = swapChainExtent.width;
     863   framebufferInfo.height = swapChainExtent.height;
     864   framebufferInfo.layers = 1;
     865
     866   for (size_t i = 0; i < swapChainImageCount; i++) {
     867      array<VkImageView, 2> attachments = {
     868         swapChainImageViews[i],
     869         depthImage.imageView
     870      };
     871
     872      framebufferInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
     873      framebufferInfo.pAttachments = attachments.data();
     874
     875      if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
     876         throw runtime_error("failed to create framebuffer!");
     877      }
     878   }
     879}
     880
     881void VulkanGame::createCommandBuffers() {
     882   commandBuffers.resize(swapChainImageCount);
     883
     884   for (size_t i = 0; i < swapChainImageCount; i++) {
     885      VkCommandBufferAllocateInfo allocInfo = {};
     886      allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
     887      allocInfo.commandPool = commandPools[i];
     888      allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
     889      allocInfo.commandBufferCount = 1;
     890
     891      if (vkAllocateCommandBuffers(device, &allocInfo, &commandBuffers[i]) != VK_SUCCESS) {
     892         throw runtime_error("failed to allocate command buffers!");
     893      }
     894   }
     895}
     896
     897void VulkanGame::createSyncObjects() {
     898   imageAcquiredSemaphores.resize(swapChainImageCount);
     899   renderCompleteSemaphores.resize(swapChainImageCount);
     900   inFlightFences.resize(swapChainImageCount);
     901
     902   VkSemaphoreCreateInfo semaphoreInfo = {};
     903   semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
     904
     905   VkFenceCreateInfo fenceInfo = {};
     906   fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
     907   fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
     908
     909   for (size_t i = 0; i < swapChainImageCount; i++) {
     910      if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAcquiredSemaphores[i]) != VK_SUCCESS) {
     911         throw runtime_error("failed to create image acquired sempahore for a frame!");
     912      }
     913
     914      if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderCompleteSemaphores[i]) != VK_SUCCESS) {
     915         throw runtime_error("failed to create render complete sempahore for a frame!");
     916      }
     917
     918      if (vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) {
     919         throw runtime_error("failed to create fence for a frame!");
     920      }
     921   }
     922}
     923
     924void VulkanGame::recreateSwapChain() {
     925   if (vkDeviceWaitIdle(device) != VK_SUCCESS) {
     926      throw runtime_error("failed to wait for device!");
     927   }
     928
     929   cleanupSwapChain();
     930
     931   createSwapChain();
     932   createImageViews();
     933   createRenderPass();
     934
     935   createCommandPools();
     936
     937   // The depth buffer does need to be recreated with the swap chain since its dimensions depend on the window size
     938   // and resizing the window is a common reason to recreate the swapchain
     939   VulkanUtils::createDepthImage(device, physicalDevice, resourceCommandPool, findDepthFormat(), swapChainExtent,
     940      depthImage, graphicsQueue);
     941
     942   createFramebuffers();
     943
     944   // TODO: Update pipelines here
     945
     946   createCommandBuffers();
     947
     948   createSyncObjects();
     949}
     950
     951void VulkanGame::cleanupSwapChain() {
     952   VulkanUtils::destroyVulkanImage(device, depthImage);
     953
     954   for (VkFramebuffer framebuffer : swapChainFramebuffers) {
     955      vkDestroyFramebuffer(device, framebuffer, nullptr);
     956   }
     957
     958   for (uint32_t i = 0; i < swapChainImageCount; i++) {
     959      vkFreeCommandBuffers(device, commandPools[i], 1, &commandBuffers[i]);
     960      vkDestroyCommandPool(device, commandPools[i], nullptr);
     961   }
     962
     963   for (uint32_t i = 0; i < swapChainImageCount; i++) {
     964      vkDestroySemaphore(device, imageAcquiredSemaphores[i], nullptr);
     965      vkDestroySemaphore(device, renderCompleteSemaphores[i], nullptr);
     966      vkDestroyFence(device, inFlightFences[i], nullptr);
     967   }
     968
     969   vkDestroyRenderPass(device, renderPass, nullptr);
     970
     971   for (VkImageView imageView : swapChainImageViews) {
     972      vkDestroyImageView(device, imageView, nullptr);
     973   }
     974
     975   vkDestroySwapchainKHR(device, swapChain, nullptr);
    681976}
    682977
    683978/********************************************** END OF NEW CODE **********************************************/
    684 
    685 /********************************************** START TEMP HELPER GUNVTIONS **********************************/
    686 
    687 // Forward Declarations
    688 void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd,
    689    const VkAllocationCallbacks* allocator);
    690 void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd,
    691    const VkAllocationCallbacks* allocator);
    692 void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device,
    693    ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
    694 
    695 // Create or resize window
    696 void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device,
    697       ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width,
    698       int height, uint32_t min_image_count) {
    699    (void)instance;
    700    ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
    701    ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
    702 }
    703 
    704 // Also destroy old swap chain and in-flight frames data, if any.
    705 void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device,
    706       ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count) {
    707    VkResult err;
    708    VkSwapchainKHR old_swapchain = wd->Swapchain;
    709    wd->Swapchain = NULL;
    710    err = vkDeviceWaitIdle(device);
    711    check_vk_result(err);
    712 
    713    // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one.
    714    // Destroy old Framebuffer
    715    for (uint32_t i = 0; i < wd->ImageCount; i++) {
    716       ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
    717       ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
    718    }
    719    IM_FREE(wd->Frames);
    720    IM_FREE(wd->FrameSemaphores);
    721    wd->Frames = NULL;
    722    wd->FrameSemaphores = NULL;
    723    wd->ImageCount = 0;
    724    if (wd->RenderPass) {
    725       vkDestroyRenderPass(device, wd->RenderPass, allocator);
    726    }
    727    if (wd->Pipeline) {
    728       vkDestroyPipeline(device, wd->Pipeline, allocator);
    729    }
    730 
    731    // If min image count was not specified, request different count of images dependent on selected present mode
    732    if (min_image_count == 0) {
    733       min_image_count = ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(wd->PresentMode);
    734    }
    735 
    736    // Create Swapchain
    737    {
    738       VkSwapchainCreateInfoKHR info = {};
    739       info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
    740       info.surface = wd->Surface;
    741       info.minImageCount = min_image_count;
    742       info.imageFormat = wd->SurfaceFormat.format;
    743       info.imageColorSpace = wd->SurfaceFormat.colorSpace;
    744       info.imageArrayLayers = 1;
    745       info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
    746       info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;           // Assume that graphics family == present family
    747       info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
    748       info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
    749       info.presentMode = wd->PresentMode;
    750       info.clipped = VK_TRUE;
    751       info.oldSwapchain = old_swapchain;
    752       VkSurfaceCapabilitiesKHR cap;
    753       err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, wd->Surface, &cap);
    754       check_vk_result(err);
    755       if (info.minImageCount < cap.minImageCount) {
    756          info.minImageCount = cap.minImageCount;
    757       } else if (cap.maxImageCount != 0 && info.minImageCount > cap.maxImageCount) {
    758          info.minImageCount = cap.maxImageCount;
    759       }
    760 
    761       if (cap.currentExtent.width == 0xffffffff) {
    762          info.imageExtent.width = wd->Width = w;
    763          info.imageExtent.height = wd->Height = h;
    764       } else {
    765          info.imageExtent.width = wd->Width = cap.currentExtent.width;
    766          info.imageExtent.height = wd->Height = cap.currentExtent.height;
    767       }
    768       err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain);
    769       check_vk_result(err);
    770       err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, NULL);
    771       check_vk_result(err);
    772       VkImage backbuffers[16] = {};
    773       IM_ASSERT(wd->ImageCount >= min_image_count);
    774       IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers));
    775       err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers);
    776       check_vk_result(err);
    777 
    778       IM_ASSERT(wd->Frames == NULL);
    779       wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount);
    780       wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->ImageCount);
    781       memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount);
    782       memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount);
    783       for (uint32_t i = 0; i < wd->ImageCount; i++) {
    784          wd->Frames[i].Backbuffer = backbuffers[i];
    785       }
    786    }
    787    if (old_swapchain) {
    788       vkDestroySwapchainKHR(device, old_swapchain, allocator);
    789    }
    790 
    791    // Create the Render Pass
    792    {
    793       VkAttachmentDescription attachment = {};
    794       attachment.format = wd->SurfaceFormat.format;
    795       attachment.samples = VK_SAMPLE_COUNT_1_BIT;
    796       attachment.loadOp = wd->ClearEnable ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    797       attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
    798       attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    799       attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
    800       attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    801       attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
    802       VkAttachmentReference color_attachment = {};
    803       color_attachment.attachment = 0;
    804       color_attachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
    805       VkSubpassDescription subpass = {};
    806       subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
    807       subpass.colorAttachmentCount = 1;
    808       subpass.pColorAttachments = &color_attachment;
    809       VkSubpassDependency dependency = {};
    810       dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    811       dependency.dstSubpass = 0;
    812       dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    813       dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    814       dependency.srcAccessMask = 0;
    815       dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    816       VkRenderPassCreateInfo info = {};
    817       info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
    818       info.attachmentCount = 1;
    819       info.pAttachments = &attachment;
    820       info.subpassCount = 1;
    821       info.pSubpasses = &subpass;
    822       info.dependencyCount = 1;
    823       info.pDependencies = &dependency;
    824       err = vkCreateRenderPass(device, &info, allocator, &wd->RenderPass);
    825       check_vk_result(err);
    826 
    827       // We do not create a pipeline by default as this is also used by examples' main.cpp,
    828       // but secondary viewport in multi-viewport mode may want to create one with:
    829       //ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline);
    830    }
    831 
    832    // Create The Image Views
    833    {
    834       VkImageViewCreateInfo info = {};
    835       info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
    836       info.viewType = VK_IMAGE_VIEW_TYPE_2D;
    837       info.format = wd->SurfaceFormat.format;
    838       info.components.r = VK_COMPONENT_SWIZZLE_R;
    839       info.components.g = VK_COMPONENT_SWIZZLE_G;
    840       info.components.b = VK_COMPONENT_SWIZZLE_B;
    841       info.components.a = VK_COMPONENT_SWIZZLE_A;
    842       VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
    843       info.subresourceRange = image_range;
    844       for (uint32_t i = 0; i < wd->ImageCount; i++) {
    845          ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
    846          info.image = fd->Backbuffer;
    847          err = vkCreateImageView(device, &info, allocator, &fd->BackbufferView);
    848          check_vk_result(err);
    849       }
    850    }
    851 
    852    // Create Framebuffer
    853    {
    854       VkImageView attachment[1];
    855       VkFramebufferCreateInfo info = {};
    856       info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
    857       info.renderPass = wd->RenderPass;
    858       info.attachmentCount = 1;
    859       info.pAttachments = attachment;
    860       info.width = wd->Width;
    861       info.height = wd->Height;
    862       info.layers = 1;
    863       for (uint32_t i = 0; i < wd->ImageCount; i++) {
    864          ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
    865          attachment[0] = fd->BackbufferView;
    866          err = vkCreateFramebuffer(device, &info, allocator, &fd->Framebuffer);
    867          check_vk_result(err);
    868       }
    869    }
    870 }
    871 
    872 /*********************************************** END TEMP HELPER GUNVTIONS ***********************************/
Note: See TracChangeset for help on using the changeset viewer.