Browse Source

Examples: Vulkan: Added calls to supports runtime changing back buffer count. (#2071)

MindSpunk 7 năm trước cách đây
mục cha
commit
b88a3b2711

+ 34 - 7
examples/example_glfw_vulkan/main.cpp

@@ -23,6 +23,7 @@
 #define IMGUI_VULKAN_DEBUG_REPORT
 #endif
 
+static uint32_t						g_MinImageCount = 2;
 static VkAllocationCallbacks*       g_Allocator = NULL;
 static VkInstance                   g_Instance = VK_NULL_HANDLE;
 static VkPhysicalDevice             g_PhysicalDevice = VK_NULL_HANDLE;
@@ -211,8 +212,8 @@ static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR
     //printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
 
     // 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, width, height);
+    ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height, g_MinImageCount);
+	ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
 }
 
 static void CleanupVulkan()
@@ -373,6 +374,7 @@ int main(int, char**)
     init_info.DescriptorPool = g_DescriptorPool;
     init_info.Allocator = g_Allocator;
     init_info.CheckVkResultFn = check_vk_result;
+	init_info.QueuedFrames = wd->BackBufferCount;
     ImGui_ImplVulkan_Init(&init_info, wd->RenderPass);
 
     // Load Fonts
@@ -433,11 +435,14 @@ int main(int, char**)
         // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
         // 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_MinImageCount);
+			ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, &g_WindowData, g_Allocator);
+			ImGui_ImplVulkan_SetQueuedFramesCount(g_WindowData.BackBufferCount);
+			g_WindowData.FrameIndex = 0;
+			g_ResizeWanted = false;
+		}
 
         // Start the Dear ImGui frame
         ImGui_ImplVulkan_NewFrame();
@@ -478,6 +483,28 @@ int main(int, char**)
             ImGui::Text("Hello from another window!");
             if (ImGui::Button("Close Me"))
                 show_another_window = false;
+
+			if (ImGui::Button("Increase"))
+			{
+				g_MinImageCount++;
+				g_ResizeWanted = true;
+			}
+
+			ImGui::SameLine();
+			if (ImGui::Button("Decrease"))
+			{
+				if (g_MinImageCount != 2)
+				{
+					g_MinImageCount--;
+					g_ResizeWanted = true;
+				}
+			}
+
+			ImGui::SameLine();
+			ImGui::Text("Back Buffers: %i", g_MinImageCount);
+
+			ImGui::Text("Frame Index %i", wd->FrameIndex);
+
             ImGui::End();
         }
 

+ 45 - 3
examples/example_sdl_vulkan/main.cpp

@@ -15,6 +15,8 @@
 #define IMGUI_VULKAN_DEBUG_REPORT
 #endif
 
+static uint32_t						g_MinImageCount = 2;
+static bool							g_PendingSwapchainRebuild = false;
 static VkAllocationCallbacks*       g_Allocator = NULL;
 static VkInstance                   g_Instance = VK_NULL_HANDLE;
 static VkPhysicalDevice             g_PhysicalDevice = VK_NULL_HANDLE;
@@ -201,8 +203,8 @@ static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR
     //printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
 
     // 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, width, height);
+    ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height, g_MinImageCount);
+	ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
 }
 
 static void CleanupVulkan()
@@ -296,6 +298,20 @@ static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
     check_vk_result(err);
 }
 
+static void RebuildSwapChain(int width, int height)
+{
+	ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, width, height, g_MinImageCount);
+	ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, &g_WindowData, g_Allocator);
+	ImGui_ImplVulkan_SetQueuedFramesCount(g_WindowData.BackBufferCount);
+	g_WindowData.FrameIndex = 0;
+	g_PendingSwapchainRebuild = false;
+}
+
+static void RebuildSwapChain()
+{
+	RebuildSwapChain(g_WindowData.Width, g_WindowData.Height);
+}
+
 int main(int, char**)
 {
     // Setup SDL
@@ -354,6 +370,7 @@ int main(int, char**)
     init_info.PipelineCache = g_PipelineCache;
     init_info.DescriptorPool = g_DescriptorPool;
     init_info.Allocator = g_Allocator;
+	init_info.QueuedFrames = wd->BackBufferCount;
     init_info.CheckVkResultFn = check_vk_result;
     ImGui_ImplVulkan_Init(&init_info, wd->RenderPass);
 
@@ -422,9 +439,12 @@ int main(int, char**)
             if (event.type == SDL_QUIT)
                 done = true;
             if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window))
-                ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, (int)event.window.data1, (int)event.window.data2);
+				RebuildSwapChain((int)event.window.data1, (int)event.window.data2);
         }
 
+		if (g_PendingSwapchainRebuild)
+			RebuildSwapChain();
+
         // Start the Dear ImGui frame
         ImGui_ImplVulkan_NewFrame();
         ImGui_ImplSDL2_NewFrame(window);
@@ -464,6 +484,28 @@ int main(int, char**)
             ImGui::Text("Hello from another window!");
             if (ImGui::Button("Close Me"))
                 show_another_window = false;
+
+			if (ImGui::Button("Increase"))
+			{
+				g_MinImageCount++;
+				g_PendingSwapchainRebuild = true;
+			}
+
+			ImGui::SameLine();
+			if (ImGui::Button("Decrease"))
+			{
+				if (g_MinImageCount != 2)
+				{
+					g_MinImageCount--;
+					g_PendingSwapchainRebuild = true;
+				}
+			}
+
+			ImGui::SameLine();
+			ImGui::Text("Back Buffers: %i", g_MinImageCount);
+
+			ImGui::Text("Frame Index %i", wd->FrameIndex);
+
             ImGui::End();
         }
 

+ 64 - 23
examples/imgui_impl_vulkan.cpp

@@ -64,8 +64,8 @@ struct FrameDataForRender
     VkBuffer        VertexBuffer;
     VkBuffer        IndexBuffer;
 };
-static int                    g_FrameIndex = 0;
-static FrameDataForRender     g_FramesDataBuffers[IMGUI_VK_QUEUED_FRAMES] = {};
+static int                              g_FrameIndex = 0;
+static ImVector<FrameDataForRender>     g_FramesDataBuffers = {};
 
 // Font data
 static VkSampler              g_FontSampler = VK_NULL_HANDLE;
@@ -240,7 +240,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
 
     VkResult err;
     FrameDataForRender* fd = &g_FramesDataBuffers[g_FrameIndex];
-    g_FrameIndex = (g_FrameIndex + 1) % IM_ARRAYSIZE(g_FramesDataBuffers);
+    g_FrameIndex = (g_FrameIndex + 1) % g_FramesDataBuffers.size();
 
     // Create the Vertex and Index buffers:
     size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);
@@ -728,15 +728,6 @@ void    ImGui_ImplVulkan_InvalidateDeviceObjects()
 {
     ImGui_ImplVulkan_InvalidateFontUploadObjects();
 
-    for (int i = 0; i < IM_ARRAYSIZE(g_FramesDataBuffers); i++)
-    {
-        FrameDataForRender* fd = &g_FramesDataBuffers[i];
-        if (fd->VertexBuffer)       { vkDestroyBuffer   (g_Device, fd->VertexBuffer,        g_Allocator); fd->VertexBuffer = VK_NULL_HANDLE; }
-        if (fd->VertexBufferMemory) { vkFreeMemory      (g_Device, fd->VertexBufferMemory,  g_Allocator); fd->VertexBufferMemory = VK_NULL_HANDLE; }
-        if (fd->IndexBuffer)        { vkDestroyBuffer   (g_Device, fd->IndexBuffer,         g_Allocator); fd->IndexBuffer = VK_NULL_HANDLE; }
-        if (fd->IndexBufferMemory)  { vkFreeMemory      (g_Device, fd->IndexBufferMemory,   g_Allocator); fd->IndexBufferMemory = VK_NULL_HANDLE; }
-    }
-
     if (g_FontView)             { vkDestroyImageView(g_Device, g_FontView, g_Allocator); g_FontView = VK_NULL_HANDLE; }
     if (g_FontImage)            { vkDestroyImage(g_Device, g_FontImage, g_Allocator); g_FontImage = VK_NULL_HANDLE; }
     if (g_FontMemory)           { vkFreeMemory(g_Device, g_FontMemory, g_Allocator); g_FontMemory = VK_NULL_HANDLE; }
@@ -746,6 +737,18 @@ void    ImGui_ImplVulkan_InvalidateDeviceObjects()
     if (g_Pipeline)             { vkDestroyPipeline(g_Device, g_Pipeline, g_Allocator); g_Pipeline = VK_NULL_HANDLE; }
 }
 
+void ImGui_ImplVulkan_InvalidateFrameDeviceObjects()
+{
+	for (int i = 0; i < g_FramesDataBuffers.size(); i++)
+	{
+		FrameDataForRender* fd = &g_FramesDataBuffers[i];
+		if (fd->VertexBuffer)       { vkDestroyBuffer(g_Device, fd->VertexBuffer,       g_Allocator); fd->VertexBuffer = VK_NULL_HANDLE; }
+		if (fd->VertexBufferMemory) { vkFreeMemory   (g_Device, fd->VertexBufferMemory, g_Allocator); fd->VertexBufferMemory = VK_NULL_HANDLE; }
+		if (fd->IndexBuffer)        { vkDestroyBuffer(g_Device, fd->IndexBuffer,        g_Allocator); fd->IndexBuffer = VK_NULL_HANDLE; }
+		if (fd->IndexBufferMemory)  { vkFreeMemory   (g_Device, fd->IndexBufferMemory,  g_Allocator); fd->IndexBufferMemory = VK_NULL_HANDLE; }
+	}
+}
+
 bool    ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass)
 {
     ImGuiIO& io = ImGui::GetIO();
@@ -768,6 +771,11 @@ bool    ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend
     g_DescriptorPool = info->DescriptorPool;
     g_Allocator = info->Allocator;
     g_CheckVkResultFn = info->CheckVkResultFn;
+	g_FramesDataBuffers.resize(info->QueuedFrames);
+	for (int i = 0; i < g_FramesDataBuffers.size(); i++)
+	{
+		g_FramesDataBuffers[i] = FrameDataForRender();
+	}
 
     ImGui_ImplVulkan_CreateDeviceObjects();
 
@@ -776,6 +784,7 @@ bool    ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend
 
 void ImGui_ImplVulkan_Shutdown()
 {
+	ImGui_ImplVulkan_InvalidateFrameDeviceObjects();
     ImGui_ImplVulkan_InvalidateDeviceObjects();
 }
 
@@ -783,6 +792,24 @@ void ImGui_ImplVulkan_NewFrame()
 {
 }
 
+void ImGui_ImplVulkan_SetQueuedFramesCount(uint32_t count)
+{
+	if (count == g_FramesDataBuffers.size())
+	{
+		return;
+	}
+	ImGui_ImplVulkan_InvalidateFrameDeviceObjects();
+
+	uint32_t old_size = g_FramesDataBuffers.size();
+	g_FramesDataBuffers.resize(count);
+	for (uint32_t i = old_size; i < count; i++)
+	{
+		
+		g_FramesDataBuffers[i] = FrameDataForRender();
+	}
+	g_FrameIndex = 0;
+}
+
 
 //-------------------------------------------------------------------------
 // Internal / Miscellaneous Vulkan Helpers
@@ -901,7 +928,7 @@ void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_
 
     // Create Command Buffers
     VkResult err;
-    for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+    for (int i = 0; i < wd->Frames.size(); i++)
     {
         ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
         {
@@ -951,10 +978,8 @@ int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_m
     return 1;
 }
 
-void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h)
+void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)
 {
-    uint32_t min_image_count = 2;   // FIXME: this should become a function parameter
-
     VkResult err;
     VkSwapchainKHR old_swapchain = wd->Swapchain;
     err = vkDeviceWaitIdle(device);
@@ -1015,7 +1040,18 @@ void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice
         err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, NULL);
         check_vk_result(err);
         err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, wd->BackBuffer);
-        check_vk_result(err);
+		check_vk_result(err);
+
+		for (uint32_t i = 0; i < wd->Frames.size(); i++)
+		{
+			ImGui_ImplVulkanH_DestroyFrameData(g_Instance, device, &wd->Frames[i], allocator);
+		}
+		uint32_t old_size = wd->Frames.size();
+		wd->Frames.resize(wd->BackBufferCount);
+		for (uint32_t i = 0; i < wd->Frames.size(); i++)
+		{
+			wd->Frames[i] = ImGui_ImplVulkanH_FrameData();
+		}
     }
     if (old_swapchain)
         vkDestroySwapchainKHR(device, old_swapchain, allocator);
@@ -1102,14 +1138,10 @@ void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, I
     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 < IM_ARRAYSIZE(wd->Frames); i++)
+    for (int i = 0; i < wd->Frames.size(); i++)
     {
         ImGui_ImplVulkanH_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->ImageAcquiredSemaphore, allocator);
-        vkDestroySemaphore(device, fd->RenderCompleteSemaphore, allocator);
+		ImGui_ImplVulkanH_DestroyFrameData(instance, device, fd, allocator);
     }
     for (uint32_t i = 0; i < wd->BackBufferCount; i++)
     {
@@ -1121,3 +1153,12 @@ void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, I
     vkDestroySurfaceKHR(instance, wd->Surface, allocator);
     *wd = ImGui_ImplVulkanH_WindowData();
 }
+
+void ImGui_ImplVulkanH_DestroyFrameData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_FrameData* fd, const VkAllocationCallbacks* allocator)
+{
+	vkDestroyFence(device, fd->Fence, allocator);
+	vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
+	vkDestroyCommandPool(device, fd->CommandPool, allocator);
+	vkDestroySemaphore(device, fd->ImageAcquiredSemaphore, allocator);
+	vkDestroySemaphore(device, fd->RenderCompleteSemaphore, allocator);
+}

+ 7 - 3
examples/imgui_impl_vulkan.h

@@ -15,7 +15,7 @@
 
 #include <vulkan/vulkan.h>
 
-#define IMGUI_VK_QUEUED_FRAMES      2
+//#define IMGUI_VK_QUEUED_FRAMES      2
 
 // Please zero-clear before use.
 struct ImGui_ImplVulkan_InitInfo
@@ -27,6 +27,7 @@ struct ImGui_ImplVulkan_InitInfo
     VkQueue                         Queue;
     VkPipelineCache                 PipelineCache;
     VkDescriptorPool                DescriptorPool;
+	int								QueuedFrames;
     const VkAllocationCallbacks*    Allocator;
     void                            (*CheckVkResultFn)(VkResult err);
 };
@@ -35,6 +36,7 @@ struct ImGui_ImplVulkan_InitInfo
 IMGUI_IMPL_API bool     ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass);
 IMGUI_IMPL_API void     ImGui_ImplVulkan_Shutdown();
 IMGUI_IMPL_API void     ImGui_ImplVulkan_NewFrame();
+IMGUI_IMPL_API void     ImGui_ImplVulkan_SetQueuedFramesCount(uint32_t count);
 IMGUI_IMPL_API void     ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);
 IMGUI_IMPL_API bool     ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
 IMGUI_IMPL_API void     ImGui_ImplVulkan_InvalidateFontUploadObjects();
@@ -42,6 +44,7 @@ IMGUI_IMPL_API void     ImGui_ImplVulkan_InvalidateFontUploadObjects();
 // Called by ImGui_ImplVulkan_Init() might be useful elsewhere.
 IMGUI_IMPL_API bool     ImGui_ImplVulkan_CreateDeviceObjects();
 IMGUI_IMPL_API void     ImGui_ImplVulkan_InvalidateDeviceObjects();
+IMGUI_IMPL_API void     ImGui_ImplVulkan_InvalidateFrameDeviceObjects();
 
 
 //-------------------------------------------------------------------------
@@ -63,8 +66,9 @@ struct ImGui_ImplVulkanH_FrameData;
 struct ImGui_ImplVulkanH_WindowData;
 
 IMGUI_IMPL_API void                 ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
-IMGUI_IMPL_API void                 ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h);
+IMGUI_IMPL_API void                 ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
 IMGUI_IMPL_API void                 ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
+IMGUI_IMPL_API void                 ImGui_ImplVulkanH_DestroyFrameData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_FrameData* fd, const VkAllocationCallbacks* allocator);
 IMGUI_IMPL_API VkSurfaceFormatKHR   ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
 IMGUI_IMPL_API VkPresentModeKHR     ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
 IMGUI_IMPL_API int                  ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
@@ -101,7 +105,7 @@ struct ImGui_ImplVulkanH_WindowData
     VkImageView         BackBufferView[16];
     VkFramebuffer       Framebuffer[16];
     uint32_t            FrameIndex;
-    ImGui_ImplVulkanH_FrameData Frames[IMGUI_VK_QUEUED_FRAMES];
+    ImVector<ImGui_ImplVulkanH_FrameData> Frames;
 
     IMGUI_IMPL_API ImGui_ImplVulkanH_WindowData();
 };