From dae0908735a91c4e87bcb13bbd003a0adaafd7c6 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Tue, 26 Nov 2019 18:28:48 +0100 Subject: [PATCH] vulkan oit: fix imgui overlay re-init imgui with the oit render pass when running game. use regular render pass otherwise. --- core/rend/vulkan/imgui_impl_vulkan.cpp | 18 +++++++++++++-- core/rend/vulkan/imgui_impl_vulkan.h | 2 +- core/rend/vulkan/oit_buffer.h | 2 +- core/rend/vulkan/oit_drawer.cpp | 1 + core/rend/vulkan/vulkan.h | 2 +- core/rend/vulkan/vulkan_context.cpp | 32 +++++++++++++++----------- 6 files changed, 38 insertions(+), 19 deletions(-) diff --git a/core/rend/vulkan/imgui_impl_vulkan.cpp b/core/rend/vulkan/imgui_impl_vulkan.cpp index c34e4c3cf..16657f241 100644 --- a/core/rend/vulkan/imgui_impl_vulkan.cpp +++ b/core/rend/vulkan/imgui_impl_vulkan.cpp @@ -41,6 +41,7 @@ static VkQueue g_Queue = VK_NULL_HANDLE; static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; static VkRenderPass g_RenderPass = VK_NULL_HANDLE; +static int g_RenderSubpass = 0; static void (*g_CheckVkResultFn)(VkResult err) = NULL; static VkDeviceSize g_BufferMemoryAlignment = 256; @@ -527,6 +528,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() } // Create Descriptor Set: + if (!g_DescriptorSet) { VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; @@ -555,6 +557,13 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } + if (g_Pipeline) + { + // Avoid destroying the in-flight pipeline + vkDeviceWaitIdle(g_Device); + vkDestroyPipeline(g_Device, g_Pipeline, g_Allocator); + g_Pipeline = VK_NULL_HANDLE; + } VkPipelineShaderStageCreateInfo stage[2] = {}; stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT; @@ -649,6 +658,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() info.pDynamicState = &dynamic_state; info.layout = g_PipelineLayout; info.renderPass = g_RenderPass; + info.subpass = g_RenderSubpass; err = vkCreateGraphicsPipelines(g_Device, g_PipelineCache, 1, &info, g_Allocator, &g_Pipeline); check_vk_result(err); @@ -694,8 +704,12 @@ void ImGui_ImplVulkan_InvalidateDeviceObjects() if (g_Pipeline) { vkDestroyPipeline(g_Device, g_Pipeline, g_Allocator); g_Pipeline = VK_NULL_HANDLE; } } -bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass) +bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass, int subpass) { + IM_ASSERT(render_pass != VK_NULL_HANDLE); + if (g_RenderPass == render_pass && g_RenderSubpass == subpass) + return true; + ImGuiIO& io = ImGui::GetIO(); io.BackendRendererName = "imgui_impl_vulkan"; @@ -704,7 +718,6 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend IM_ASSERT(info->Device != VK_NULL_HANDLE); IM_ASSERT(info->Queue != VK_NULL_HANDLE); IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE); - IM_ASSERT(render_pass != VK_NULL_HANDLE); g_Instance = info->Instance; g_PhysicalDevice = info->PhysicalDevice; @@ -712,6 +725,7 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend g_QueueFamily = info->QueueFamily; g_Queue = info->Queue; g_RenderPass = render_pass; + g_RenderSubpass = subpass; g_PipelineCache = info->PipelineCache; g_DescriptorPool = info->DescriptorPool; g_Allocator = info->Allocator; diff --git a/core/rend/vulkan/imgui_impl_vulkan.h b/core/rend/vulkan/imgui_impl_vulkan.h index c8d624cd3..3c75f569e 100644 --- a/core/rend/vulkan/imgui_impl_vulkan.h +++ b/core/rend/vulkan/imgui_impl_vulkan.h @@ -32,7 +32,7 @@ struct ImGui_ImplVulkan_InitInfo }; // Called by user code -IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass); +IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass, int subpass = 0); IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer); diff --git a/core/rend/vulkan/oit_buffer.h b/core/rend/vulkan/oit_buffer.h index 570a385a2..57c7c6aae 100644 --- a/core/rend/vulkan/oit_buffer.h +++ b/core/rend/vulkan/oit_buffer.h @@ -63,7 +63,7 @@ public: pixelCounterReset->upload(sizeof(zero), &zero); } // We need to wait until this buffer is not used before deleting it - VulkanContext::Instance()->GetGraphicsQueue().waitIdle(); + context->GetGraphicsQueue().waitIdle(); abufferPointerAttachment.reset(); abufferPointerAttachment = std::unique_ptr( new FramebufferAttachment(context->GetPhysicalDevice(), context->GetDevice())); diff --git a/core/rend/vulkan/oit_drawer.cpp b/core/rend/vulkan/oit_drawer.cpp index 91b767510..d6b46f66a 100644 --- a/core/rend/vulkan/oit_drawer.cpp +++ b/core/rend/vulkan/oit_drawer.cpp @@ -577,6 +577,7 @@ void OITTextureDrawer::EndFrame() vk::CommandBuffer OITScreenDrawer::NewFrame() { GetContext()->NewFrame(); + GetContext()->InitImgui(GetRenderPass(), 2); vk::CommandBuffer commandBuffer = GetContext()->GetCurrentCommandBuffer(); viewport.offset.x = 0; diff --git a/core/rend/vulkan/vulkan.h b/core/rend/vulkan/vulkan.h index c38cceb1e..aa2dec7af 100644 --- a/core/rend/vulkan/vulkan.h +++ b/core/rend/vulkan/vulkan.h @@ -40,6 +40,7 @@ public: bool Init(); bool InitInstance(const char** extensions, uint32_t extensions_count); bool InitDevice(); + void InitImgui(vk::RenderPass renderPass, int subpass = 0); void CreateSwapChain(); void Term(); void SetWindow(void *window, void *display) { this->window = window; this->display = display; } @@ -95,7 +96,6 @@ public: private: vk::Format InitDepthBuffer(); - void InitImgui(); void DoSwapAutomation(); vk::SurfaceKHR GetSurface() { #ifdef USE_SDL diff --git a/core/rend/vulkan/vulkan_context.cpp b/core/rend/vulkan/vulkan_context.cpp index d0a2a34c2..757e0790a 100644 --- a/core/rend/vulkan/vulkan_context.cpp +++ b/core/rend/vulkan/vulkan_context.cpp @@ -281,7 +281,7 @@ vk::Format VulkanContext::InitDepthBuffer() return depthFormat; } -void VulkanContext::InitImgui() +void VulkanContext::InitImgui(vk::RenderPass renderPass, int subpass) { gui_init(); ImGui_ImplVulkan_InitInfo initInfo = {}; @@ -296,22 +296,25 @@ void VulkanContext::InitImgui() initInfo.CheckVkResultFn = &CheckImGuiResult; #endif - if (!ImGui_ImplVulkan_Init(&initInfo, (VkRenderPass)*renderPass)) + if (!ImGui_ImplVulkan_Init(&initInfo, (VkRenderPass)renderPass, subpass)) { die("ImGui initialization failed"); } - // Upload Fonts - device->resetFences(1, &(*drawFences.front())); - device->resetCommandPool(*commandPools.front(), vk::CommandPoolResetFlagBits::eReleaseResources); - vk::CommandBuffer& commandBuffer = *commandBuffers.front(); - commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); - ImGui_ImplVulkan_CreateFontsTexture((VkCommandBuffer)commandBuffer); - commandBuffer.end(); - vk::SubmitInfo submitInfo(0, nullptr, nullptr, 1, &commandBuffer); - graphicsQueue.submit(1, &submitInfo, *drawFences.front()); + if (ImGui::GetIO().Fonts->TexID == 0) + { + // Upload Fonts + device->resetFences(1, &(*drawFences.front())); + device->resetCommandPool(*commandPools.front(), vk::CommandPoolResetFlagBits::eReleaseResources); + vk::CommandBuffer& commandBuffer = *commandBuffers.front(); + commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); + ImGui_ImplVulkan_CreateFontsTexture((VkCommandBuffer)commandBuffer); + commandBuffer.end(); + vk::SubmitInfo submitInfo(0, nullptr, nullptr, 1, &commandBuffer); + graphicsQueue.submit(1, &submitInfo, *drawFences.front()); - device->waitIdle(); - ImGui_ImplVulkan_InvalidateFontUploadObjects(); + device->waitIdle(); + ImGui_ImplVulkan_InvalidateFontUploadObjects(); + } } bool VulkanContext::InitDevice() @@ -604,7 +607,7 @@ void VulkanContext::CreateSwapChain() imageAcquiredSemaphores.push_back(device->createSemaphoreUnique(vk::SemaphoreCreateInfo())); } - InitImgui(); + InitImgui(*renderPass); INFO_LOG(RENDERER, "Vulkan swap chain created: %d x %d, swap chain size %d", width, height, (int)imageViews.size()); } @@ -677,6 +680,7 @@ void VulkanContext::NewFrame() void VulkanContext::BeginRenderPass() { + InitImgui(*renderPass); const vk::ClearValue clear_colors[] = { vk::ClearColorValue(std::array{0.f, 0.f, 0.f, 1.f}), vk::ClearDepthStencilValue{ 0.f, 0 } }; vk::CommandBuffer commandBuffer = *commandBuffers[currentImage]; commandBuffer.beginRenderPass(vk::RenderPassBeginInfo(*renderPass, *framebuffers[currentImage], vk::Rect2D({0, 0}, {width, height}), 2, clear_colors),