From 2deb04f9ed8c9af493e9a922ebc2ea678954d9a3 Mon Sep 17 00:00:00 2001 From: Amber Date: Wed, 26 Oct 2022 09:39:28 +0200 Subject: [PATCH] Add support for multiple in-flight frames --- src/main.c | 60 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/main.c b/src/main.c index 8a0bc9e..9066938 100644 --- a/src/main.c +++ b/src/main.c @@ -29,6 +29,7 @@ typedef struct SwapChainSupportDetails { VkPresentModeKHR* present_modes; } SwapChainSupportDetails; +#define MAX_FRAMES_IN_FLIGHT 2 typedef struct ApplicationState { GLFWwindow* window; @@ -64,13 +65,13 @@ typedef struct ApplicationState { VkFramebuffer* framebuffers; VkCommandPool commandPool; - VkCommandBuffer command_buffer; + VkCommandBuffer command_buffer[MAX_FRAMES_IN_FLIGHT]; //synchronization objects //semaphoers are gpu<->gpu, fences are cpu<->gpu - VkSemaphore image_available_semaph; - VkSemaphore render_finished_sempah; - VkFence in_flight_frames; + VkSemaphore image_available_semaph[MAX_FRAMES_IN_FLIGHT]; + VkSemaphore render_finished_sempah[MAX_FRAMES_IN_FLIGHT]; + VkFence in_flight_frames[MAX_FRAMES_IN_FLIGHT]; } ApplicationState; typedef struct QueueFamilyIndices { @@ -627,6 +628,7 @@ void create_render_pass(ApplicationState* state) { //wait on the color attachment dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency.srcAccessMask = 0; + //the part of the subpass when the attachment is written has to wait dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; @@ -871,9 +873,9 @@ void create_command_buffer(ApplicationState* state) { //VK_COMMAND_BUFFER_LEVEL_PRIMARY: Can be submitted to a queue for execution, but cannot be called from other command buffers. //VK_COMMAND_BUFFER_LEVEL_SECONDARY: Cannot be submitted directly, but can be called from primary command buffers command_buf_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - command_buf_allocate_info.commandBufferCount = 1; + command_buf_allocate_info.commandBufferCount = MAX_FRAMES_IN_FLIGHT; - if (vkAllocateCommandBuffers(state->device, &command_buf_allocate_info, &state->command_buffer) != VK_SUCCESS) { + if (vkAllocateCommandBuffers(state->device, &command_buf_allocate_info, state->command_buffer) != VK_SUCCESS) { printf("failed to allocated command buffer"); exit(1); } @@ -951,11 +953,13 @@ void create_sync_objects(ApplicationState* state) { //initialize it to signalled so we can draw the first frame fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; - if (vkCreateSemaphore(state->device, &semaphore_info, NULL, &state->image_available_semaph) != VK_SUCCESS || - vkCreateSemaphore(state->device, &semaphore_info, NULL, &state->render_finished_sempah) != VK_SUCCESS || - vkCreateFence(state->device, &fence_info, NULL, &state->in_flight_frames)) { - printf("failed to create sync objects\n"); - exit(1); + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + if (vkCreateSemaphore(state->device, &semaphore_info, NULL, &state->image_available_semaph[i]) != VK_SUCCESS || + vkCreateSemaphore(state->device, &semaphore_info, NULL, &state->render_finished_sempah[i]) != VK_SUCCESS || + vkCreateFence(state->device, &fence_info, NULL, &state->in_flight_frames[i])) { + printf("failed to create sync objects\n"); + exit(1); + } } } @@ -974,37 +978,36 @@ void init_vulkan(ApplicationState* state) { create_sync_objects(state); } -void draw_frame(ApplicationState* state) { +void draw_frame(ApplicationState* state, uint32_t current_frame) { //wait for the previous frame to be rendered - vkWaitForFences(state->device, 1, &state->in_flight_frames, VK_TRUE, UINT64_MAX); - vkResetFences(state->device, 1, &state->in_flight_frames); + vkWaitForFences(state->device, 1, &state->in_flight_frames[current_frame], VK_TRUE, UINT64_MAX); + vkResetFences(state->device, 1, &state->in_flight_frames[current_frame]); uint32_t image_index; //get images from the swapchain and signal when the image is ready - vkAcquireNextImageKHR(state->device, state->swapchain, UINT64_MAX, state->image_available_semaph, VK_NULL_HANDLE, &image_index); + vkAcquireNextImageKHR(state->device, state->swapchain, UINT64_MAX, state->image_available_semaph[current_frame], VK_NULL_HANDLE, &image_index); //reset and setup the commands we want to run - vkResetCommandBuffer(state->command_buffer, 0); - record_command_buffer(state, state->command_buffer, image_index); - + vkResetCommandBuffer(state->command_buffer[current_frame], 0); + record_command_buffer(state, state->command_buffer[current_frame], image_index); //specify what to wait for before execution can begin VkSubmitInfo submit_info = {0}; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - VkSemaphore to_wait[] = {state->image_available_semaph}; + VkSemaphore to_wait[] = {state->image_available_semaph[current_frame]}; VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; submit_info.waitSemaphoreCount = 1; submit_info.pWaitSemaphores = to_wait; submit_info.pWaitDstStageMask = wait_stages; submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &state->command_buffer; + submit_info.pCommandBuffers = &state->command_buffer[current_frame]; - VkSemaphore signal_semaphores[] = {state->render_finished_sempah}; + VkSemaphore signal_semaphores[] = {state->render_finished_sempah[current_frame]}; submit_info.signalSemaphoreCount = 1; submit_info.pSignalSemaphores = signal_semaphores; - if (vkQueueSubmit(state->graphics_queue, 1, &submit_info, state->in_flight_frames) != VK_SUCCESS) { + if (vkQueueSubmit(state->graphics_queue, 1, &submit_info, state->in_flight_frames[current_frame]) != VK_SUCCESS) { printf("failed to submit draw command buffer"); exit(1); } @@ -1021,19 +1024,24 @@ void draw_frame(ApplicationState* state) { present_info.pResults = NULL; vkQueuePresentKHR(state->present_queue, &present_info); + + current_frame = (current_frame + 1) % MAX_FRAMES_IN_FLIGHT; } void main_loop(ApplicationState* state) { + uint32_t current_frame = 0; while(!glfwWindowShouldClose(state->window)) { - draw_frame(state); + draw_frame(state, current_frame); glfwPollEvents(); } } void terminate(ApplicationState* state) { - vkDestroyFence(state->device, state->in_flight_frames, NULL); - vkDestroySemaphore(state->device, state->image_available_semaph, NULL); - vkDestroySemaphore(state->device, state->render_finished_sempah, NULL); + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + vkDestroyFence(state->device, state->in_flight_frames[i], NULL); + vkDestroySemaphore(state->device, state->image_available_semaph[i], NULL); + vkDestroySemaphore(state->device, state->render_finished_sempah[i], NULL); + } vkDestroyCommandPool(state->device, state->commandPool, NULL); for (int i = 0; i < state->swapchain_image_count; i++) { vkDestroyFramebuffer(state->device, state->framebuffers[i], NULL);