diff --git a/.gitignore b/.gitignore index d2bf98a016f588760241f9dc7f90f6197c458404..7ee4ff1903e902c4715c6e2b0c3e784ed5755aaf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,3 @@ -<<<<<<< HEAD -======= - ->>>>>>> develop # IDE specific files .project .cproject @@ -19,3 +15,6 @@ cmake-build-release/ *.exe *.ilk *.pdb + +# GUI configuration files +imgui.ini diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index b192dc798b01a0b40c9c9aa3275c26520b6ec17c..dd078107956371a71de72c25c2c76408a41a4667 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -41,6 +41,7 @@ namespace vkcv QueueType queueType; std::vector<vk::Semaphore> waitSemaphores; std::vector<vk::Semaphore> signalSemaphores; + vk::Fence fence; }; class Core final @@ -280,5 +281,8 @@ namespace vkcv void submitCommandStream(const CommandStreamHandle handle); void prepareSwapchainImageForPresent(const CommandStreamHandle handle); void prepareImageForSampling(const CommandStreamHandle cmdStream, const ImageHandle image); + + const vk::ImageView& getSwapchainImageView() const; + }; } diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp index a1219ce4147ebbb8ae0650da8a87766f8967874b..840650a1d6288922eceff7ba10ee7e71bf88dc22 100644 --- a/include/vkcv/Image.hpp +++ b/include/vkcv/Image.hpp @@ -29,9 +29,6 @@ namespace vkcv { [[nodiscard]] uint32_t getDepth() const; - - [[nodiscard]] - vk::ImageLayout getLayout() const; [[nodiscard]] vkcv::ImageHandle getHandle() const; diff --git a/modules/gui/CMakeLists.txt b/modules/gui/CMakeLists.txt index f08ed81b0234b13340168421b5a14a9ad788fd82..ce03f16e1f8d421f5b8e6c2fe913c0da04d34598 100644 --- a/modules/gui/CMakeLists.txt +++ b/modules/gui/CMakeLists.txt @@ -10,8 +10,8 @@ set(vkcv_gui_include ${PROJECT_SOURCE_DIR}/include) # Add source and header files to the module set(vkcv_gui_sources - ${vkcv_gui_include}/vkcv/gui/GUIWindow.hpp - ${vkcv_gui_source}/vkcv/gui/GUIWindow.cpp + ${vkcv_gui_include}/vkcv/gui/GUI.hpp + ${vkcv_gui_source}/vkcv/gui/GUI.cpp ) # Setup some path variables to load libraries diff --git a/modules/gui/include/vkcv/gui/GUIWindow.hpp b/modules/gui/include/vkcv/gui/GUI.hpp similarity index 52% rename from modules/gui/include/vkcv/gui/GUIWindow.hpp rename to modules/gui/include/vkcv/gui/GUI.hpp index afc1895790879a0207208f1e49d981a3f1510f90..5d62f1519b2e6e6e25daeffc4bc08e9388a758fe 100644 --- a/modules/gui/include/vkcv/gui/GUIWindow.hpp +++ b/modules/gui/include/vkcv/gui/GUI.hpp @@ -5,28 +5,32 @@ #include "imgui/backends/imgui_impl_vulkan.h" #include <vkcv/Core.hpp> +#include <vkcv/Window.hpp> namespace vkcv::gui { - class GUIWindow final : Window { + class GUI final { private: + GLFWwindow* m_window; Core& m_core; const Context& m_context; - const Swapchain& m_swapchain; ImGuiContext* m_gui_context; - ImGui_ImplVulkanH_Window m_gui_window; - vk::DescriptorPool m_descriptor_pool; - + vk::RenderPass m_render_pass; + + GUI(GLFWwindow* window, Core& core); + public: - GUIWindow(GLFWwindow* window, Core& core); - - virtual ~GUIWindow() override; + virtual ~GUI(); + + static GUI create(Core& core, Window& window); + + void beginGUI(); - static GUIWindow create(Core& core, const char *windowTitle, int width = -1, int height = -1, bool resizable = false); + void endGUI(); }; diff --git a/modules/gui/src/vkcv/gui/GUI.cpp b/modules/gui/src/vkcv/gui/GUI.cpp new file mode 100644 index 0000000000000000000000000000000000000000..11f87b236050bd7705ca4ba73da372ecf188fe7d --- /dev/null +++ b/modules/gui/src/vkcv/gui/GUI.cpp @@ -0,0 +1,221 @@ + +#include "vkcv/gui/GUI.hpp" + +#include <GLFW/glfw3.h> +#include <vkcv/Logger.hpp> + +namespace vkcv::gui { + + static void checkVulkanResult(VkResult resultCode) { + if (resultCode == 0) + return; + + const auto result = vk::Result(resultCode); + + vkcv_log(LogLevel::ERROR, "ImGui has a problem with Vulkan! (%s)", vk::to_string(result).c_str()); + } + + GUI::GUI(GLFWwindow* window, Core& core) : + m_core(core), + m_context(core.getContext()), + m_gui_context(nullptr) { + IMGUI_CHECKVERSION(); + + m_gui_context = ImGui::CreateContext(); + + ImGui_ImplGlfw_InitForVulkan(window, false); + + vk::DescriptorPoolSize pool_sizes[] = { + vk::DescriptorPoolSize(vk::DescriptorType::eSampler, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eCombinedImageSampler, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eSampledImage, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eStorageImage, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eUniformTexelBuffer, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eStorageTexelBuffer, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eUniformBufferDynamic, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eStorageBufferDynamic, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eInputAttachment, 1000) + }; + + const vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo ( + vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, + static_cast<uint32_t>(1000 * IM_ARRAYSIZE(pool_sizes)), + static_cast<uint32_t>(IM_ARRAYSIZE(pool_sizes)), + pool_sizes + ); + + m_descriptor_pool = m_context.getDevice().createDescriptorPool(descriptorPoolCreateInfo); + + const vk::PhysicalDevice& physicalDevice = m_context.getPhysicalDevice(); + const Swapchain& swapchain = core.getSwapchain(); + + const uint32_t graphicsQueueFamilyIndex = ( + m_context.getQueueManager().getGraphicsQueues()[0].familyIndex + ); + + ImGui_ImplVulkan_InitInfo init_info = {}; + init_info.Instance = m_context.getInstance(); + init_info.PhysicalDevice = m_context.getPhysicalDevice(); + init_info.Device = m_context.getDevice(); + init_info.QueueFamily = graphicsQueueFamilyIndex; + init_info.Queue = m_context.getQueueManager().getGraphicsQueues()[0].handle; + init_info.PipelineCache = nullptr; + init_info.DescriptorPool = m_descriptor_pool; + init_info.Allocator = nullptr; + init_info.MinImageCount = swapchain.getImageCount(); + init_info.ImageCount = swapchain.getImageCount(); + init_info.CheckVkResultFn = checkVulkanResult; + + const vk::AttachmentDescription attachment ( + vk::AttachmentDescriptionFlags(), + swapchain.getFormat(), + vk::SampleCountFlagBits::e1, + vk::AttachmentLoadOp::eLoad, + vk::AttachmentStoreOp::eStore, + vk::AttachmentLoadOp::eDontCare, + vk::AttachmentStoreOp::eDontCare, + vk::ImageLayout::eUndefined, + vk::ImageLayout::ePresentSrcKHR + ); + + const vk::AttachmentReference attachmentReference ( + 0, + vk::ImageLayout::eColorAttachmentOptimal + ); + + const vk::SubpassDescription subpass ( + vk::SubpassDescriptionFlags(), + vk::PipelineBindPoint::eGraphics, + 0, + nullptr, + 1, + &attachmentReference, + nullptr, + nullptr, + 0, + nullptr + ); + + const vk::SubpassDependency dependency ( + VK_SUBPASS_EXTERNAL, + 0, + vk::PipelineStageFlagBits::eColorAttachmentOutput, + vk::PipelineStageFlagBits::eColorAttachmentOutput, + vk::AccessFlags(), + vk::AccessFlagBits::eColorAttachmentWrite, + vk::DependencyFlags() + ); + + const vk::RenderPassCreateInfo passCreateInfo ( + vk::RenderPassCreateFlags(), + 1, + &attachment, + 1, + &subpass, + 1, + &dependency + ); + + m_render_pass = m_context.getDevice().createRenderPass(passCreateInfo); + + ImGui_ImplVulkan_Init(&init_info, m_render_pass); + + const SubmitInfo submitInfo { QueueType::Graphics, {}, {} }; + + core.recordAndSubmitCommands(submitInfo, [](const vk::CommandBuffer& commandBuffer) { + ImGui_ImplVulkan_CreateFontsTexture(commandBuffer); + }, []() { + ImGui_ImplVulkan_DestroyFontUploadObjects(); + }); + + m_context.getDevice().waitIdle(); + } + + GUI::~GUI() { + m_context.getDevice().waitIdle(); + + ImGui_ImplVulkan_Shutdown(); + + m_context.getDevice().destroyRenderPass(m_render_pass); + m_context.getDevice().destroyDescriptorPool(m_descriptor_pool); + + ImGui_ImplGlfw_Shutdown(); + + if (m_gui_context) { + ImGui::DestroyContext(m_gui_context); + } + } + + GUI GUI::create(Core &core, Window& window) { + return GUI(window.getWindow(), core); + } + + void GUI::beginGUI() { + const Swapchain& swapchain = m_core.getSwapchain(); + const auto extent = swapchain.getExtent(); + + if ((extent.width > 0) && (extent.height > 0)) { + ImGui_ImplVulkan_SetMinImageCount(swapchain.getImageCount()); + } + + ImGui_ImplVulkan_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + } + + void GUI::endGUI() { + ImGui::Render(); + + ImDrawData* drawData = ImGui::GetDrawData(); + + if ((!drawData) || + (drawData->DisplaySize.x <= 0.0f) || + (drawData->DisplaySize.y <= 0.0f)) { + return; + } + + const Swapchain& swapchain = m_core.getSwapchain(); + const auto extent = swapchain.getExtent(); + + const vk::FramebufferCreateInfo framebufferCreateInfo ( + vk::FramebufferCreateFlags(), + m_render_pass, + 1, + &m_core.getSwapchainImageView(), + extent.width, + extent.height, + 1 + ); + + const vk::Framebuffer framebuffer = m_context.getDevice().createFramebuffer(framebufferCreateInfo); + + SubmitInfo submitInfo; + submitInfo.queueType = QueueType::Graphics; + + m_core.recordAndSubmitCommands(submitInfo, [&](const vk::CommandBuffer& commandBuffer) { + const vk::Rect2D renderArea ( + vk::Offset2D(0, 0), + extent + ); + + const vk::RenderPassBeginInfo beginInfo ( + m_render_pass, + framebuffer, + renderArea, + 0, + nullptr + ); + + commandBuffer.beginRenderPass(beginInfo, vk::SubpassContents::eInline); + + ImGui_ImplVulkan_RenderDrawData(drawData, commandBuffer); + + commandBuffer.endRenderPass(); + }, [&]() { + m_context.getDevice().destroyFramebuffer(framebuffer); + }); + } + +} diff --git a/modules/gui/src/vkcv/gui/GUIWindow.cpp b/modules/gui/src/vkcv/gui/GUIWindow.cpp deleted file mode 100644 index 15bc03837caa397b8a38f941c1dd25fcb0e1d50c..0000000000000000000000000000000000000000 --- a/modules/gui/src/vkcv/gui/GUIWindow.cpp +++ /dev/null @@ -1,116 +0,0 @@ - -#include "vkcv/gui/GUIWindow.hpp" - -#include <vkcv/Logger.hpp> - -namespace vkcv::gui { - - static void checkVulkanResult(VkResult resultCode) { - if (resultCode == 0) - return; - - const vk::Result result = vk::Result(resultCode); - - vkcv_log(LogLevel::ERROR, "ImGui has a problem with Vulkan! (%s)", vk::to_string(result).c_str()); - } - - GUIWindow::GUIWindow(GLFWwindow* window, Core& core) : - Window(window), - m_core(core), - m_context(core.getContext()), - m_swapchain(core.getSwapchain()), - m_gui_context(nullptr) { - IMGUI_CHECKVERSION(); - - m_gui_context = ImGui::CreateContext(); - - const auto extent = m_swapchain.getExtent(); - const uint32_t graphicsQueueFamilyIndex = ( - m_context.getQueueManager().getGraphicsQueues()[0].familyIndex - ); - - ImGui_ImplVulkanH_CreateOrResizeWindow( - m_context.getInstance(), - m_context.getPhysicalDevice(), - m_context.getDevice(), - &m_gui_window, - graphicsQueueFamilyIndex, - nullptr, - static_cast<int>(extent.width), - static_cast<int>(extent.height), - m_swapchain.getImageCount() - ); - - ImGui_ImplGlfw_InitForVulkan(window, true); - - vk::DescriptorPoolSize pool_sizes[] = { - vk::DescriptorPoolSize(vk::DescriptorType::eSampler, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eCombinedImageSampler, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eSampledImage, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eStorageImage, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eUniformTexelBuffer, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eStorageTexelBuffer, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eUniformBufferDynamic, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eStorageBufferDynamic, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eInputAttachment, 1000) - }; - - const vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo ( - vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, - static_cast<uint32_t>(1000 * IM_ARRAYSIZE(pool_sizes)), - static_cast<uint32_t>(IM_ARRAYSIZE(pool_sizes)), - pool_sizes - ); - - m_descriptor_pool = m_context.getDevice().createDescriptorPool(descriptorPoolCreateInfo); - - ImGui_ImplVulkan_InitInfo init_info = {}; - init_info.Instance = m_context.getInstance(); - init_info.PhysicalDevice = m_context.getPhysicalDevice(); - init_info.Device = m_context.getDevice(); - init_info.QueueFamily = graphicsQueueFamilyIndex; - init_info.Queue = m_context.getQueueManager().getGraphicsQueues()[0].handle; - init_info.PipelineCache = nullptr; - init_info.DescriptorPool = m_descriptor_pool; - init_info.Allocator = nullptr; - init_info.MinImageCount = m_swapchain.getImageCount(); - init_info.ImageCount = m_gui_window.ImageCount; - init_info.CheckVkResultFn = checkVulkanResult; - ImGui_ImplVulkan_Init(&init_info, m_gui_window.RenderPass); - - const SubmitInfo submitInfo { QueueType::Transfer, {}, {} }; - - core.recordAndSubmitCommands(submitInfo, [](const vk::CommandBuffer& commandBuffer) { - ImGui_ImplVulkan_CreateFontsTexture(commandBuffer); - }, []() { - ImGui_ImplVulkan_DestroyFontUploadObjects(); - }); - } - - GUIWindow::~GUIWindow() { - m_context.getDevice().waitIdle(); - - ImGui_ImplVulkan_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - - vkDestroyDescriptorPool(m_context.getDevice(), m_descriptor_pool, nullptr); - - ImGui_ImplVulkanH_DestroyWindow( - m_context.getInstance(), - m_context.getDevice(), - &m_gui_window, - nullptr - ); - - if (m_gui_context) { - ImGui::DestroyContext(m_gui_context); - } - } - - GUIWindow GUIWindow::create(Core &core, const char *windowTitle, int width, int height, bool resizable) { - return GUIWindow(Window::createGLFWWindow(windowTitle, width, height, resizable), core); - } - -} diff --git a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp index 7214e208b068ba7b9002363e594f76d66123bffd..9e07dec255d283b4b8a8d4fcc769083498c10264 100644 --- a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp +++ b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp @@ -167,12 +167,13 @@ namespace vkcv::shader { } std::streamsize fileSize = file.tellg(); - std::vector<char> buffer (fileSize); + std::vector<char> buffer (fileSize + 1); file.seekg(0); file.read(buffer.data(), fileSize); file.close(); + buffer[fileSize] = '\0'; return buffer; } diff --git a/projects/first_triangle/CMakeLists.txt b/projects/first_triangle/CMakeLists.txt index 7e606b2348ea82486c2a57ee1062ef34150e46a0..ba8c83c06fc804082e6a0a14c3c0414899ef3057 100644 --- a/projects/first_triangle/CMakeLists.txt +++ b/projects/first_triangle/CMakeLists.txt @@ -22,7 +22,7 @@ if(MSVC) endif() # including headers of dependencies and the VkCV framework -target_include_directories(first_triangle SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include}) +target_include_directories(first_triangle SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include}) # linking with libraries from all dependencies and the VkCV framework -target_link_libraries(first_triangle vkcv vkcv_testing vkcv_camera vkcv_shader_compiler) +target_link_libraries(first_triangle vkcv vkcv_testing vkcv_camera vkcv_shader_compiler vkcv_gui) diff --git a/projects/first_triangle/shaders/shader.frag b/projects/first_triangle/shaders/shader.frag index d26446a73020111695aa2c86166205796dfa5e44..080678beb011afe4b03aed3bf7ae7148b77932dc 100644 --- a/projects/first_triangle/shaders/shader.frag +++ b/projects/first_triangle/shaders/shader.frag @@ -4,6 +4,6 @@ layout(location = 0) in vec3 fragColor; layout(location = 0) out vec4 outColor; -void main() { +void main() { outColor = vec4(fragColor, 1.0); } \ No newline at end of file diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index eca7ad7734caeba855a2edbb63c46965316525a7..2a7e8ba804b50ee8ffd20e7bac02ce6c926e6105 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -5,6 +5,7 @@ #include <chrono> #include <vkcv/shader/GLSLCompiler.hpp> +#include <vkcv/gui/GUI.hpp> int main(int argc, const char** argv) { const char* applicationName = "First Triangle"; @@ -28,6 +29,8 @@ int main(int argc, const char** argv) { {}, { "VK_KHR_swapchain" } ); + + vkcv::gui::GUI gui = vkcv::gui::GUI::create(core, window); const auto& context = core.getContext(); const vk::Instance& instance = context.getInstance(); @@ -215,6 +218,14 @@ int main(int argc, const char** argv) { core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); + + gui.beginGUI(); + + ImGui::Begin("Hello world"); + ImGui::Text("This is a test!"); + ImGui::End(); + + gui.endGUI(); core.endFrame(); } diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 5fab62f783a49823f7b5b2c531ea67718146939d..ced339d6b306b63e95b4ef48705b0d46c356df85 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -236,7 +236,6 @@ namespace vkcv attachmentsViews.push_back(targetHandle); } - vk::Framebuffer framebuffer = nullptr; const vk::FramebufferCreateInfo createInfo( {}, renderpass, @@ -244,16 +243,21 @@ namespace vkcv attachmentsViews.data(), width, height, - 1); - if(m_Context.m_Device.createFramebuffer(&createInfo, nullptr, &framebuffer) != vk::Result::eSuccess) - { + 1 + ); + + vk::Framebuffer framebuffer = m_Context.m_Device.createFramebuffer(createInfo); + + if (!framebuffer) { vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer"); return; } - vk::Viewport dynamicViewport(0.0f, 0.0f, - static_cast<float>(width), static_cast<float>(height), - 0.0f, 1.0f); + vk::Viewport dynamicViewport( + 0.0f, 0.0f, + static_cast<float>(width), static_cast<float>(height), + 0.0f, 1.0f + ); vk::Rect2D dynamicScissor({0, 0}, {width, height}); @@ -353,15 +357,17 @@ namespace vkcv const auto swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain()); const auto& queueManager = m_Context.getQueueManager(); - std::array<vk::Semaphore, 2> waitSemaphores{ - m_SyncResources.renderFinished, - m_SyncResources.swapchainImageAcquired }; + std::array<vk::Semaphore, 2> waitSemaphores{ + m_SyncResources.renderFinished, + m_SyncResources.swapchainImageAcquired + }; const vk::SwapchainKHR& swapchain = m_swapchain.getSwapchain(); const vk::PresentInfoKHR presentInfo( waitSemaphores, swapchain, - m_currentSwapchainImageIndex); + m_currentSwapchainImageIndex + ); vk::Result result; @@ -390,11 +396,19 @@ namespace vkcv beginCommandBuffer(cmdBuffer, vk::CommandBufferUsageFlagBits::eOneTimeSubmit); record(cmdBuffer); cmdBuffer.end(); - - const vk::Fence waitFence = createFence(device); + + vk::Fence waitFence; + + if (!submitInfo.fence) { + waitFence = createFence(device); + } + submitCommandBufferToQueue(queue.handle, cmdBuffer, waitFence, submitInfo.waitSemaphores, submitInfo.signalSemaphores); waitForFence(device, waitFence); - device.destroyFence(waitFence); + + if (!submitInfo.fence) { + device.destroyFence(waitFence); + } device.freeCommandBuffers(cmdPool, cmdBuffer); @@ -507,4 +521,9 @@ namespace vkcv m_ImageManager->recordImageLayoutTransition(image, vk::ImageLayout::eShaderReadOnlyOptimal, cmdBuffer); }, nullptr); } + + const vk::ImageView& Core::getSwapchainImageView() const { + return m_swapchainImageViews[m_currentSwapchainImageIndex]; + } + }