From 35198bce6bdb4b389c1c0742d82430e168463f3f Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Mon, 8 Dec 2025 00:58:09 -0500 Subject: [PATCH] Pulled the gui out into VkGUI to separate it out. --- meson.build | 1 + vk_engine.cpp | 155 +++----------------------------------------------- vk_engine.h | 22 +------ vk_gui.cpp | 151 ++++++++++++++++++++++++++++++++++++++++++++++++ vk_gui.h | 18 ++++++ vk_types.h | 17 ++++++ 6 files changed, 198 insertions(+), 166 deletions(-) create mode 100644 vk_gui.cpp create mode 100644 vk_gui.h diff --git a/meson.build b/meson.build index deacd3f..64df191 100644 --- a/meson.build +++ b/meson.build @@ -121,6 +121,7 @@ sources = [ 'vk_images.cpp', 'vk_descriptors.cpp', 'vk_pipelines.cpp', + 'vk_gui.cpp', 'main.cpp', ] diff --git a/vk_engine.cpp b/vk_engine.cpp index 6e9dbc8..cf70b02 100644 --- a/vk_engine.cpp +++ b/vk_engine.cpp @@ -3,18 +3,13 @@ #include "vk_pipelines.h" #include -#include -#include - #include #include #include "VkBootstrap.h" #include #include -#include "imgui.h" -#include "imgui_impl_sdl2.h" -#include "imgui_impl_vulkan.h" +#include #define VMA_IMPLEMENTATION #include "vk_mem_alloc.h" @@ -32,18 +27,7 @@ void VulkanEngine::init() assert(loadedEngine == nullptr); loadedEngine = this; - // We initialize SDL and create a window with it. - SDL_Init(SDL_INIT_VIDEO); - - SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_VULKAN); - - _window = SDL_CreateWindow( - "Vulkan Engine", - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - int(_windowExtent.width), - int(_windowExtent.height), - window_flags); + _window = _gui.init_window(_windowExtent); init_vulkan(); init_swapchain(); @@ -51,7 +35,7 @@ void VulkanEngine::init() init_sync_structures(); init_descriptors(); init_pipelines(); - init_imgui(); + _gui.init_imgui(VulkanEngine::Get()); //everything went fine _isInitialized = true; @@ -81,7 +65,7 @@ void VulkanEngine::cleanup() vkDestroyDevice(_device, nullptr); vkb::destroy_debug_utils_messenger(_instance, _debug_messenger); vkDestroyInstance(_instance, nullptr); - SDL_DestroyWindow(_window); + _gui.destroy(_window); } loadedEngine = nullptr; @@ -125,7 +109,7 @@ void VulkanEngine::draw() vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - draw_imgui(cmd, _swapchainImageViews[swapchainImageIndex]); + _gui.draw_imgui(_swapchainExtent, cmd, _swapchainImageViews[swapchainImageIndex]); vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); @@ -168,68 +152,21 @@ void VulkanEngine::draw() void VulkanEngine::run() { - SDL_Event e; - bool bQuit = false; - bool stop_rendering = false; - //main loop - while(!bQuit) + while(!_gui.should_quit) { - //Handle events on queue - while(SDL_PollEvent(&e) != 0) - { - //close the window when user alt-f4s or clicks the X button - if(e.type == SDL_QUIT) { - bQuit = true; - } + _gui.poll_event(); - if(e.type == SDL_WINDOWEVENT) { - if(e.window.event == SDL_WINDOWEVENT_MINIMIZED) { - stop_rendering = true; - } - - if(e.window.event == SDL_WINDOWEVENT_RESTORED) { - stop_rendering = false; - } - } - - ImGui_ImplSDL2_ProcessEvent(&e); - } - - if(stop_rendering) { + if(_gui.stop_rendering) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); continue; } - render_imgui(); + _gui.render_imgui(backgroundEffects, ¤tBackgroundEffect); draw(); } } -void VulkanEngine::render_imgui() { - ImGui_ImplVulkan_NewFrame(); - ImGui_ImplSDL2_NewFrame(); - - ImGui::NewFrame(); - - if (ImGui::Begin("background")) { - - ComputeEffect& selected = backgroundEffects[currentBackgroundEffect]; - - ImGui::Text("Selected effect: %s", selected.name); - - ImGui::SliderInt("Effect Index", ¤tBackgroundEffect,0, backgroundEffects.size() - 1); - - ImGui::InputFloat4("data1",(float*)& selected.data.data1); - ImGui::InputFloat4("data2",(float*)& selected.data.data2); - ImGui::InputFloat4("data3",(float*)& selected.data.data3); - ImGui::InputFloat4("data4",(float*)& selected.data.data4); - } - ImGui::End(); - - ImGui::Render(); -} - void VulkanEngine::init_vulkan() { vkb::InstanceBuilder builder; @@ -570,81 +507,7 @@ void VulkanEngine::immediate_submit(std::function&& f VK_CHECK(vkQueueSubmit2(_graphicsQueue, 1, &submit, _immFence)); VK_CHECK(vkWaitForFences(_device, 1, &_immFence, true,9999999999)); - } -void VulkanEngine::init_imgui() -{ -// 1: create descriptor pool for IMGUI - // the size of the pool is very oversize, but it's copied from imgui demo - // itself. - VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 }, - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 }, - { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 }, - { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } - }; - - VkDescriptorPoolCreateInfo pool_info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, - .maxSets = 1000, - .poolSizeCount = (uint32_t)std::size(pool_sizes), - .pPoolSizes = pool_sizes, - }; - - VkDescriptorPool imguiPool; - VK_CHECK(vkCreateDescriptorPool(_device, &pool_info, nullptr, &imguiPool)); - // 2: initialize the imgui library - ImGui::CreateContext(); - - ImGui_ImplSDL2_InitForVulkan(_window); - - ImGui_ImplVulkan_InitInfo init_info{ - .Instance = _instance, - .PhysicalDevice = _chosenGPU, - .Device = _device, - .Queue = _graphicsQueue, - .DescriptorPool = imguiPool, - .MinImageCount = 3, - .ImageCount = 3, - .MSAASamples = VK_SAMPLE_COUNT_1_BIT, - .UseDynamicRendering = true, - .PipelineRenderingCreateInfo = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, - .colorAttachmentCount = 1, - .pColorAttachmentFormats = &_swapchainImageFormat, - }, - }; - - ImGui_ImplVulkan_Init(&init_info); - ImGui_ImplVulkan_CreateFontsTexture(); - - _mainDeletionQueue.push_function([=,this]() { - ImGui_ImplVulkan_Shutdown(); - vkDestroyDescriptorPool(_device, imguiPool, nullptr); - }); -} - - -void VulkanEngine::draw_imgui(VkCommandBuffer cmd, VkImageView targetImageView) -{ - VkRenderingAttachmentInfo colorAttachment = vkinit::attachment_info(targetImageView, nullptr, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - VkRenderingInfo renderInfo = vkinit::rendering_info(_swapchainExtent, &colorAttachment, nullptr); - - vkCmdBeginRendering(cmd, &renderInfo); - - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd); - - vkCmdEndRendering(cmd); -} diff --git a/vk_engine.h b/vk_engine.h index 5a7903b..b5c85a5 100644 --- a/vk_engine.h +++ b/vk_engine.h @@ -5,22 +5,7 @@ #include #include - -struct ComputePushConstants { - glm::vec4 data1; - glm::vec4 data2; - glm::vec4 data3; - glm::vec4 data4; -}; - -struct ComputeEffect { - const char *name; - VkPipeline pipeline; - VkPipelineLayout layout; - - ComputePushConstants data; -}; - +#include "vk_gui.h" struct DeletionQueue { std::deque> deletors; @@ -48,7 +33,6 @@ struct FrameData { DeletionQueue _deletionQueue; }; -constexpr unsigned int FRAME_OVERLAP=2; class VulkanEngine { public: @@ -104,6 +88,7 @@ public: // imgui shader stuff std::vector backgroundEffects; int currentBackgroundEffect{0}; + VkGUI _gui; static VulkanEngine& Get(); @@ -129,11 +114,8 @@ private: void init_descriptors(); void init_pipelines(); void init_background_pipelines(); - void init_imgui(); void create_swapchain(uint32_t width, uint32_t height); void destroy_swapchain(); void draw_background(VkCommandBuffer cmd); - void draw_imgui(VkCommandBuffer cmd, VkImageView targetImageView); - void render_imgui(); }; diff --git a/vk_gui.cpp b/vk_gui.cpp new file mode 100644 index 0000000..86e4bd3 --- /dev/null +++ b/vk_gui.cpp @@ -0,0 +1,151 @@ +#include "vk_gui.h" +#include "vk_initializers.h" +#include +#include +#include +#include +#include +#include "vk_engine.h" + +struct SDL_Window* VkGUI::init_window(VkExtent2D windowExtent) +{ + SDL_Init(SDL_INIT_VIDEO); + + SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_VULKAN); + + return SDL_CreateWindow( + "Vulkan Engine", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + int(windowExtent.width), + int(windowExtent.height), + window_flags); +} + +void VkGUI::init_imgui(VulkanEngine& engine) +{ + // 1. create descriptor pool for IMGUI + // the size of the pool is very oversize, but it's copied from imgui demo + // itself. + VkDescriptorPoolSize pool_sizes[] = { + { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 }, + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 }, + { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 }, + { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } + }; + + VkDescriptorPoolCreateInfo pool_info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + .maxSets = 1000, + .poolSizeCount = (uint32_t)std::size(pool_sizes), + .pPoolSizes = pool_sizes, + }; + + VkDescriptorPool imguiPool; + VK_CHECK(vkCreateDescriptorPool(engine._device, &pool_info, nullptr, &imguiPool)); + + // 2: initialize the imgui library + ImGui::CreateContext(); + + ImGui_ImplSDL2_InitForVulkan(engine._window); + + ImGui_ImplVulkan_InitInfo init_info{ + .Instance = engine._instance, + .PhysicalDevice = engine._chosenGPU, + .Device = engine._device, + .Queue = engine._graphicsQueue, + .DescriptorPool = imguiPool, + .MinImageCount = 3, + .ImageCount = 3, + .MSAASamples = VK_SAMPLE_COUNT_1_BIT, + .UseDynamicRendering = true, + .PipelineRenderingCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + .colorAttachmentCount = 1, + .pColorAttachmentFormats = &engine._swapchainImageFormat, + }, + }; + + ImGui_ImplVulkan_Init(&init_info); + ImGui_ImplVulkan_CreateFontsTexture(); + + engine._mainDeletionQueue.push_function([=,this]() { + ImGui_ImplVulkan_Shutdown(); + vkDestroyDescriptorPool(engine._device, imguiPool, nullptr); + }); +} + +void VkGUI::draw_imgui(VkExtent2D& swapchainExtent, VkCommandBuffer cmd, VkImageView targetImageView) +{ + VkRenderingAttachmentInfo colorAttachment = vkinit::attachment_info(targetImageView, nullptr, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + VkRenderingInfo renderInfo = vkinit::rendering_info(swapchainExtent, &colorAttachment, nullptr); + + vkCmdBeginRendering(cmd, &renderInfo); + + ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd); + + vkCmdEndRendering(cmd); +} + +void VkGUI::render_imgui(std::vector& backgroundEffects, int* currentBackgroundEffect) +{ + ImGui_ImplVulkan_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + + ImGui::NewFrame(); + + if (ImGui::Begin("background")) { + + ComputeEffect& selected = backgroundEffects[*currentBackgroundEffect]; + + ImGui::Text("Selected effect: %s", selected.name); + + ImGui::SliderInt("Effect Index", currentBackgroundEffect,0, backgroundEffects.size() - 1); + + ImGui::InputFloat4("data1",(float*)& selected.data.data1); + ImGui::InputFloat4("data2",(float*)& selected.data.data2); + ImGui::InputFloat4("data3",(float*)& selected.data.data3); + ImGui::InputFloat4("data4",(float*)& selected.data.data4); + } + ImGui::End(); + + ImGui::Render(); +} + +void VkGUI::destroy(struct SDL_Window* _window) +{ + SDL_DestroyWindow(_window); +} + + +void VkGUI::poll_event() { + SDL_Event event; + + while(SDL_PollEvent(&event) != 0) { + //close the window when user alt-f4s or clicks the X button + if(event.type == SDL_QUIT) { + should_quit = true; + } + + if(event.type == SDL_WINDOWEVENT) { + if(event.window.event == SDL_WINDOWEVENT_MINIMIZED) { + stop_rendering = true; + } + + if(event.window.event == SDL_WINDOWEVENT_RESTORED) { + stop_rendering = false; + } + } + + ImGui_ImplSDL2_ProcessEvent(&event); + } +} diff --git a/vk_gui.h b/vk_gui.h new file mode 100644 index 0000000..8890504 --- /dev/null +++ b/vk_gui.h @@ -0,0 +1,18 @@ +#pragma once +#include "vk_types.h" + +class VulkanEngine; + +class VkGUI { + public: + bool should_quit = false; + bool stop_rendering = false; + + struct SDL_Window* init_window(VkExtent2D windowExtent); + void init_imgui(VulkanEngine& engine); + void draw_imgui(VkExtent2D& swapchainExtent, VkCommandBuffer cmd, VkImageView targetImageView); + void render_imgui(std::vector& backgroundEffects, int* currentBackgroundEffect); + void destroy(struct SDL_Window* _window); + + void poll_event(); +}; diff --git a/vk_types.h b/vk_types.h index 9b880a6..ed4264a 100644 --- a/vk_types.h +++ b/vk_types.h @@ -37,3 +37,20 @@ struct AllocatedImage { VkExtent3D imageExtent; VkFormat imageFormat; }; + +struct ComputePushConstants { + glm::vec4 data1; + glm::vec4 data2; + glm::vec4 data3; + glm::vec4 data4; +}; + +struct ComputeEffect { + const char *name; + VkPipeline pipeline; + VkPipelineLayout layout; + + ComputePushConstants data; +}; + +constexpr unsigned int FRAME_OVERLAP=2;