diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index 6b520ba2..b9cf06e0 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -452,6 +452,9 @@ static void ImGui_ImplGlfw_InitPlatformInterface() io.PlatformInterface.RenderViewport = ImGui_ImplGlfw_RenderViewport; io.PlatformInterface.SwapBuffers = ImGui_ImplGlfw_SwapBuffers; + // We let the user set up the link to glfwCreateWindowSurface() here, so this binding can work with old GLFW and without Vulkan headers + io.PlatformInterface.CreateVkSurface = NULL; + // Register main window handle ImGuiViewport* main_viewport = ImGui::GetMainViewport(); ImGuiPlatformDataGlfw* data = IM_NEW(ImGuiPlatformDataGlfw)(); diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp index 8864c3d5..a117600c 100644 --- a/examples/imgui_impl_vulkan.cpp +++ b/examples/imgui_impl_vulkan.cpp @@ -55,7 +55,7 @@ struct FrameDataForRender VkBuffer IndexBuffer; }; static int g_FrameIndex = 0; -static FrameDataForRender g_FramesDataBuffers[IMGUI_VK_QUEUED_FRAMES]; +static FrameDataForRender g_FramesDataBuffers[IMGUI_VK_QUEUED_FRAMES] = {}; // Font data static VkSampler g_FontSampler = VK_NULL_HANDLE; @@ -204,6 +204,7 @@ void ImGui_ImplVulkan_RenderDrawData(VkCommandBuffer command_buffer, ImDrawData* return; FrameDataForRender* fd = &g_FramesDataBuffers[g_FrameIndex]; + g_FrameIndex = (g_FrameIndex + 1) % IMGUI_VK_QUEUED_FRAMES; // Create the Vertex and Index buffers: size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); @@ -713,7 +714,10 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend ImGui_ImplVulkan_CreateDeviceObjects(); io.ConfigFlags |= ImGuiConfigFlags_RendererHasViewports; if (io.ConfigFlags & ImGuiConfigFlags_EnableViewports) + { + IM_ASSERT(io.PlatformInterface.CreateVkSurface != NULL); ImGui_ImplVulkan_InitPlatformInterface(); + } return true; } @@ -728,12 +732,6 @@ void ImGui_ImplVulkan_NewFrame() { } -void ImGui_ImplVulkan_Render(VkCommandBuffer command_buffer) -{ - ImGui_ImplVulkan_RenderDrawData(command_buffer, ImGui::GetDrawData()); - g_FrameIndex = (g_FrameIndex + 1) % IMGUI_VK_QUEUED_FRAMES; -} - //------------------------------------------------------------------------- // Miscellaneous Vulkan Helpers // (Those are currently not strictly needed by the binding, but will be once if we support multi-viewports) @@ -747,7 +745,7 @@ ImGui_ImplVulkan_FrameData::ImGui_ImplVulkan_FrameData() CommandPool = VK_NULL_HANDLE; CommandBuffer = VK_NULL_HANDLE; Fence = VK_NULL_HANDLE; - PresentCompleteSemaphore = VK_NULL_HANDLE; + ImageAcquiredSemaphore = VK_NULL_HANDLE; RenderCompleteSemaphore = VK_NULL_HANDLE; } @@ -867,7 +865,7 @@ void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_ { VkSemaphoreCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - err = vkCreateSemaphore(device, &info, allocator, &fd->PresentCompleteSemaphore); + err = vkCreateSemaphore(device, &info, allocator, &fd->ImageAcquiredSemaphore); check_vk_result(err); err = vkCreateSemaphore(device, &info, allocator, &fd->RenderCompleteSemaphore); check_vk_result(err); @@ -875,8 +873,22 @@ void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_ } } +int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode) +{ + if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR) + return 3; + if (present_mode == VK_PRESENT_MODE_FIFO_KHR || present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR) + return 2; + if (present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR) + return 1; + IM_ASSERT(0); + return 1; +} + void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkan_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h) { + uint32_t min_image_count = 2; // FIXME: this should become a function parameter + VkResult err; VkSwapchainKHR old_swapchain = wd->Swapchain; err = vkDeviceWaitIdle(device); @@ -893,12 +905,17 @@ void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice wd->BackBufferCount = 0; if (wd->RenderPass) vkDestroyRenderPass(device, wd->RenderPass, allocator); + + // If min image count was not specified, request different count of images dependent on selected present mode + if (min_image_count == 0) + min_image_count = ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(wd->PresentMode); // Create Swapchain { VkSwapchainCreateInfoKHR info = {}; info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; info.surface = wd->Surface; + info.minImageCount = min_image_count; info.imageFormat = wd->SurfaceFormat.format; info.imageColorSpace = wd->SurfaceFormat.colorSpace; info.imageArrayLayers = 1; @@ -912,10 +929,10 @@ void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice VkSurfaceCapabilitiesKHR cap; err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, wd->Surface, &cap); check_vk_result(err); - if (cap.maxImageCount > 0) - info.minImageCount = (cap.minImageCount + 2 < cap.maxImageCount) ? (cap.minImageCount + 2) : cap.maxImageCount; - else - info.minImageCount = cap.minImageCount + 2; + if (info.minImageCount < cap.minImageCount) + info.minImageCount = cap.minImageCount; + else if (info.minImageCount > cap.maxImageCount) + info.minImageCount = cap.maxImageCount; if (cap.currentExtent.width == 0xffffffff) { @@ -1007,14 +1024,16 @@ void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkan_WindowData* wd, const VkAllocationCallbacks* allocator) { - vkDeviceWaitIdle(device); + vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals) + //vkQueueWaitIdle(g_Queue); + for (int i = 0; i < IMGUI_VK_QUEUED_FRAMES; i++) { ImGui_ImplVulkan_FrameData* fd = &wd->Frames[i]; vkDestroyFence(device, fd->Fence, allocator); vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer); vkDestroyCommandPool(device, fd->CommandPool, allocator); - vkDestroySemaphore(device, fd->PresentCompleteSemaphore, allocator); + vkDestroySemaphore(device, fd->ImageAcquiredSemaphore, allocator); vkDestroySemaphore(device, fd->RenderCompleteSemaphore, allocator); } for (uint32_t i = 0; i < wd->BackBufferCount; i++) @@ -1046,19 +1065,41 @@ static void ImGui_ImplVulkan_CreateViewport(ImGuiViewport* viewport) { ImGuiPlatformDataVulkan* data = IM_NEW(ImGuiPlatformDataVulkan)(); viewport->RendererUserData = data; + ImGui_ImplVulkan_WindowData* wd = &data->WindowData; - // FIXME-PLATFORM - //HWND hwnd = (HWND)viewport->PlatformHandle; - //IM_ASSERT(hwnd != 0); + // Create surface + ImGuiIO& io = ImGui::GetIO(); + VkResult err = (VkResult)io.PlatformInterface.CreateVkSurface(viewport->PlatformHandle, (ImU64)g_Instance, (const void*)g_Allocator, (ImU64*)&wd->Surface); + check_vk_result(err); - //... + // Check for WSI support + VkBool32 res; + vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, wd->Surface, &res); + if (res != VK_TRUE) + { + fprintf(stderr, "Error no WSI support on physical device 0\n"); + exit(-1); + } + + // Get Surface Format + const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM }; + const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), requestSurfaceColorSpace); + + // Get Present Mode + VkPresentModeKHR present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR; + wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(g_PhysicalDevice, wd->Surface, &present_mode, 1); + + // Create SwapChain, RenderPass, Framebuffer, etc. + ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator); + ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, (int)viewport->Size.x, (int)viewport->Size.y); } static void ImGui_ImplVulkan_DestroyViewport(ImGuiViewport* viewport) { if (ImGuiPlatformDataVulkan* data = (ImGuiPlatformDataVulkan*)viewport->RendererUserData) { - //... + ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, &data->WindowData, g_Allocator); IM_DELETE(data); } viewport->RendererUserData = NULL; @@ -1067,32 +1108,107 @@ static void ImGui_ImplVulkan_DestroyViewport(ImGuiViewport* viewport) static void ImGui_ImplVulkan_ResizeViewport(ImGuiViewport* viewport, ImVec2 size) { ImGuiPlatformDataVulkan* data = (ImGuiPlatformDataVulkan*)viewport->RendererUserData; - //... - (void)data; - (void)size; + ImGui_ImplVulkan_WindowData* wd = &data->WindowData; + ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, (int)size.x, (int)size.y); } static void ImGui_ImplVulkan_RenderViewport(ImGuiViewport* viewport) { ImGuiPlatformDataVulkan* data = (ImGuiPlatformDataVulkan*)viewport->RendererUserData; + ImGui_ImplVulkan_WindowData* wd = &data->WindowData; + VkResult err; + ImVec4 clear_color = ImGui::GetStyle().Colors[ImGuiCol_WindowBg]; // FIXME-PLATFORM clear_color.w = 1.0f; - (void)data; - // clear - // call ImGui_ImplVulkan_RenderDrawData(&viewport->DrawData) + { + ImGui_ImplVulkan_FrameData* fd = &wd->Frames[wd->FrameIndex]; + for (;;) + { + err = vkWaitForFences(g_Device, 1, &fd->Fence, VK_TRUE, 100); + if (err == VK_SUCCESS) break; + if (err == VK_TIMEOUT) continue; + check_vk_result(err); + } + { + err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, fd->ImageAcquiredSemaphore, VK_NULL_HANDLE, &fd->BackbufferIndex); + check_vk_result(err); + } + { + err = vkResetCommandPool(g_Device, fd->CommandPool, 0); + check_vk_result(err); + VkCommandBufferBeginInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + err = vkBeginCommandBuffer(fd->CommandBuffer, &info); + check_vk_result(err); + } + { + VkRenderPassBeginInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + info.renderPass = wd->RenderPass; + info.framebuffer = wd->Framebuffer[fd->BackbufferIndex]; + info.renderArea.extent.width = wd->Width; + info.renderArea.extent.height = wd->Height; + info.clearValueCount = 1; + info.pClearValues = &wd->ClearValue; + vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE); + } + } + + memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float)); + ImGui_ImplVulkan_RenderDrawData(wd->Frames[wd->FrameIndex].CommandBuffer, &viewport->DrawData); + + { + ImGui_ImplVulkan_FrameData* fd = &wd->Frames[wd->FrameIndex]; + vkCmdEndRenderPass(fd->CommandBuffer); + { + VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + info.waitSemaphoreCount = 1; + info.pWaitSemaphores = &fd->ImageAcquiredSemaphore; + info.pWaitDstStageMask = &wait_stage; + info.commandBufferCount = 1; + info.pCommandBuffers = &fd->CommandBuffer; + info.signalSemaphoreCount = 1; + info.pSignalSemaphores = &fd->RenderCompleteSemaphore; + + err = vkEndCommandBuffer(fd->CommandBuffer); + check_vk_result(err); + err = vkResetFences(g_Device, 1, &fd->Fence); + check_vk_result(err); + err = vkQueueSubmit(g_Queue, 1, &info, fd->Fence); + check_vk_result(err); + } + } } static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport) { ImGuiPlatformDataVulkan* data = (ImGuiPlatformDataVulkan*)viewport->RendererUserData; - (void)data; - //... + ImGui_ImplVulkan_WindowData* wd = &data->WindowData; + + VkResult err; + uint32_t PresentIndex = wd->FrameIndex; + + ImGui_ImplVulkan_FrameData* fd = &wd->Frames[PresentIndex]; + VkPresentInfoKHR info = {}; + info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + info.waitSemaphoreCount = 1; + info.pWaitSemaphores = &fd->RenderCompleteSemaphore; + info.swapchainCount = 1; + info.pSwapchains = &wd->Swapchain; + info.pImageIndices = &fd->BackbufferIndex; + err = vkQueuePresentKHR(g_Queue, &info); + check_vk_result(err); + wd->FrameIndex = (wd->FrameIndex + 1) % IMGUI_VK_QUEUED_FRAMES; } void ImGui_ImplVulkan_InitPlatformInterface() { ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.PlatformInterface.CreateVkSurface != NULL); io.RendererInterface.CreateViewport = ImGui_ImplVulkan_CreateViewport; io.RendererInterface.DestroyViewport = ImGui_ImplVulkan_DestroyViewport; io.RendererInterface.ResizeViewport = ImGui_ImplVulkan_ResizeViewport; @@ -1102,6 +1218,7 @@ void ImGui_ImplVulkan_InitPlatformInterface() void ImGui_ImplVulkan_ShutdownPlatformInterface() { + ImGui::DestroyViewportsRendererData(ImGui::GetCurrentContext()); ImGuiIO& io = ImGui::GetIO(); memset(&io.RendererInterface, 0, sizeof(io.RendererInterface)); } diff --git a/examples/imgui_impl_vulkan.h b/examples/imgui_impl_vulkan.h index afabbb74..f9ef133e 100644 --- a/examples/imgui_impl_vulkan.h +++ b/examples/imgui_impl_vulkan.h @@ -29,7 +29,6 @@ struct ImGui_ImplVulkan_InitInfo IMGUI_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass); IMGUI_API void ImGui_ImplVulkan_Shutdown(); IMGUI_API void ImGui_ImplVulkan_NewFrame(); -IMGUI_API void ImGui_ImplVulkan_Render(VkCommandBuffer command_buffer); IMGUI_API void ImGui_ImplVulkan_RenderDrawData(VkCommandBuffer command_buffer, ImDrawData* draw_data); // Called by Init/NewFrame/Shutdown @@ -55,6 +54,7 @@ IMGUI_API void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFr IMGUI_API void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkan_WindowData* wd, const VkAllocationCallbacks* allocator); IMGUI_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space); IMGUI_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count); +IMGUI_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode); struct ImGui_ImplVulkan_FrameData { @@ -62,7 +62,7 @@ struct ImGui_ImplVulkan_FrameData VkCommandPool CommandPool; VkCommandBuffer CommandBuffer; VkFence Fence; - VkSemaphore PresentCompleteSemaphore; + VkSemaphore ImageAcquiredSemaphore; VkSemaphore RenderCompleteSemaphore; IMGUI_API ImGui_ImplVulkan_FrameData(); diff --git a/examples/sdl_vulkan_example/main.cpp b/examples/sdl_vulkan_example/main.cpp index 7ed0f997..5c4e6008 100644 --- a/examples/sdl_vulkan_example/main.cpp +++ b/examples/sdl_vulkan_example/main.cpp @@ -479,7 +479,7 @@ int main(int, char**) ImGui::Render(); memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float)); FrameBegin(wd); - ImGui_ImplVulkan_Render(wd->Frames[wd->FrameIndex].CommandBuffer); + ImGui_ImplVulkan_RenderDrawData(wd->Frames[wd->FrameIndex].CommandBuffer, ImGui::GetDrawData()); FrameEnd(wd); ImGui::RenderAdditionalViewports(); diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index cd4e3e72..4029c651 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -224,83 +224,79 @@ static void CleanupVulkan() vkDestroyInstance(g_Instance, g_Allocator); } -static void FrameBegin(ImGui_ImplVulkan_WindowData* wd) +static void FrameRender(ImGui_ImplVulkan_WindowData* wd) { - ImGui_ImplVulkan_FrameData* fd = &wd->Frames[wd->FrameIndex]; - VkResult err; - for (;;) - { - err = vkWaitForFences(g_Device, 1, &fd->Fence, VK_TRUE, 100); - if (err == VK_SUCCESS) break; - if (err == VK_TIMEOUT) continue; - check_vk_result(err); - } - { - err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, fd->PresentCompleteSemaphore, VK_NULL_HANDLE, &fd->BackbufferIndex); - check_vk_result(err); - } - { - err = vkResetCommandPool(g_Device, fd->CommandPool, 0); - check_vk_result(err); - VkCommandBufferBeginInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - err = vkBeginCommandBuffer(fd->CommandBuffer, &info); - check_vk_result(err); - } - { - VkRenderPassBeginInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - info.renderPass = wd->RenderPass; - info.framebuffer = wd->Framebuffer[fd->BackbufferIndex]; - info.renderArea.extent.width = wd->Width; - info.renderArea.extent.height = wd->Height; - info.clearValueCount = 1; - info.pClearValues = &wd->ClearValue; - vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE); - } -} + VkResult err; -static void FrameEnd(ImGui_ImplVulkan_WindowData* wd) -{ - ImGui_ImplVulkan_FrameData* fd = &wd->Frames[wd->FrameIndex]; - VkResult err; - vkCmdEndRenderPass(fd->CommandBuffer); - { - VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - VkSubmitInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - info.waitSemaphoreCount = 1; - info.pWaitSemaphores = &fd->PresentCompleteSemaphore; - info.pWaitDstStageMask = &wait_stage; - info.commandBufferCount = 1; - info.pCommandBuffers = &fd->CommandBuffer; - info.signalSemaphoreCount = 1; - info.pSignalSemaphores = &fd->RenderCompleteSemaphore; + VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore; + err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); + check_vk_result(err); - err = vkEndCommandBuffer(fd->CommandBuffer); - check_vk_result(err); - err = vkResetFences(g_Device, 1, &fd->Fence); - check_vk_result(err); - err = vkQueueSubmit(g_Queue, 1, &info, fd->Fence); - check_vk_result(err); - } + ImGui_ImplVulkan_FrameData* fd = &wd->Frames[wd->FrameIndex]; + { + err = vkWaitForFences(g_Device, 1, &fd->Fence, VK_TRUE, UINT64_MAX); // wait indefinitely instead of periodically checking + check_vk_result(err); + + err = vkResetFences(g_Device, 1, &fd->Fence); + check_vk_result(err); + } + { + err = vkResetCommandPool(g_Device, fd->CommandPool, 0); + check_vk_result(err); + VkCommandBufferBeginInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + err = vkBeginCommandBuffer(fd->CommandBuffer, &info); + check_vk_result(err); + } + { + VkRenderPassBeginInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + info.renderPass = wd->RenderPass; + info.framebuffer = wd->Framebuffer[wd->FrameIndex]; + info.renderArea.extent.width = wd->Width; + info.renderArea.extent.height = wd->Height; + info.clearValueCount = 1; + info.pClearValues = &wd->ClearValue; + vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE); + } + + // Record Imgui Draw Data and draw funcs into command buffer + ImGui_ImplVulkan_RenderDrawData(fd->CommandBuffer, ImGui::GetDrawData()); + + // Submit command buffer + vkCmdEndRenderPass(fd->CommandBuffer); + { + VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + info.waitSemaphoreCount = 1; + info.pWaitSemaphores = &image_acquired_semaphore; + info.pWaitDstStageMask = &wait_stage; + info.commandBufferCount = 1; + info.pCommandBuffers = &fd->CommandBuffer; + info.signalSemaphoreCount = 1; + info.pSignalSemaphores = &fd->RenderCompleteSemaphore; + + err = vkEndCommandBuffer(fd->CommandBuffer); + check_vk_result(err); + err = vkQueueSubmit(g_Queue, 1, &info, fd->Fence); + check_vk_result(err); + } } static void FramePresent(ImGui_ImplVulkan_WindowData* wd) { - VkResult err; - ImGui_ImplVulkan_FrameData* fd = &wd->Frames[wd->FrameIndex]; - VkPresentInfoKHR info = {}; - info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - info.waitSemaphoreCount = 1; - info.pWaitSemaphores = &fd->RenderCompleteSemaphore; - info.swapchainCount = 1; - info.pSwapchains = &wd->Swapchain; - info.pImageIndices = &fd->BackbufferIndex; - err = vkQueuePresentKHR(g_Queue, &info); - check_vk_result(err); + VkPresentInfoKHR info = {}; + info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + info.waitSemaphoreCount = 1; + info.pWaitSemaphores = &fd->RenderCompleteSemaphore; + info.swapchainCount = 1; + info.pSwapchains = &wd->Swapchain; + info.pImageIndices = &wd->FrameIndex; + VkResult err = vkQueuePresentKHR(g_Queue, &info); + check_vk_result(err); } static void glfw_error_callback(int error, const char* description) @@ -312,12 +308,23 @@ static void glfw_resize_callback(GLFWwindow*, int w, int h) { g_ResizeWanted = true; g_ResizeWidth = w; - g_ResizeHeight = h; + g_ResizeHeight = h; +} + +static int glfw_create_vk_surface(void* platform_handle, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface) +{ + GLFWwindow* window = (GLFWwindow*)platform_handle; + VkInstance instance = (VkInstance)vk_instance; + const VkAllocationCallbacks* allocator = (const VkAllocationCallbacks*)vk_allocator; + VkSurfaceKHR* surface = (VkSurfaceKHR*)out_vk_surface; + VkResult err = glfwCreateWindowSurface(instance, window, allocator, surface); + check_vk_result(err); + return (int)err; } int main(int, char**) { - // Setup window + // Setup window glfwSetErrorCallback(glfw_error_callback); if (!glfwInit()) return 1; @@ -354,6 +361,10 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_PlatformNoTaskBar; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + // Setup GLFW binding + ImGui_ImplGlfw_InitForVulkan(window, true); + io.PlatformInterface.CreateVkSurface = glfw_create_vk_surface; + // Setup Vulkan binding ImGui_ImplVulkan_InitInfo init_info = {}; init_info.Instance = g_Instance; @@ -365,7 +376,6 @@ int main(int, char**) init_info.DescriptorPool = g_DescriptorPool; init_info.Allocator = g_Allocator; init_info.CheckVkResultFn = check_vk_result; - ImGui_ImplGlfw_InitForVulkan(window, true); ImGui_ImplVulkan_Init(&init_info, wd->RenderPass); // Setup style @@ -430,9 +440,12 @@ int main(int, char**) // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. glfwPollEvents(); - if (g_ResizeWanted) - ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, g_ResizeWidth, g_ResizeHeight); - g_ResizeWanted = false; + if (g_ResizeWanted) + { + ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, g_ResizeWidth, g_ResizeHeight); + g_ResizeWanted = false; + } + ImGui_ImplVulkan_NewFrame(); ImGui_ImplGlfw_NewFrame(); @@ -443,7 +456,7 @@ int main(int, char**) static int counter = 0; ImGui::Text("Hello, world!"); // Display some text (you can use a format string too) ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f - ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color + ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color (nb: you could use (float*)&wd->ClearValue instead) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our windows open/close state ImGui::Checkbox("Another Window", &show_another_window); @@ -476,13 +489,9 @@ int main(int, char**) // Rendering ImGui::Render(); memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float)); - FrameBegin(wd); - ImGui_ImplVulkan_Render(wd->Frames[wd->FrameIndex].CommandBuffer); - FrameEnd(wd); + FrameRender(wd); ImGui::RenderAdditionalViewports(); FramePresent(wd); - - wd->FrameIndex = (wd->FrameIndex + 1) % IMGUI_VK_QUEUED_FRAMES; } // Cleanup diff --git a/imgui.h b/imgui.h index 7e56bd01..0bbdfb65 100644 --- a/imgui.h +++ b/imgui.h @@ -966,6 +966,9 @@ struct ImGuiPlatformInterface void (*RenderViewport)(ImGuiViewport* viewport); void (*SwapBuffers)(ImGuiViewport* viewport); + // FIXME-VIEWPORT: Experimenting with back-end abstraction. This probably shouldn't stay as is. + int (*CreateVkSurface)(void* platform_handle, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface); + // FIXME-DPI float (*GetWindowDpiScale)(ImGuiViewport* viewport); // (Optional) void (*ChangedViewport)(ImGuiViewport* viewport); // (Optional) Called during Begin() every time the viewport we are outputting into changes (viewport = next viewport)