diff options
| author | Clément Sibille <clements@lisible.xyz> | 2025-03-25 07:31:37 +0100 |
|---|---|---|
| committer | Clément Sibille <clements@lisible.xyz> | 2025-03-25 07:31:37 +0100 |
| commit | a33f692a0a0d3d4210044bdd93ec6d067a17c8b5 (patch) | |
| tree | 8fa34185bf3c184b67077044fceaceb957c9d7a1 /src | |
| parent | 979ec073d45f4111da8060f4ac081101c85d4a0e (diff) | |
Render hello triangle
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.c | 5 | ||||
| -rw-r--r-- | src/renderer.c | 186 | ||||
| -rw-r--r-- | src/renderer.h | 11 |
3 files changed, 190 insertions, 12 deletions
@@ -24,9 +24,12 @@ int main(void) { goto out_main_loop; } } + + vgltf_renderer_triangle_pass(&renderer); + renderer.current_frame = + (renderer.current_frame + 1) % VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT; } out_main_loop: - vgltf_renderer_deinit(&renderer); vgltf_platform_deinit(&platform); return 0; diff --git a/src/renderer.c b/src/renderer.c index c241fe1..d95cf99 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -894,13 +894,24 @@ static bool vgltf_renderer_create_render_pass(struct vgltf_renderer *renderer) { }; VkSubpassDescription subpass = {.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, - .pColorAttachments = &color_attachment_ref}; + .pColorAttachments = &color_attachment_ref, + .colorAttachmentCount = 1}; + VkSubpassDependency dependency = { + .srcSubpass = VK_SUBPASS_EXTERNAL, + .dstSubpass = 0, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = 0, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT}; + VkRenderPassCreateInfo render_pass_info = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, .attachmentCount = 1, .pAttachments = &color_attachment, .subpassCount = 1, - .pSubpasses = &subpass}; + .pSubpasses = &subpass, + .dependencyCount = 1, + .pDependencies = &dependency}; if (vkCreateRenderPass(renderer->device, &render_pass_info, nullptr, &renderer->render_pass) != VK_SUCCESS) { @@ -1112,11 +1123,11 @@ vgltf_renderer_create_command_buffer(struct vgltf_renderer *renderer) { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .commandPool = renderer->command_pool, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = 1}; + .commandBufferCount = VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT}; if (vkAllocateCommandBuffers(renderer->device, &allocate_info, - &renderer->command_buffer) != VK_SUCCESS) { - VGLTF_LOG_ERR("Couldn't allocate command buffer"); + renderer->command_buffer) != VK_SUCCESS) { + VGLTF_LOG_ERR("Couldn't allocate command buffers"); goto err; } @@ -1125,11 +1136,155 @@ err: return false; } -static bool vgltf_renderer_record_command_buffer +static bool +vgltf_renderer_create_sync_objects(struct vgltf_renderer *renderer) { + VkSemaphoreCreateInfo semaphore_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + }; + + VkFenceCreateInfo fence_info = {.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = VK_FENCE_CREATE_SIGNALED_BIT}; + + int frame_in_flight_index = 0; + for (; frame_in_flight_index < VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT; + frame_in_flight_index++) { + if (vkCreateSemaphore( + renderer->device, &semaphore_info, nullptr, + &renderer->image_available_semaphores[frame_in_flight_index]) != + VK_SUCCESS || + vkCreateSemaphore( + renderer->device, &semaphore_info, nullptr, + &renderer->render_finished_semaphores[frame_in_flight_index]) != + VK_SUCCESS || + vkCreateFence(renderer->device, &fence_info, nullptr, + &renderer->in_flight_fences[frame_in_flight_index]) != + VK_SUCCESS) { + VGLTF_LOG_ERR("Couldn't create sync objects"); + goto err; + } + } + + return true; +err: + for (int frame_in_flight_to_delete_index = 0; + frame_in_flight_to_delete_index < frame_in_flight_index; + frame_in_flight_to_delete_index++) { + vkDestroyFence(renderer->device, + renderer->in_flight_fences[frame_in_flight_index], nullptr); + vkDestroySemaphore( + renderer->device, + renderer->render_finished_semaphores[frame_in_flight_index], nullptr); + vkDestroySemaphore( + renderer->device, + renderer->image_available_semaphores[frame_in_flight_index], nullptr); + } + return false; +} + +bool vgltf_renderer_triangle_pass(struct vgltf_renderer *renderer) { + vkWaitForFences(renderer->device, 1, + &renderer->in_flight_fences[renderer->current_frame], VK_TRUE, + UINT64_MAX); + vkResetFences(renderer->device, 1, + &renderer->in_flight_fences[renderer->current_frame]); + + uint32_t image_index; + vkAcquireNextImageKHR( + renderer->device, renderer->swapchain, UINT64_MAX, + renderer->image_available_semaphores[renderer->current_frame], + VK_NULL_HANDLE, &image_index); + + vkResetCommandBuffer(renderer->command_buffer[renderer->current_frame], 0); + VkCommandBufferBeginInfo begin_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + }; + + if (vkBeginCommandBuffer(renderer->command_buffer[renderer->current_frame], + &begin_info) != VK_SUCCESS) { + VGLTF_LOG_ERR("Failed to begin recording command buffer"); + goto err; + } + + VkRenderPassBeginInfo render_pass_info = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = renderer->render_pass, + .framebuffer = renderer->swapchain_framebuffers[image_index], + .renderArea = {.offset = {}, .extent = renderer->swapchain_extent}, + .clearValueCount = 1, + .pClearValues = + &(const VkClearValue){.color = {.float32 = {0.f, 0.f, 0.f, 1.f}}}, + + }; + + vkCmdBeginRenderPass(renderer->command_buffer[renderer->current_frame], + &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBindPipeline(renderer->command_buffer[renderer->current_frame], + VK_PIPELINE_BIND_POINT_GRAPHICS, + renderer->graphics_pipeline); + VkViewport viewport = {.x = 0.f, + .y = 0.f, + .width = (float)renderer->swapchain_extent.width, + .height = (float)renderer->swapchain_extent.height, + .minDepth = 0.f, + .maxDepth = 1.f}; + vkCmdSetViewport(renderer->command_buffer[renderer->current_frame], 0, 1, + &viewport); + VkRect2D scissor = {.offset = {}, .extent = renderer->swapchain_extent}; + vkCmdSetScissor(renderer->command_buffer[renderer->current_frame], 0, 1, + &scissor); + + vkCmdDraw(renderer->command_buffer[renderer->current_frame], 3, 1, 0, 0); + + vkCmdEndRenderPass(renderer->command_buffer[renderer->current_frame]); + + if (vkEndCommandBuffer(renderer->command_buffer[renderer->current_frame]) != + VK_SUCCESS) { + VGLTF_LOG_ERR("Failed to record command buffer"); + goto err; + } + + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + }; + + VkSemaphore wait_semaphores[] = { + renderer->image_available_semaphores[renderer->current_frame]}; + VkPipelineStageFlags wait_stages[] = { + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = wait_semaphores; + submit_info.pWaitDstStageMask = wait_stages; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = + &renderer->command_buffer[renderer->current_frame]; + + VkSemaphore signal_semaphores[] = { + renderer->render_finished_semaphores[renderer->current_frame]}; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = signal_semaphores; + if (vkQueueSubmit(renderer->graphics_queue, 1, &submit_info, + renderer->in_flight_fences[renderer->current_frame]) != + VK_SUCCESS) { + VGLTF_LOG_ERR("Failed to submit draw command buffer"); + goto err; + } + + VkPresentInfoKHR present_info = {.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .waitSemaphoreCount = 1, + .pWaitSemaphores = signal_semaphores}; - bool - vgltf_renderer_init(struct vgltf_renderer *renderer, - struct vgltf_platform *platform) { + VkSwapchainKHR swapchains[] = {renderer->swapchain}; + present_info.swapchainCount = 1; + present_info.pSwapchains = swapchains; + present_info.pImageIndices = &image_index; + vkQueuePresentKHR(renderer->present_queue, &present_info); + return true; +err: + return false; +} + +bool vgltf_renderer_init(struct vgltf_renderer *renderer, + struct vgltf_platform *platform) { if (!vgltf_renderer_create_instance(renderer, platform)) { VGLTF_LOG_ERR("instance creation failed"); goto err; @@ -1190,6 +1345,11 @@ static bool vgltf_renderer_record_command_buffer goto destroy_command_pool; } + if (!vgltf_renderer_create_sync_objects(renderer)) { + VGLTF_LOG_ERR("Couldn't create sync objects"); + goto destroy_command_pool; + } + return true; destroy_command_pool: @@ -1231,6 +1391,14 @@ err: return false; } void vgltf_renderer_deinit(struct vgltf_renderer *renderer) { + vkDeviceWaitIdle(renderer->device); + for (int i = 0; i < VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT; i++) { + vkDestroySemaphore(renderer->device, + renderer->image_available_semaphores[i], nullptr); + vkDestroySemaphore(renderer->device, + renderer->render_finished_semaphores[i], nullptr); + vkDestroyFence(renderer->device, renderer->in_flight_fences[i], nullptr); + } vkDestroyCommandPool(renderer->device, renderer->command_pool, nullptr); for (uint32_t swapchain_framebuffer_index = 0; swapchain_framebuffer_index < renderer->swapchain_image_count; diff --git a/src/renderer.h b/src/renderer.h index c5e5adc..17897b6 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -4,6 +4,7 @@ #include "platform.h" #include <vulkan/vulkan.h> +constexpr int VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT = 2; constexpr int VGLTF_RENDERER_MAX_SWAPCHAIN_IMAGE_COUNT = 32; struct vgltf_renderer { VkInstance instance; @@ -25,10 +26,16 @@ struct vgltf_renderer { VkFramebuffer swapchain_framebuffers[VGLTF_RENDERER_MAX_SWAPCHAIN_IMAGE_COUNT]; VkCommandPool command_pool; - VkCommandBuffer command_buffer; + VkCommandBuffer command_buffer[VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT]; + VkSemaphore + image_available_semaphores[VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT]; + VkSemaphore + render_finished_semaphores[VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT]; + VkFence in_flight_fences[VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT]; + uint32_t current_frame; }; bool vgltf_renderer_init(struct vgltf_renderer *renderer, struct vgltf_platform *platform); void vgltf_renderer_deinit(struct vgltf_renderer *renderer); - +bool vgltf_renderer_triangle_pass(struct vgltf_renderer *renderer); #endif // VGLTF_RENDERER_H |
