mirror of
https://github.com/Drezil/imgui.git
synced 2024-11-15 09:27:00 +00:00
Image presentation now depends on the completeness of command buffer submission through semaphores.
To maintain maximum frame rate we render to the last acquired swapchain image but present the last but one drawn image. This behavior is optional through conditional compilation macros.
This commit is contained in:
parent
a9add1ce63
commit
201d589714
@ -13,7 +13,9 @@
|
|||||||
|
|
||||||
#define IMGUI_MAX_POSSIBLE_BACK_BUFFERS 16
|
#define IMGUI_MAX_POSSIBLE_BACK_BUFFERS 16
|
||||||
#define IMGUI_UNLIMITED_FRAME_RATE
|
#define IMGUI_UNLIMITED_FRAME_RATE
|
||||||
|
//#ifdef _DEBUG
|
||||||
//#define IMGUI_VULKAN_DEBUG_REPORT
|
//#define IMGUI_VULKAN_DEBUG_REPORT
|
||||||
|
//#endif
|
||||||
|
|
||||||
static VkAllocationCallbacks* g_Allocator = NULL;
|
static VkAllocationCallbacks* g_Allocator = NULL;
|
||||||
static VkInstance g_Instance = VK_NULL_HANDLE;
|
static VkInstance g_Instance = VK_NULL_HANDLE;
|
||||||
@ -34,7 +36,7 @@ static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
|
|||||||
static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
|
static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
|
||||||
|
|
||||||
static int fb_width, fb_height;
|
static int fb_width, fb_height;
|
||||||
static uint32_t g_BackBufferIndex = 0;
|
static uint32_t g_BackbufferIndices[IMGUI_VK_QUEUED_FRAMES]; // keep track of recently rendered swapchain frame indices
|
||||||
static uint32_t g_BackBufferCount = 0;
|
static uint32_t g_BackBufferCount = 0;
|
||||||
static VkImage g_BackBuffer[IMGUI_MAX_POSSIBLE_BACK_BUFFERS] = {};
|
static VkImage g_BackBuffer[IMGUI_MAX_POSSIBLE_BACK_BUFFERS] = {};
|
||||||
static VkImageView g_BackBufferView[IMGUI_MAX_POSSIBLE_BACK_BUFFERS] = {};
|
static VkImageView g_BackBufferView[IMGUI_MAX_POSSIBLE_BACK_BUFFERS] = {};
|
||||||
@ -44,7 +46,8 @@ static uint32_t g_FrameIndex = 0;
|
|||||||
static VkCommandPool g_CommandPool[IMGUI_VK_QUEUED_FRAMES];
|
static VkCommandPool g_CommandPool[IMGUI_VK_QUEUED_FRAMES];
|
||||||
static VkCommandBuffer g_CommandBuffer[IMGUI_VK_QUEUED_FRAMES];
|
static VkCommandBuffer g_CommandBuffer[IMGUI_VK_QUEUED_FRAMES];
|
||||||
static VkFence g_Fence[IMGUI_VK_QUEUED_FRAMES];
|
static VkFence g_Fence[IMGUI_VK_QUEUED_FRAMES];
|
||||||
static VkSemaphore g_Semaphore[IMGUI_VK_QUEUED_FRAMES];
|
static VkSemaphore g_PresentCompleteSemaphore[IMGUI_VK_QUEUED_FRAMES];
|
||||||
|
static VkSemaphore g_RenderCompleteSemaphore[IMGUI_VK_QUEUED_FRAMES];
|
||||||
|
|
||||||
static VkClearValue g_ClearValue = {};
|
static VkClearValue g_ClearValue = {};
|
||||||
|
|
||||||
@ -452,7 +455,9 @@ static void setup_vulkan(GLFWwindow* window)
|
|||||||
{
|
{
|
||||||
VkSemaphoreCreateInfo info = {};
|
VkSemaphoreCreateInfo info = {};
|
||||||
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
err = vkCreateSemaphore(g_Device, &info, g_Allocator, &g_Semaphore[i]);
|
err = vkCreateSemaphore(g_Device, &info, g_Allocator, &g_PresentCompleteSemaphore[i]);
|
||||||
|
check_vk_result(err);
|
||||||
|
err = vkCreateSemaphore(g_Device, &info, g_Allocator, &g_RenderCompleteSemaphore[i]);
|
||||||
check_vk_result(err);
|
check_vk_result(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -492,7 +497,8 @@ static void cleanup_vulkan()
|
|||||||
vkDestroyFence(g_Device, g_Fence[i], g_Allocator);
|
vkDestroyFence(g_Device, g_Fence[i], g_Allocator);
|
||||||
vkFreeCommandBuffers(g_Device, g_CommandPool[i], 1, &g_CommandBuffer[i]);
|
vkFreeCommandBuffers(g_Device, g_CommandPool[i], 1, &g_CommandBuffer[i]);
|
||||||
vkDestroyCommandPool(g_Device, g_CommandPool[i], g_Allocator);
|
vkDestroyCommandPool(g_Device, g_CommandPool[i], g_Allocator);
|
||||||
vkDestroySemaphore(g_Device, g_Semaphore[i], g_Allocator);
|
vkDestroySemaphore(g_Device, g_PresentCompleteSemaphore[i], g_Allocator);
|
||||||
|
vkDestroySemaphore(g_Device, g_RenderCompleteSemaphore[i], g_Allocator);
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < g_BackBufferCount; i++)
|
for (uint32_t i = 0; i < g_BackBufferCount; i++)
|
||||||
{
|
{
|
||||||
@ -525,7 +531,7 @@ static void frame_begin()
|
|||||||
check_vk_result(err);
|
check_vk_result(err);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
err = vkAcquireNextImageKHR(g_Device, g_Swapchain, UINT64_MAX, g_Semaphore[g_FrameIndex], VK_NULL_HANDLE, &g_BackBufferIndex);
|
err = vkAcquireNextImageKHR(g_Device, g_Swapchain, UINT64_MAX, g_PresentCompleteSemaphore[g_FrameIndex], VK_NULL_HANDLE, &g_BackbufferIndices[g_FrameIndex]);
|
||||||
check_vk_result(err);
|
check_vk_result(err);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -541,7 +547,7 @@ static void frame_begin()
|
|||||||
VkRenderPassBeginInfo info = {};
|
VkRenderPassBeginInfo info = {};
|
||||||
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
info.renderPass = g_RenderPass;
|
info.renderPass = g_RenderPass;
|
||||||
info.framebuffer = g_Framebuffer[g_BackBufferIndex];
|
info.framebuffer = g_Framebuffer[g_BackbufferIndices[g_FrameIndex]];
|
||||||
info.renderArea.extent.width = fb_width;
|
info.renderArea.extent.width = fb_width;
|
||||||
info.renderArea.extent.height = fb_height;
|
info.renderArea.extent.height = fb_height;
|
||||||
info.clearValueCount = 1;
|
info.clearValueCount = 1;
|
||||||
@ -559,10 +565,12 @@ static void frame_end()
|
|||||||
VkSubmitInfo info = {};
|
VkSubmitInfo info = {};
|
||||||
info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
info.waitSemaphoreCount = 1;
|
info.waitSemaphoreCount = 1;
|
||||||
info.pWaitSemaphores = &g_Semaphore[g_FrameIndex];
|
info.pWaitSemaphores = &g_PresentCompleteSemaphore[g_FrameIndex];
|
||||||
info.pWaitDstStageMask = &wait_stage;
|
info.pWaitDstStageMask = &wait_stage;
|
||||||
info.commandBufferCount = 1;
|
info.commandBufferCount = 1;
|
||||||
info.pCommandBuffers = &g_CommandBuffer[g_FrameIndex];
|
info.pCommandBuffers = &g_CommandBuffer[g_FrameIndex];
|
||||||
|
info.signalSemaphoreCount = 1;
|
||||||
|
info.pSignalSemaphores = &g_RenderCompleteSemaphore[g_FrameIndex];
|
||||||
|
|
||||||
err = vkEndCommandBuffer(g_CommandBuffer[g_FrameIndex]);
|
err = vkEndCommandBuffer(g_CommandBuffer[g_FrameIndex]);
|
||||||
check_vk_result(err);
|
check_vk_result(err);
|
||||||
@ -571,18 +579,32 @@ static void frame_end()
|
|||||||
err = vkQueueSubmit(g_Queue, 1, &info, g_Fence[g_FrameIndex]);
|
err = vkQueueSubmit(g_Queue, 1, &info, g_Fence[g_FrameIndex]);
|
||||||
check_vk_result(err);
|
check_vk_result(err);
|
||||||
}
|
}
|
||||||
{
|
}
|
||||||
|
|
||||||
|
static void frame_present()
|
||||||
|
{
|
||||||
|
VkResult err;
|
||||||
|
// If IMGUI_UNLIMITED_FRAME_RATE is defined we present the latest but one frame
|
||||||
|
// Othrewise we present the latest rendered frame
|
||||||
|
#ifdef IMGUI_UNLIMITED_FRAME_RATE
|
||||||
|
uint32_t PresentIndex = (g_FrameIndex + IMGUI_VK_QUEUED_FRAMES - 1) % IMGUI_VK_QUEUED_FRAMES;
|
||||||
|
#else
|
||||||
|
uint32_t PresentIndex = g_FrameIndex;
|
||||||
|
#endif // IMGUI_UNLIMITED_FRAME_RATE
|
||||||
|
|
||||||
VkSwapchainKHR swapchains[1] = {g_Swapchain};
|
VkSwapchainKHR swapchains[1] = {g_Swapchain};
|
||||||
uint32_t indices[1] = {g_BackBufferIndex};
|
uint32_t indices[1] = {g_BackbufferIndices[PresentIndex]};
|
||||||
VkPresentInfoKHR info = {};
|
VkPresentInfoKHR info = {};
|
||||||
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||||
|
info.waitSemaphoreCount = 1;
|
||||||
|
info.pWaitSemaphores = &g_RenderCompleteSemaphore[PresentIndex];
|
||||||
info.swapchainCount = 1;
|
info.swapchainCount = 1;
|
||||||
info.pSwapchains = swapchains;
|
info.pSwapchains = swapchains;
|
||||||
info.pImageIndices = indices;
|
info.pImageIndices = indices;
|
||||||
err = vkQueuePresentKHR(g_Queue, &info);
|
err = vkQueuePresentKHR(g_Queue, &info);
|
||||||
check_vk_result(err);
|
check_vk_result(err);
|
||||||
}
|
|
||||||
g_FrameIndex = (g_FrameIndex+1) % IMGUI_VK_QUEUED_FRAMES;
|
g_FrameIndex = (g_FrameIndex + 1) % IMGUI_VK_QUEUED_FRAMES;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void error_callback(int error, const char* description)
|
static void error_callback(int error, const char* description)
|
||||||
@ -660,6 +682,18 @@ int main(int, char**)
|
|||||||
bool show_another_window = false;
|
bool show_another_window = false;
|
||||||
ImVec4 clear_color = ImColor(114, 144, 154);
|
ImVec4 clear_color = ImColor(114, 144, 154);
|
||||||
|
|
||||||
|
// When IMGUI_UNLIMITED_FRAME_RATE is defined we render into latest image acquired from the swapchain
|
||||||
|
// but we display the image which was rendered before
|
||||||
|
// hence we must render once and increase the g_FrameIndex without presenting, which we do befor entering the render loop
|
||||||
|
// this is also the reason why frame_end() is split into frame_end() and frame_present(), the latter one not being called here
|
||||||
|
#ifdef IMGUI_UNLIMITED_FRAME_RATE
|
||||||
|
ImGui_ImplGlfwVulkan_NewFrame();
|
||||||
|
frame_begin();
|
||||||
|
ImGui_ImplGlfwVulkan_Render(g_CommandBuffer[g_FrameIndex]);
|
||||||
|
frame_end();
|
||||||
|
g_FrameIndex = (g_FrameIndex + 1) % IMGUI_VK_QUEUED_FRAMES;
|
||||||
|
#endif // IMGUI_UNLIMITED_FRAME_RATE
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
while (!glfwWindowShouldClose(window))
|
while (!glfwWindowShouldClose(window))
|
||||||
{
|
{
|
||||||
@ -702,6 +736,7 @@ int main(int, char**)
|
|||||||
frame_begin();
|
frame_begin();
|
||||||
ImGui_ImplGlfwVulkan_Render(g_CommandBuffer[g_FrameIndex]);
|
ImGui_ImplGlfwVulkan_Render(g_CommandBuffer[g_FrameIndex]);
|
||||||
frame_end();
|
frame_end();
|
||||||
|
frame_present();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
|
Loading…
Reference in New Issue
Block a user