Browse Source

Examples, Viewport: Vulkan: Experiment (broken) multi-viewport support, merging code from ParticlePeter branches. (#1542, #1042)

omar 7 years ago
parent
commit
b88492746e

+ 3 - 0
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)();

+ 145 - 28
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));
 }

+ 2 - 2
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();

+ 1 - 1
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();

+ 89 - 80
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;
+
+	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);
 
-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;
-
-        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);
-    }
+		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

+ 3 - 0
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)