Browse Source

Add support for multiple in-flight frames

master
Amber 2 years ago
parent
commit
2deb04f9ed
  1. 60
      src/main.c

60
src/main.c

@ -29,6 +29,7 @@ typedef struct SwapChainSupportDetails {
VkPresentModeKHR* present_modes; VkPresentModeKHR* present_modes;
} SwapChainSupportDetails; } SwapChainSupportDetails;
#define MAX_FRAMES_IN_FLIGHT 2
typedef struct ApplicationState { typedef struct ApplicationState {
GLFWwindow* window; GLFWwindow* window;
@ -64,13 +65,13 @@ typedef struct ApplicationState {
VkFramebuffer* framebuffers; VkFramebuffer* framebuffers;
VkCommandPool commandPool; VkCommandPool commandPool;
VkCommandBuffer command_buffer; VkCommandBuffer command_buffer[MAX_FRAMES_IN_FLIGHT];
//synchronization objects //synchronization objects
//semaphoers are gpu<->gpu, fences are cpu<->gpu //semaphoers are gpu<->gpu, fences are cpu<->gpu
VkSemaphore image_available_semaph; VkSemaphore image_available_semaph[MAX_FRAMES_IN_FLIGHT];
VkSemaphore render_finished_sempah; VkSemaphore render_finished_sempah[MAX_FRAMES_IN_FLIGHT];
VkFence in_flight_frames; VkFence in_flight_frames[MAX_FRAMES_IN_FLIGHT];
} ApplicationState; } ApplicationState;
typedef struct QueueFamilyIndices { typedef struct QueueFamilyIndices {
@ -627,6 +628,7 @@ void create_render_pass(ApplicationState* state) {
//wait on the color attachment //wait on the color attachment
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = 0; 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.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_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_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 //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.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"); printf("failed to allocated command buffer");
exit(1); exit(1);
} }
@ -951,11 +953,13 @@ void create_sync_objects(ApplicationState* state) {
//initialize it to signalled so we can draw the first frame //initialize it to signalled so we can draw the first frame
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
if (vkCreateSemaphore(state->device, &semaphore_info, NULL, &state->image_available_semaph) != VK_SUCCESS || for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
vkCreateSemaphore(state->device, &semaphore_info, NULL, &state->render_finished_sempah) != VK_SUCCESS || if (vkCreateSemaphore(state->device, &semaphore_info, NULL, &state->image_available_semaph[i]) != VK_SUCCESS ||
vkCreateFence(state->device, &fence_info, NULL, &state->in_flight_frames)) { vkCreateSemaphore(state->device, &semaphore_info, NULL, &state->render_finished_sempah[i]) != VK_SUCCESS ||
printf("failed to create sync objects\n"); vkCreateFence(state->device, &fence_info, NULL, &state->in_flight_frames[i])) {
exit(1); printf("failed to create sync objects\n");
exit(1);
}
} }
} }
@ -974,37 +978,36 @@ void init_vulkan(ApplicationState* state) {
create_sync_objects(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 //wait for the previous frame to be rendered
vkWaitForFences(state->device, 1, &state->in_flight_frames, VK_TRUE, UINT64_MAX); vkWaitForFences(state->device, 1, &state->in_flight_frames[current_frame], VK_TRUE, UINT64_MAX);
vkResetFences(state->device, 1, &state->in_flight_frames); vkResetFences(state->device, 1, &state->in_flight_frames[current_frame]);
uint32_t image_index; uint32_t image_index;
//get images from the swapchain and signal when the image is ready //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 //reset and setup the commands we want to run
vkResetCommandBuffer(state->command_buffer, 0); vkResetCommandBuffer(state->command_buffer[current_frame], 0);
record_command_buffer(state, state->command_buffer, image_index); record_command_buffer(state, state->command_buffer[current_frame], image_index);
//specify what to wait for before execution can begin //specify what to wait for before execution can begin
VkSubmitInfo submit_info = {0}; VkSubmitInfo submit_info = {0};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 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}; VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submit_info.waitSemaphoreCount = 1; submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = to_wait; submit_info.pWaitSemaphores = to_wait;
submit_info.pWaitDstStageMask = wait_stages; submit_info.pWaitDstStageMask = wait_stages;
submit_info.commandBufferCount = 1; 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.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = signal_semaphores; 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"); printf("failed to submit draw command buffer");
exit(1); exit(1);
} }
@ -1021,19 +1024,24 @@ void draw_frame(ApplicationState* state) {
present_info.pResults = NULL; present_info.pResults = NULL;
vkQueuePresentKHR(state->present_queue, &present_info); vkQueuePresentKHR(state->present_queue, &present_info);
current_frame = (current_frame + 1) % MAX_FRAMES_IN_FLIGHT;
} }
void main_loop(ApplicationState* state) { void main_loop(ApplicationState* state) {
uint32_t current_frame = 0;
while(!glfwWindowShouldClose(state->window)) { while(!glfwWindowShouldClose(state->window)) {
draw_frame(state); draw_frame(state, current_frame);
glfwPollEvents(); glfwPollEvents();
} }
} }
void terminate(ApplicationState* state) { void terminate(ApplicationState* state) {
vkDestroyFence(state->device, state->in_flight_frames, NULL); for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
vkDestroySemaphore(state->device, state->image_available_semaph, NULL); vkDestroyFence(state->device, state->in_flight_frames[i], NULL);
vkDestroySemaphore(state->device, state->render_finished_sempah, 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); vkDestroyCommandPool(state->device, state->commandPool, NULL);
for (int i = 0; i < state->swapchain_image_count; i++) { for (int i = 0; i < state->swapchain_image_count; i++) {
vkDestroyFramebuffer(state->device, state->framebuffers[i], NULL); vkDestroyFramebuffer(state->device, state->framebuffers[i], NULL);

Loading…
Cancel
Save