Changeset 6493e43 in opengl-game for sdl-game.cpp


Ignore:
Timestamp:
Jan 3, 2021, 6:18:28 PM (4 years ago)
Author:
Dmitry Portnoy <dportnoy@…>
Branches:
feature/imgui-sdl
Children:
6a39266
Parents:
3b7d497
Message:

In sdl-game, add support for using separate graphics and present queues, and move the example ImGui code for (re)creating the swapchain into my own files

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sdl-game.cpp

    r3b7d497 r6493e43  
    44#include <set>
    55#include <stdexcept>
     6
     7#include "IMGUI/imgui_impl_sdl.h"
     8
     9#include <stdio.h>          // printf, fprintf
     10#include <stdlib.h>         // abort
    611
    712// dear imgui: standalone example application for SDL2 + Vulkan
     
    1520// Read comments in imgui_impl_vulkan.h.
    1621
    17 #include "IMGUI/imgui.h"
    18 #include "IMGUI/imgui_impl_sdl.h"
    19 #include "IMGUI/imgui_impl_vulkan.h"
    20 #include <stdio.h>          // printf, fprintf
    21 #include <stdlib.h>         // abort
    22 
    2322#include <SDL2/SDL_vulkan.h>
    2423
     
    3534static VkPhysicalDevice         g_PhysicalDevice = VK_NULL_HANDLE;
    3635static VkDevice                 g_Device = VK_NULL_HANDLE;
    37 static uint32_t                 g_QueueFamily = (uint32_t)-1;
    38 static VkQueue                  g_Queue = VK_NULL_HANDLE;
     36static VkQueue                  g_GraphicsQueue = VK_NULL_HANDLE;
     37static VkQueue                  g_PresentQueue = VK_NULL_HANDLE;
    3938static VkPipelineCache          g_PipelineCache = VK_NULL_HANDLE;
    40 static VkDescriptorPool         g_DescriptorPool = VK_NULL_HANDLE;
    4139
    4240static ImGui_ImplVulkanH_Window g_MainWindowData;
     
    5553// All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo.
    5654// Your real engine/app may not use them.
    57 static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height)
    58 {
     55
     56static 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
    5961   wd->Surface = surface;
    60 
    61    // Check for WSI support
    62    VkBool32 res;
    63    vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, wd->Surface, &res);
    64    if (res != VK_TRUE)
    65    {
    66       fprintf(stderr, "Error no WSI support on physical device 0\n");
    67       exit(-1);
    68    }
    6962
    7063   // Select Surface Format
     
    8477   // Create SwapChain, RenderPass, Framebuffer, etc.
    8578   IM_ASSERT(g_MinImageCount >= 2);
    86    ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
     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);
    8784}
    8885
     
    154151      err = vkEndCommandBuffer(fd->CommandBuffer);
    155152      check_vk_result(err);
    156       err = vkQueueSubmit(g_Queue, 1, &info, fd->Fence);
     153      err = vkQueueSubmit(g_GraphicsQueue, 1, &info, fd->Fence);
    157154      check_vk_result(err);
    158155   }
     
    171168   info.pSwapchains = &wd->Swapchain;
    172169   info.pImageIndices = &wd->FrameIndex;
    173    VkResult err = vkQueuePresentKHR(g_Queue, &info);
     170   VkResult err = vkQueuePresentKHR(g_PresentQueue, &info);
    174171   if (err == VK_ERROR_OUT_OF_DATE_KHR)
    175172   {
     
    212209   initVulkan();
    213210
     211   VkResult err;
     212
    214213   // Create Framebuffers
    215    int w, h;
    216    SDL_GetWindowSize(window, &w, &h);
    217214   ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
    218    // TODO: SetupVulkanWIndow calls vkGetPhysicalDeviceSurfaceSupportKHR to get the present queue. In vulkan-game, I do this in findQueueFamilies.
    219    SetupVulkanWindow(wd, surface, w, h);
    220 
    221    // TODO: Start from here. I've already reviewed everything before this
    222 
    223    // Setup Dear ImGui context
    224    IMGUI_CHECKVERSION();
    225    ImGui::CreateContext();
    226    ImGuiIO& io = ImGui::GetIO(); (void)io;
    227    //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable Keyboard Controls
    228    //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
    229 
    230    // Setup Dear ImGui style
    231    ImGui::StyleColorsDark();
    232    //ImGui::StyleColorsClassic();
    233 
    234    // Setup Platform/Renderer bindings
    235    ImGui_ImplSDL2_InitForVulkan(window);
    236    ImGui_ImplVulkan_InitInfo init_info = {};
    237    init_info.Instance = g_Instance;
    238    init_info.PhysicalDevice = g_PhysicalDevice;
    239    init_info.Device = g_Device;
    240    init_info.QueueFamily = g_QueueFamily;
    241    init_info.Queue = g_Queue;
    242    init_info.PipelineCache = g_PipelineCache;
    243    init_info.DescriptorPool = g_DescriptorPool;
    244    init_info.Allocator = g_Allocator;
    245    init_info.MinImageCount = g_MinImageCount;
    246    init_info.ImageCount = wd->ImageCount;
    247    init_info.CheckVkResultFn = check_vk_result;
    248    ImGui_ImplVulkan_Init(&init_info, wd->RenderPass);
    249 
    250    // Load Fonts
    251    // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
    252    // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
    253    // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
    254    // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
    255    // - Read 'docs/FONTS.md' for more instructions and details.
    256    // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
    257    //io.Fonts->AddFontDefault();
    258    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
    259    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
    260    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
    261    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f);
    262    //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
    263    //IM_ASSERT(font != NULL);
    264 
    265    VkResult err;
    266 
    267    // Upload Fonts
    268    {
    269       // Use any command queue
    270       VkCommandPool command_pool = wd->Frames[wd->FrameIndex].CommandPool;
    271       VkCommandBuffer command_buffer = wd->Frames[wd->FrameIndex].CommandBuffer;
    272 
    273       err = vkResetCommandPool(g_Device, command_pool, 0);
    274       check_vk_result(err);
    275       VkCommandBufferBeginInfo begin_info = {};
    276       begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    277       begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
    278       err = vkBeginCommandBuffer(command_buffer, &begin_info);
    279       check_vk_result(err);
    280 
    281       ImGui_ImplVulkan_CreateFontsTexture(command_buffer);
    282 
    283       VkSubmitInfo end_info = {};
    284       end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    285       end_info.commandBufferCount = 1;
    286       end_info.pCommandBuffers = &command_buffer;
    287       err = vkEndCommandBuffer(command_buffer);
    288       check_vk_result(err);
    289       err = vkQueueSubmit(g_Queue, 1, &end_info, VK_NULL_HANDLE);
    290       check_vk_result(err);
    291 
    292       err = vkDeviceWaitIdle(g_Device);
    293       check_vk_result(err);
    294       ImGui_ImplVulkan_DestroyFontUploadObjects();
    295    }
    296 
    297    // Our state
    298    bool show_demo_window = true;
    299    bool show_another_window = false;
    300    ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
    301 
    302    // Main loop
    303    bool done = false;
    304    while (!done) {
    305       // Poll and handle events (inputs, window resize, etc.)
    306       // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
    307       // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
    308       // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
    309       // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
    310       SDL_Event event;
    311       while (SDL_PollEvent(&event)) {
    312          ImGui_ImplSDL2_ProcessEvent(&event);
    313          if (event.type == SDL_QUIT)
    314             done = true;
    315          if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
    316             done = true;
    317       }
    318 
    319       // Resize swap chain?
    320       if (g_SwapChainRebuild) {
    321          int width, height;
    322          SDL_GetWindowSize(window, &width, &height);
    323          if (width > 0 && height > 0)
    324          {
    325             ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
    326             ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
    327             g_MainWindowData.FrameIndex = 0;
    328             g_SwapChainRebuild = false;
    329          }
    330       }
    331 
    332       // Start the Dear ImGui frame
    333       ImGui_ImplVulkan_NewFrame();
    334       ImGui_ImplSDL2_NewFrame(window);
    335       ImGui::NewFrame();
    336 
    337       // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
    338       if (show_demo_window)
    339          ImGui::ShowDemoWindow(&show_demo_window);
    340 
    341       // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
    342       {
    343          static float f = 0.0f;
    344          static int counter = 0;
    345 
    346          ImGui::Begin("Hello, world!");                          // Create a window called "Hello, world!" and append into it.
    347 
    348          ImGui::Text("This is some useful text.");               // Display some text (you can use a format strings too)
    349          ImGui::Checkbox("Demo Window", &show_demo_window);      // Edit bools storing our window open/close state
    350          ImGui::Checkbox("Another Window", &show_another_window);
    351 
    352          ImGui::SliderFloat("float", &f, 0.0f, 1.0f);            // Edit 1 float using a slider from 0.0f to 1.0f
    353          ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
    354 
    355          if (ImGui::Button("Button"))                            // Buttons return true when clicked (most widgets return true when edited/activated)
    356             counter++;
    357          ImGui::SameLine();
    358          ImGui::Text("counter = %d", counter);
    359 
    360          ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
    361          ImGui::End();
    362       }
    363 
    364       // 3. Show another simple window.
    365       if (show_another_window)
    366       {
    367          ImGui::Begin("Another Window", &show_another_window);   // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
    368          ImGui::Text("Hello from another window!");
    369          if (ImGui::Button("Close Me"))
    370             show_another_window = false;
    371          ImGui::End();
    372       }
    373 
    374       // Rendering
    375       ImGui::Render();
    376       ImDrawData* draw_data = ImGui::GetDrawData();
    377       const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f);
    378       if (!is_minimized)
    379       {
    380          memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float));
    381          FrameRender(wd, draw_data);
    382          FramePresent(wd);
    383       }
    384    }
    385 
    386    // Cleanup
    387    err = vkDeviceWaitIdle(g_Device);
    388    check_vk_result(err);
    389    ImGui_ImplVulkan_Shutdown();
    390    ImGui_ImplSDL2_Shutdown();
    391    ImGui::DestroyContext();
    392 
    393    CleanupVulkanWindow();
    394    cleanup();
    395 
    396    close_log();
    397 }
    398 
    399 bool VulkanGame::initUI(int width, int height, unsigned char guiFlags) {
    400    // TODO: Create a game-gui function to get the gui version and retrieve it that way
    401 
    402    SDL_VERSION(&sdlVersion); // This gets the compile-time version
    403    SDL_GetVersion(&sdlVersion); // This gets the runtime version
    404 
    405    cout << "SDL " <<
    406       to_string(sdlVersion.major) << "." <<
    407       to_string(sdlVersion.minor) << "." <<
    408       to_string(sdlVersion.patch) << endl;
    409 
    410    // TODO: Refactor the logger api to be more flexible,
    411    // esp. since gl_log() and gl_log_err() have issues printing anything besides strings
    412    restart_gl_log();
    413    gl_log("starting SDL\n%s.%s.%s",
    414       to_string(sdlVersion.major).c_str(),
    415       to_string(sdlVersion.minor).c_str(),
    416       to_string(sdlVersion.patch).c_str());
    417 
    418    // TODO: Use open_Log() and related functions instead of gl_log ones
    419    // TODO: In addition, delete the gl_log functions
    420    open_log();
    421    get_log() << "starting SDL" << endl;
    422    get_log() <<
    423       (int)sdlVersion.major << "." <<
    424       (int)sdlVersion.minor << "." <<
    425       (int)sdlVersion.patch << endl;
    426 
    427    // TODO: Put all fonts, textures, and images in the assets folder
    428    gui = new GameGui_SDL();
    429 
    430    if (gui->init() == RTWO_ERROR) {
    431       // TODO: Also print these sorts of errors to the log
    432       cout << "UI library could not be initialized!" << endl;
    433       cout << gui->getError() << endl;
    434       return RTWO_ERROR;
    435    }
    436 
    437    window = (SDL_Window*)gui->createWindow("Vulkan Game", width, height, guiFlags & GUI_FLAGS_WINDOW_FULLSCREEN);
    438    if (window == nullptr) {
    439       cout << "Window could not be created!" << endl;
    440       cout << gui->getError() << endl;
    441       return RTWO_ERROR;
    442    }
    443 
    444    cout << "Target window size: (" << width << ", " << height << ")" << endl;
    445    cout << "Actual window size: (" << gui->getWindowWidth() << ", " << gui->getWindowHeight() << ")" << endl;
    446 
    447    return RTWO_SUCCESS;
    448 }
    449 
    450 void VulkanGame::initVulkan() {
    451    const vector<const char*> validationLayers = {
    452       "VK_LAYER_KHRONOS_validation"
    453    };
    454    const vector<const char*> deviceExtensions = {
    455       VK_KHR_SWAPCHAIN_EXTENSION_NAME
    456    };
    457 
    458    createVulkanInstance(validationLayers);
    459    setupDebugMessenger();
    460    createVulkanSurface();
    461    pickPhysicalDevice(deviceExtensions);
    462    createLogicalDevice(validationLayers, deviceExtensions);
    463 
    464    VkResult err;
     215   SetupVulkanWindow(wd, surface, window);
    465216
    466217   // Create Descriptor Pool
     
    486237      pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes);
    487238      pool_info.pPoolSizes = pool_sizes;
    488       err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool);
    489       check_vk_result(err);
    490    }
     239      err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &descriptorPool);
     240      check_vk_result(err);
     241   }
     242
     243   // Setup Dear ImGui context
     244   IMGUI_CHECKVERSION();
     245   ImGui::CreateContext();
     246   ImGuiIO& io = ImGui::GetIO(); (void)io;
     247   //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable Keyboard Controls
     248   //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
     249
     250   // Setup Dear ImGui style
     251   ImGui::StyleColorsDark();
     252   //ImGui::StyleColorsClassic();
     253
     254   // Setup Platform/Renderer bindings
     255   ImGui_ImplSDL2_InitForVulkan(window);
     256   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;
     261   init_info.DescriptorPool = descriptorPool;
     262   init_info.Allocator = g_Allocator;
     263   init_info.MinImageCount = g_MinImageCount;
     264   init_info.ImageCount = wd->ImageCount;
     265   init_info.CheckVkResultFn = check_vk_result;
     266   ImGui_ImplVulkan_Init(&init_info, wd->RenderPass);
     267
     268   // Load Fonts
     269   // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
     270   // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
     271   // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
     272   // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
     273   // - Read 'docs/FONTS.md' for more instructions and details.
     274   // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
     275   //io.Fonts->AddFontDefault();
     276   //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
     277   //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
     278   //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
     279   //io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f);
     280   //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
     281   //IM_ASSERT(font != NULL);
     282
     283   // Upload Fonts
     284   {
     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);
     310      ImGui_ImplVulkan_DestroyFontUploadObjects();
     311   }
     312
     313   // Our state
     314   bool show_demo_window = true;
     315   bool show_another_window = false;
     316   ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
     317
     318   // Main loop
     319   bool done = false;
     320   while (!done) {
     321      // Poll and handle events (inputs, window resize, etc.)
     322      // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
     323      // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
     324      // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
     325      // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
     326      SDL_Event event;
     327      while (SDL_PollEvent(&event)) {
     328         ImGui_ImplSDL2_ProcessEvent(&event);
     329         if (event.type == SDL_QUIT)
     330            done = true;
     331         if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
     332            done = true;
     333      }
     334
     335      // Resize swap chain?
     336      if (g_SwapChainRebuild) {
     337         int width, height;
     338         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;
     348            g_SwapChainRebuild = false;
     349         }
     350      }
     351
     352      // Start the Dear ImGui frame
     353      ImGui_ImplVulkan_NewFrame();
     354      ImGui_ImplSDL2_NewFrame(window);
     355      ImGui::NewFrame();
     356
     357      // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
     358      if (show_demo_window)
     359         ImGui::ShowDemoWindow(&show_demo_window);
     360
     361      // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
     362      {
     363         static float f = 0.0f;
     364         static int counter = 0;
     365
     366         ImGui::Begin("Hello, world!");                          // Create a window called "Hello, world!" and append into it.
     367
     368         ImGui::Text("This is some useful text.");               // Display some text (you can use a format strings too)
     369         ImGui::Checkbox("Demo Window", &show_demo_window);      // Edit bools storing our window open/close state
     370         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
     374
     375         if (ImGui::Button("Button"))                            // Buttons return true when clicked (most widgets return true when edited/activated)
     376            counter++;
     377         ImGui::SameLine();
     378         ImGui::Text("counter = %d", counter);
     379
     380         ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
     381         ImGui::End();
     382      }
     383
     384      // 3. Show another simple window.
     385      if (show_another_window)
     386      {
     387         ImGui::Begin("Another Window", &show_another_window);   // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
     388         ImGui::Text("Hello from another window!");
     389         if (ImGui::Button("Close Me"))
     390            show_another_window = false;
     391         ImGui::End();
     392      }
     393
     394      // Rendering
     395      ImGui::Render();
     396      ImDrawData* draw_data = ImGui::GetDrawData();
     397      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();
     414   cleanup();
     415
     416   close_log();
     417}
     418
     419bool VulkanGame::initUI(int width, int height, unsigned char guiFlags) {
     420   // TODO: Create a game-gui function to get the gui version and retrieve it that way
     421
     422   SDL_VERSION(&sdlVersion); // This gets the compile-time version
     423   SDL_GetVersion(&sdlVersion); // This gets the runtime version
     424
     425   cout << "SDL " <<
     426      to_string(sdlVersion.major) << "." <<
     427      to_string(sdlVersion.minor) << "." <<
     428      to_string(sdlVersion.patch) << endl;
     429
     430   // TODO: Refactor the logger api to be more flexible,
     431   // esp. since gl_log() and gl_log_err() have issues printing anything besides strings
     432   restart_gl_log();
     433   gl_log("starting SDL\n%s.%s.%s",
     434      to_string(sdlVersion.major).c_str(),
     435      to_string(sdlVersion.minor).c_str(),
     436      to_string(sdlVersion.patch).c_str());
     437
     438   // TODO: Use open_Log() and related functions instead of gl_log ones
     439   // TODO: In addition, delete the gl_log functions
     440   open_log();
     441   get_log() << "starting SDL" << endl;
     442   get_log() <<
     443      (int)sdlVersion.major << "." <<
     444      (int)sdlVersion.minor << "." <<
     445      (int)sdlVersion.patch << endl;
     446
     447   // TODO: Put all fonts, textures, and images in the assets folder
     448   gui = new GameGui_SDL();
     449
     450   if (gui->init() == RTWO_ERROR) {
     451      // TODO: Also print these sorts of errors to the log
     452      cout << "UI library could not be initialized!" << endl;
     453      cout << gui->getError() << endl;
     454      return RTWO_ERROR;
     455   }
     456
     457   window = (SDL_Window*)gui->createWindow("Vulkan Game", width, height, guiFlags & GUI_FLAGS_WINDOW_FULLSCREEN);
     458   if (window == nullptr) {
     459      cout << "Window could not be created!" << endl;
     460      cout << gui->getError() << endl;
     461      return RTWO_ERROR;
     462   }
     463
     464   cout << "Target window size: (" << width << ", " << height << ")" << endl;
     465   cout << "Actual window size: (" << gui->getWindowWidth() << ", " << gui->getWindowHeight() << ")" << endl;
     466
     467   return RTWO_SUCCESS;
     468}
     469
     470void VulkanGame::initVulkan() {
     471   const vector<const char*> validationLayers = {
     472      "VK_LAYER_KHRONOS_validation"
     473   };
     474   const vector<const char*> deviceExtensions = {
     475      VK_KHR_SWAPCHAIN_EXTENSION_NAME
     476   };
     477
     478   createVulkanInstance(validationLayers);
     479   setupDebugMessenger();
     480   createVulkanSurface();
     481   pickPhysicalDevice(deviceExtensions);
     482   createLogicalDevice(validationLayers, deviceExtensions);
    491483}
    492484
    493485void VulkanGame::cleanup() {
    494    vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
     486   vkDestroyDescriptorPool(g_Device, descriptorPool, g_Allocator);
    495487
    496488   if (ENABLE_VALIDATION_LAYERS) {
     
    633625      const vector<const char*>& deviceExtensions) {
    634626   QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(g_PhysicalDevice, surface);
    635    g_QueueFamily = indices.graphicsFamily.value();
     627
     628   if (!indices.isComplete()) {
     629      throw runtime_error("failed to find required queue families!");
     630   }
     631
     632   // TODO: Using separate graphics and present queues currently works, but I should verify that I'm
     633   // using them correctly to get the most benefit out of separate queues
    636634
    637635   vector<VkDeviceQueueCreateInfo> queueCreateInfoList;
    638    set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value() };
     636   set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() };
    639637
    640638   float queuePriority = 1.0f;
     
    668666      createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
    669667      createInfo.ppEnabledLayerNames = validationLayers.data();
    670    }
    671    else {
     668   } else {
    672669      createInfo.enabledLayerCount = 0;
    673670   }
     
    677674   }
    678675
    679    vkGetDeviceQueue(g_Device, g_QueueFamily, 0, &g_Queue);
    680    //vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
    681    //vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
     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;
    682681}
    683682
    684683/********************************************** END OF NEW CODE **********************************************/
     684
     685/********************************************** START TEMP HELPER GUNVTIONS **********************************/
     686
     687// Forward Declarations
     688void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd,
     689   const VkAllocationCallbacks* allocator);
     690void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd,
     691   const VkAllocationCallbacks* allocator);
     692void 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
     696void 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.
     705void 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.