|
|
|
@ -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,13 +953,15 @@ void create_sync_objects(ApplicationState* state) {
@@ -951,13 +953,15 @@ 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)) { |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void init_vulkan(ApplicationState* state) { |
|
|
|
|
create_instance(state); |
|
|
|
@ -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); |
|
|
|
|