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 { @@ -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 { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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);

Loading…
Cancel
Save