Changeset 6493e43 in opengl-game for sdl-game.cpp
- Timestamp:
- Jan 3, 2021, 6:18:28 PM (4 years ago)
- Branches:
- feature/imgui-sdl
- Children:
- 6a39266
- Parents:
- 3b7d497
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sdl-game.cpp
r3b7d497 r6493e43 4 4 #include <set> 5 5 #include <stdexcept> 6 7 #include "IMGUI/imgui_impl_sdl.h" 8 9 #include <stdio.h> // printf, fprintf 10 #include <stdlib.h> // abort 6 11 7 12 // dear imgui: standalone example application for SDL2 + Vulkan … … 15 20 // Read comments in imgui_impl_vulkan.h. 16 21 17 #include "IMGUI/imgui.h"18 #include "IMGUI/imgui_impl_sdl.h"19 #include "IMGUI/imgui_impl_vulkan.h"20 #include <stdio.h> // printf, fprintf21 #include <stdlib.h> // abort22 23 22 #include <SDL2/SDL_vulkan.h> 24 23 … … 35 34 static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE; 36 35 static VkDevice g_Device = VK_NULL_HANDLE; 37 static uint32_t g_QueueFamily = (uint32_t)-1;38 static VkQueue g_ Queue = VK_NULL_HANDLE;36 static VkQueue g_GraphicsQueue = VK_NULL_HANDLE; 37 static VkQueue g_PresentQueue = VK_NULL_HANDLE; 39 38 static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; 40 static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;41 39 42 40 static ImGui_ImplVulkanH_Window g_MainWindowData; … … 55 53 // All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo. 56 54 // Your real engine/app may not use them. 57 static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height) 58 { 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 59 61 wd->Surface = surface; 60 61 // Check for WSI support62 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 }69 62 70 63 // Select Surface Format … … 84 77 // Create SwapChain, RenderPass, Framebuffer, etc. 85 78 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); 87 84 } 88 85 … … 154 151 err = vkEndCommandBuffer(fd->CommandBuffer); 155 152 check_vk_result(err); 156 err = vkQueueSubmit(g_ Queue, 1, &info, fd->Fence);153 err = vkQueueSubmit(g_GraphicsQueue, 1, &info, fd->Fence); 157 154 check_vk_result(err); 158 155 } … … 171 168 info.pSwapchains = &wd->Swapchain; 172 169 info.pImageIndices = &wd->FrameIndex; 173 VkResult err = vkQueuePresentKHR(g_ Queue, &info);170 VkResult err = vkQueuePresentKHR(g_PresentQueue, &info); 174 171 if (err == VK_ERROR_OUT_OF_DATE_KHR) 175 172 { … … 212 209 initVulkan(); 213 210 211 VkResult err; 212 214 213 // Create Framebuffers 215 int w, h;216 SDL_GetWindowSize(window, &w, &h);217 214 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); 465 216 466 217 // Create Descriptor Pool … … 486 237 pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); 487 238 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 419 bool 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 470 void 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); 491 483 } 492 484 493 485 void VulkanGame::cleanup() { 494 vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);486 vkDestroyDescriptorPool(g_Device, descriptorPool, g_Allocator); 495 487 496 488 if (ENABLE_VALIDATION_LAYERS) { … … 633 625 const vector<const char*>& deviceExtensions) { 634 626 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 636 634 637 635 vector<VkDeviceQueueCreateInfo> queueCreateInfoList; 638 set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value() };636 set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() }; 639 637 640 638 float queuePriority = 1.0f; … … 668 666 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size()); 669 667 createInfo.ppEnabledLayerNames = validationLayers.data(); 670 } 671 else { 668 } else { 672 669 createInfo.enabledLayerCount = 0; 673 670 } … … 677 674 } 678 675 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; 682 681 } 683 682 684 683 /********************************************** 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.