Browse Source

Add drawing functionality to actually display a triangle.

master
Amber 2 years ago
parent
commit
9b9c0675f0
  1. 185
      src/main.c

185
src/main.c

@ -62,6 +62,15 @@ typedef struct ApplicationState {
VkPipeline graphics_pipeline; VkPipeline graphics_pipeline;
VkFramebuffer* framebuffers; VkFramebuffer* framebuffers;
VkCommandPool commandPool;
VkCommandBuffer command_buffer;
//synchronization objects
//semaphoers are gpu<->gpu, fences are cpu<->gpu
VkSemaphore image_available_semaph;
VkSemaphore render_finished_sempah;
VkFence in_flight_frames;
} ApplicationState; } ApplicationState;
typedef struct QueueFamilyIndices { typedef struct QueueFamilyIndices {
@ -598,6 +607,20 @@ void create_render_pass(ApplicationState* state) {
render_pass_info.subpassCount = 1; render_pass_info.subpassCount = 1;
render_pass_info.pSubpasses = &subpass; render_pass_info.pSubpasses = &subpass;
//subpass dependencies
VkSubpassDependency dependency = {0};
//implicit subpass before or after rendering is complete
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
//wait on the color attachment
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = 0;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
render_pass_info.dependencyCount = 1;
render_pass_info.pDependencies = &dependency;
if (vkCreateRenderPass(state->device, &render_pass_info, NULL, &state->render_pass) != VK_SUCCESS) { if (vkCreateRenderPass(state->device, &render_pass_info, NULL, &state->render_pass) != VK_SUCCESS) {
printf("failed to create render pass"); printf("failed to create render pass");
exit(1); exit(1);
@ -813,6 +836,116 @@ void create_framebuffers(ApplicationState* state) {
printf("created framebuffers\n"); printf("created framebuffers\n");
} }
void create_command_pool(ApplicationState* state) {
QueueFamilyIndices families = find_queue_families(state, state->physical_device);
VkCommandPoolCreateInfo pool_info = {0};
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
//Allow command buffers to be rerecorded individually
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
pool_info.queueFamilyIndex = families.graphics_queue;
if (vkCreateCommandPool(state->device, &pool_info, NULL, &state->commandPool) != VK_SUCCESS) {
printf("failed to create command pool");
exit(1);
}
printf("created command pools\n");
}
void create_command_buffer(ApplicationState* state) {
VkCommandBufferAllocateInfo command_buf_allocate_info = {0};
command_buf_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buf_allocate_info.commandPool = state->commandPool;
//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;
if (vkAllocateCommandBuffers(state->device, &command_buf_allocate_info, &state->command_buffer) != VK_SUCCESS) {
printf("failed to allocated command buffer");
exit(1);
}
printf("created command buffer\n");
}
void record_command_buffer(ApplicationState* state, VkCommandBuffer command_buffer, uint32_t image_index) {
VkCommandBufferBeginInfo begin_info = {0};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags = 0;
begin_info.pInheritanceInfo = NULL;
if (vkBeginCommandBuffer(command_buffer, &begin_info) != VK_SUCCESS) {
printf("failed to begin recording\n");
exit(1);
}
printf("start recording command buffer\n");
VkRenderPassBeginInfo render_pass_info = {0};
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_info.renderPass = state->render_pass;
render_pass_info.framebuffer = state->framebuffers[image_index];
render_pass_info.renderArea.offset.x = 0;
render_pass_info.renderArea.offset.y = 0;
render_pass_info.renderArea.extent = state->swapchain_extent;
VkClearValue clearColor = {0};
render_pass_info.clearValueCount = 1;
render_pass_info.pClearValues = &clearColor;
//can also be VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS to execute command stored in secondary buffers
vkCmdBeginRenderPass(command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, state->graphics_pipeline);
VkViewport viewport = {0};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = (float)state->swapchain_extent.width;
viewport.height = (float)state->swapchain_extent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
//0 and 1 are the first and the count
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
//we want to draw all of the framebuffer
VkRect2D scissor = {0};
scissor.offset.x = 0;
scissor.offset.y = 0;
scissor.extent = state->swapchain_extent;
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
//vertex count, instance count, first vertex and first instance
vkCmdDraw(command_buffer, 3, 1, 0, 0);
vkCmdEndRenderPass(command_buffer);
if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS) {
printf("failed to record command buffer\n");
exit(1);
}
printf("recorded command buffer\n");
}
void create_sync_objects(ApplicationState* state) {
VkSemaphoreCreateInfo semaphore_info = {0};
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
VkFenceCreateInfo fence_info = {0};
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
//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);
}
}
void init_vulkan(ApplicationState* state) { void init_vulkan(ApplicationState* state) {
create_instance(state); create_instance(state);
create_surface(state); create_surface(state);
@ -823,15 +956,67 @@ void init_vulkan(ApplicationState* state) {
create_render_pass(state); create_render_pass(state);
create_graphics_pipeline(state); create_graphics_pipeline(state);
create_framebuffers(state); create_framebuffers(state);
create_command_pool(state);
create_command_buffer(state);
create_sync_objects(state);
}
void draw_frame(ApplicationState* state) {
vkWaitForFences(state->device, 1, &state->in_flight_frames, VK_TRUE, UINT64_MAX);
vkResetFences(state->device, 1, &state->in_flight_frames);
uint32_t image_index;
vkAcquireNextImageKHR(state->device, state->swapchain, UINT64_MAX, state->image_available_semaph, VK_NULL_HANDLE, &image_index);
vkResetCommandBuffer(state->command_buffer, 0);
record_command_buffer(state, state->command_buffer, image_index);
VkSubmitInfo submit_info = {0};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore to_wait[] = {state->image_available_semaph};
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;
VkSemaphore signal_semaphores[] = {state->render_finished_sempah};
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = signal_semaphores;
if (vkQueueSubmit(state->graphics_queue, 1, &submit_info, state->in_flight_frames) != VK_SUCCESS) {
printf("failed to submit draw command buffer");
exit(1);
}
VkPresentInfoKHR present_info = {0};
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = signal_semaphores;
VkSwapchainKHR swapchains[] = {state->swapchain};
present_info.swapchainCount = 1;
present_info.pSwapchains = swapchains;
present_info.pImageIndices = &image_index;
present_info.pResults = NULL;
vkQueuePresentKHR(state->present_queue, &present_info);
} }
void main_loop(ApplicationState* state) { void main_loop(ApplicationState* state) {
while(!glfwWindowShouldClose(state->window)) { while(!glfwWindowShouldClose(state->window)) {
draw_frame(state);
glfwPollEvents(); glfwPollEvents();
} }
} }
void terminate(ApplicationState* state) { 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);
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