From 994bb207cb5cb09127876f921c5447795e2210ce Mon Sep 17 00:00:00 2001 From: ravi688 Date: Wed, 22 May 2024 22:15:33 +0530 Subject: [PATCH 1/6] [Bug Fix] Fixed image layout transition related validation error for POINT_LIGHT_SHADOWS - Added vulkan_renderer_wait_idle and renderer_wait_idle - Added support for multiple frame rendering and present in flight - Corrected pipeline barries for image layout transitions in vulkan_renderer_begin_frame and _end_frame - This results in zero vulkan validation layer (synchronization) errors. --- .../internal/vulkan/vulkan_renderer.h | 20 +++- .../internal/vulkan/vulkan_swapchain.h | 2 +- include/renderer/memory_allocation_type.h | 2 + include/renderer/renderer.h | 2 + source/main.c | 4 +- source/renderer/renderer.c | 5 + source/renderer/vulkan/vulkan_camera.c | 4 +- .../renderer/vulkan/vulkan_descriptor_set.c | 2 +- .../vulkan/vulkan_graphics_pipeline.c | 2 +- source/renderer/vulkan/vulkan_mesh.c | 6 +- .../renderer/vulkan/vulkan_pipeline_layout.c | 2 +- source/renderer/vulkan/vulkan_render_pass.c | 6 +- source/renderer/vulkan/vulkan_render_queue.c | 2 +- source/renderer/vulkan/vulkan_renderer.c | 102 ++++++++++++------ source/renderer/vulkan/vulkan_swapchain.c | 4 +- source/renderer/vulkan/vulkan_text_mesh.c | 2 +- 16 files changed, 115 insertions(+), 52 deletions(-) diff --git a/include/renderer/internal/vulkan/vulkan_renderer.h b/include/renderer/internal/vulkan/vulkan_renderer.h index a3392e4a..9f481153 100644 --- a/include/renderer/internal/vulkan/vulkan_renderer.h +++ b/include/renderer/internal/vulkan/vulkan_renderer.h @@ -75,9 +75,21 @@ typedef struct vulkan_renderer_t VkCommandPool vo_command_pool; VkDescriptorPool vo_descriptor_pool; - VkSemaphore vo_image_available_semaphore; - VkSemaphore vo_render_finished_semaphore; - VkFence vo_fence; + /* index of the current frame, it ranges from 0 (inclusive) to swapchain->image_count (exclusive) */ + u32 current_frame_index; + + struct + { + /* number of VkSemaphore or VkFence objects in vo_image_available_semaphores and vo_render_finished_semaphores, or vo_fences */ + u32 primitive_count; + /* semaphores for max number of frames in flight to indicate presentation has finished for them */ + VkSemaphore* vo_image_available_semaphores; + /* semaphores for max number of frames in flight to indicate rendering has finished on them */ + VkSemaphore* vo_render_finished_semaphores; + /* fences */ + VkFence* vo_fences; + } render_present_sync_primitives; + /* global_set::screen_info * { @@ -142,6 +154,8 @@ RENDERER_API void vulkan_renderer_begin_frame(vulkan_renderer_t* renderer); /* ends the command buffer recording */ RENDERER_API void vulkan_renderer_end_frame(vulkan_renderer_t* renderer); +RENDERER_API void vulkan_renderer_wait_idle(vulkan_renderer_t* renderer); + RENDERER_API render_window_t* vulkan_renderer_get_window(vulkan_renderer_t* renderer); END_CPP_COMPATIBLE diff --git a/include/renderer/internal/vulkan/vulkan_swapchain.h b/include/renderer/internal/vulkan/vulkan_swapchain.h index 03b7206a..d7f3e1c6 100644 --- a/include/renderer/internal/vulkan/vulkan_swapchain.h +++ b/include/renderer/internal/vulkan/vulkan_swapchain.h @@ -65,6 +65,6 @@ RENDERER_API void vulkan_swapchain_create_no_alloc(vulkan_renderer_t* renderer, RENDERER_API void vulkan_swapchain_destroy(vulkan_swapchain_t* swapchain); RENDERER_API void vulkan_swapchain_release_resources(vulkan_swapchain_t* swapchain); RENDERER_API void vulkan_swapchain_refresh(vulkan_swapchain_t* swapchain, vulkan_swapchain_create_info_t* create_info); -RENDERER_API u32 vulkan_swapchain_acquire_next_image(vulkan_swapchain_t* swapchain); +RENDERER_API u32 vulkan_swapchain_acquire_next_image(vulkan_swapchain_t* swapchain, VkSemaphore signal_semaphore); END_CPP_COMPATIBLE diff --git a/include/renderer/memory_allocation_type.h b/include/renderer/memory_allocation_type.h index 785ec268..402107f1 100644 --- a/include/renderer/memory_allocation_type.h +++ b/include/renderer/memory_allocation_type.h @@ -111,6 +111,8 @@ typedef enum memory_allocation_type_t MEMORY_ALLOCATION_TYPE_OBJ_VKAPI_ATTACHMENT_DESCRIPTION, MEMORY_ALLOCATION_TYPE_OBJ_VKAPI_DESCRIPTOR_SET_LAYOUT_BINDING_ARRAY, MEMORY_ALLOCATION_TYPE_OBJ_VKAPI_DEVICE_QUEUE_CREATE_INFO_ARRAY, + MEMORY_ALLOCATION_TYPE_OBJ_VKAPI_SEMAPHORE_ARRAY, + MEMORY_ALLOCATION_TYPE_OBJ_VKAPI_FENCE_ARRAY, MEMORY_ALLOCATION_TYPE_OBJ_VKAPI_CLEAR_VALUE_ARRAY, MEMORY_ALLOCATION_TYPE_OBJ_VKAPI_FORMAT_ARRAY, diff --git a/include/renderer/renderer.h b/include/renderer/renderer.h index 4bbb9b46..2c9aee11 100644 --- a/include/renderer/renderer.h +++ b/include/renderer/renderer.h @@ -129,6 +129,8 @@ RENDERER_API void renderer_begin_frame(renderer_t* renderer); */ RENDERER_API void renderer_end_frame(renderer_t* renderer); +RENDERER_API void renderer_wait_idle(renderer_t* renderer); + /* getters */ RENDERER_API render_window_t* renderer_get_window(renderer_t* renderer); RENDERER_API shader_library_t* renderer_get_shader_library(renderer_t* renderer); diff --git a/source/main.c b/source/main.c index a463e57f..777adaca 100644 --- a/source/main.c +++ b/source/main.c @@ -160,7 +160,9 @@ int main(int argc, const char** argv) test->update(driver, deltaTime, test->user_data); } - /* REASON: Takes too much time for complex allocation trees! */ + /* we need to wait for the device to finish any pending tasks, so that all the resources/objects will be unreferenced + * , as test->terminate() destroys the test related objects etc. */ + renderer_wait_idle(driver); test->terminate(driver, test->user_data); test_destroy(test); diff --git a/source/renderer/renderer.c b/source/renderer/renderer.c index 16ffd93a..22a2882e 100644 --- a/source/renderer/renderer.c +++ b/source/renderer/renderer.c @@ -87,6 +87,11 @@ RENDERER_API void renderer_end_frame(renderer_t* renderer) vulkan_renderer_end_frame(renderer->vulkan_handle); } +RENDERER_API void renderer_wait_idle(renderer_t* renderer) +{ + vulkan_renderer_wait_idle(renderer->vulkan_handle); +} + /* getters */ RENDERER_API render_window_t* renderer_get_window(renderer_t* renderer) { diff --git a/source/renderer/vulkan/vulkan_camera.c b/source/renderer/vulkan/vulkan_camera.c index 381f0568..ce129779 100644 --- a/source/renderer/vulkan/vulkan_camera.c +++ b/source/renderer/vulkan/vulkan_camera.c @@ -664,7 +664,7 @@ RENDERER_API void vulkan_camera_release_resources(vulkan_camera_t* camera) UNUSED_FUNCTION static void transition_target_layout_for_write(VkFormat format, vulkan_image_view_t* view) { - VkCommandBuffer cb = view->renderer->vo_command_buffers[view->renderer->swapchain->current_image_index]; + VkCommandBuffer cb = view->renderer->vo_command_buffers[view->renderer->current_frame_index]; switch(format) { case VK_FORMAT_B8G8R8A8_SRGB: @@ -696,7 +696,7 @@ UNUSED_FUNCTION static void transition_target_layout_for_write(VkFormat format, static void transition_target_layout_for_sample(VkFormat format, vulkan_image_view_t* view) { - VkCommandBuffer cb = view->renderer->vo_command_buffers[view->renderer->swapchain->current_image_index]; + VkCommandBuffer cb = view->renderer->vo_command_buffers[view->renderer->current_frame_index]; switch(format) { case VK_FORMAT_B8G8R8A8_SRGB: diff --git a/source/renderer/vulkan/vulkan_descriptor_set.c b/source/renderer/vulkan/vulkan_descriptor_set.c index 4269d7f7..c686180b 100644 --- a/source/renderer/vulkan/vulkan_descriptor_set.c +++ b/source/renderer/vulkan/vulkan_descriptor_set.c @@ -90,7 +90,7 @@ RENDERER_API void vulkan_descriptor_set_release_resources(vulkan_descriptor_set_ RENDERER_API void vulkan_descriptor_set_bind(vulkan_descriptor_set_t* set, u32 set_number, vulkan_pipeline_layout_t* pipeline_layout) { - u32 image_index = set->renderer->swapchain->current_image_index; + u32 image_index = set->renderer->current_frame_index; vkCmdBindDescriptorSets(set->renderer->vo_command_buffers[image_index], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout->vo_handle, set_number, 1, &set->vo_handle, 0, NULL); } diff --git a/source/renderer/vulkan/vulkan_graphics_pipeline.c b/source/renderer/vulkan/vulkan_graphics_pipeline.c index 629bc0cc..dab4b80e 100644 --- a/source/renderer/vulkan/vulkan_graphics_pipeline.c +++ b/source/renderer/vulkan/vulkan_graphics_pipeline.c @@ -223,7 +223,7 @@ RENDERER_API vulkan_graphics_pipeline_t* vulkan_graphics_pipeline_create(vulkan_ RENDERER_API void vulkan_graphics_pipeline_bind(vulkan_graphics_pipeline_t* pipeline) { - AUTO command_buffer = pipeline->renderer->vo_command_buffers[pipeline->renderer->swapchain->current_image_index]; + AUTO command_buffer = pipeline->renderer->vo_command_buffers[pipeline->renderer->current_frame_index]; vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->vo_handle); debug_assert__(!pipeline->is_user_defined_viewport, "For now let's focus on full render area of the render target\n"); diff --git a/source/renderer/vulkan/vulkan_mesh.c b/source/renderer/vulkan/vulkan_mesh.c index 5fa16a33..fbe7dc8e 100644 --- a/source/renderer/vulkan/vulkan_mesh.c +++ b/source/renderer/vulkan/vulkan_mesh.c @@ -143,7 +143,7 @@ RENDERER_API void vulkan_mesh_draw_indexed_instanced_only(vulkan_mesh_t* mesh, u _debug_assert__(mesh->index_buffer.buffer != NULL); _debug_assert__(mesh->index_buffer.index_type != VK_INDEX_TYPE_MAX_ENUM); - VkCommandBuffer vo_command_buffer = mesh->renderer->vo_command_buffers[mesh->renderer->swapchain->current_image_index]; + VkCommandBuffer vo_command_buffer = mesh->renderer->vo_command_buffers[mesh->renderer->current_frame_index]; vkCmdBindIndexBuffer(vo_command_buffer, mesh->index_buffer.buffer->vo_handle, 0, mesh->index_buffer.index_type); vkCmdDrawIndexed(vo_command_buffer, mesh->index_buffer.buffer->count, instance_count, 0, 0, 0); @@ -165,7 +165,7 @@ RENDERER_API void vulkan_mesh_bind_all_vertex_buffers(vulkan_mesh_t* mesh) if(count > 0) { - VkCommandBuffer vo_command_buffer = mesh->renderer->vo_command_buffers[mesh->renderer->swapchain->current_image_index]; + VkCommandBuffer vo_command_buffer = mesh->renderer->vo_command_buffers[mesh->renderer->current_frame_index]; vulkan_command_bind_vertex_buffers(vo_command_buffer, bindings, buffers, count); } } @@ -182,7 +182,7 @@ RENDERER_API void vulkan_mesh_draw_indexed_instanced(vulkan_mesh_t* mesh, u32 in RENDERER_API void vulkan_mesh_draw_instanced(vulkan_mesh_t* mesh, u32 instance_count) { vulkan_mesh_bind_all_vertex_buffers(mesh); - VkCommandBuffer vo_command_buffer = mesh->renderer->vo_command_buffers[mesh->renderer->swapchain->current_image_index]; + VkCommandBuffer vo_command_buffer = mesh->renderer->vo_command_buffers[mesh->renderer->current_frame_index]; vkCmdDraw(vo_command_buffer, CAST_TO(vulkan_vertex_buffer_t*, buf_get_ptr_at(&mesh->vertex_buffers, 0))->buffer->count, instance_count, 0, 0); // set the binding index to zero, for the next frame diff --git a/source/renderer/vulkan/vulkan_pipeline_layout.c b/source/renderer/vulkan/vulkan_pipeline_layout.c index 46bc9195..defa75f0 100644 --- a/source/renderer/vulkan/vulkan_pipeline_layout.c +++ b/source/renderer/vulkan/vulkan_pipeline_layout.c @@ -78,6 +78,6 @@ RENDERER_API void vulkan_pipeline_layout_release_resources(vulkan_pipeline_layou RENDERER_API void vulkan_pipeline_layout_push_constants(vulkan_pipeline_layout_t* layout, VkShaderStageFlagBits stage_flags, u32 offset, u32 size, void* bytes) { - VkCommandBuffer command_buffer = layout->renderer->vo_command_buffers[layout->renderer->swapchain->current_image_index]; + VkCommandBuffer command_buffer = layout->renderer->vo_command_buffers[layout->renderer->current_frame_index]; vkCmdPushConstants(command_buffer, layout->vo_handle, stage_flags, offset, size, bytes); } diff --git a/source/renderer/vulkan/vulkan_render_pass.c b/source/renderer/vulkan/vulkan_render_pass.c index 70712737..1088266d 100644 --- a/source/renderer/vulkan/vulkan_render_pass.c +++ b/source/renderer/vulkan/vulkan_render_pass.c @@ -241,14 +241,14 @@ RENDERER_API void vulkan_render_pass_begin(vulkan_render_pass_t* render_pass, u3 .clearValueCount = render_pass->clear_value_count, .pClearValues = render_pass->vo_clear_values }; - vkCmdBeginRenderPass(render_pass->renderer->vo_command_buffers[render_pass->renderer->swapchain->current_image_index], &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBeginRenderPass(render_pass->renderer->vo_command_buffers[render_pass->renderer->current_frame_index], &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); render_pass->current_subpass_index = 0; } RENDERER_API void vulkan_render_pass_end(vulkan_render_pass_t* render_pass) { - vkCmdEndRenderPass(render_pass->renderer->vo_command_buffers[render_pass->renderer->swapchain->current_image_index]); + vkCmdEndRenderPass(render_pass->renderer->vo_command_buffers[render_pass->renderer->current_frame_index]); } RENDERER_API void vulkan_render_pass_next(vulkan_render_pass_t* render_pass) @@ -258,6 +258,6 @@ RENDERER_API void vulkan_render_pass_next(vulkan_render_pass_t* render_pass) log_wrn("There are only %u subpasses but you're trying to exceed it\n", render_pass->subpass_count); return; } - vkCmdNextSubpass(render_pass->renderer->vo_command_buffers[render_pass->renderer->swapchain->current_image_index], VK_SUBPASS_CONTENTS_INLINE); + vkCmdNextSubpass(render_pass->renderer->vo_command_buffers[render_pass->renderer->current_frame_index], VK_SUBPASS_CONTENTS_INLINE); ++(render_pass->current_subpass_index); } diff --git a/source/renderer/vulkan/vulkan_render_queue.c b/source/renderer/vulkan/vulkan_render_queue.c index 23fb60b7..1ddda71e 100644 --- a/source/renderer/vulkan/vulkan_render_queue.c +++ b/source/renderer/vulkan/vulkan_render_queue.c @@ -393,7 +393,7 @@ RENDERER_API void vulkan_render_queue_dispatch(vulkan_render_queue_t* queue, vul vulkan_render_pass_t* pass = vulkan_render_pass_pool_getH(pass_pool, pass_handle); // begin the render pass - vulkan_render_pass_begin(pass, queue->renderer->swapchain->current_image_index, camera); + vulkan_render_pass_begin(pass, VULKAN_RENDER_PASS_FRAMEBUFFER_INDEX_SWAPCHAIN, camera); // get the number of sub passes that this render pass has u32 sub_pass_count = pass->subpass_count; diff --git a/source/renderer/vulkan/vulkan_renderer.c b/source/renderer/vulkan/vulkan_renderer.c index 56709281..fe51beb9 100644 --- a/source/renderer/vulkan/vulkan_renderer.c +++ b/source/renderer/vulkan/vulkan_renderer.c @@ -166,20 +166,46 @@ static vulkan_descriptor_set_layout_t create_global_set_layout(vulkan_renderer_t static vulkan_descriptor_set_layout_t create_object_set_layout(vulkan_renderer_t* renderer); static vulkan_descriptor_set_layout_t create_camera_set_layout(vulkan_renderer_t* renderer); static void setup_global_set(vulkan_renderer_t* renderer); -static VkSemaphore get_semaphore(vulkan_renderer_t* renderer) +static VkSemaphore create_semaphore(vulkan_renderer_t* renderer) { VkSemaphore semaphore; VkSemaphoreCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; vkCall(vkCreateSemaphore(renderer->logical_device->vo_handle, &createInfo, VULKAN_ALLOCATION_CALLBACKS(renderer), &semaphore)); return semaphore; } -static VkFence get_unsigned_fence(vulkan_renderer_t* renderer) +static VkSemaphore* create_semaphores(vulkan_renderer_t* renderer, u32 count) +{ + VkSemaphore* semaphores = memory_allocator_alloc_obj_array(renderer->allocator, MEMORY_ALLOCATION_TYPE_OBJ_VKAPI_SEMAPHORE_ARRAY, VkSemaphore, count); + for(u32 i = 0; i < count; i++) + semaphores[i] = create_semaphore(renderer); + return semaphores; +} +static INLINE_IF_RELEASE_MODE void destroy_semaphores(vulkan_renderer_t* renderer, VkSemaphore* semaphores, u32 count) +{ + for(u32 i = 0; i < count; i++) + vkDestroySemaphore(renderer->logical_device->vo_handle, semaphores[i], VULKAN_ALLOCATION_CALLBACKS(renderer)); + memory_allocator_dealloc(renderer->allocator, semaphores); +} +static VkFence create_signaled_fence(vulkan_renderer_t* renderer) { VkFence fence; - VkFenceCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; + VkFenceCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .flags = VK_FENCE_CREATE_SIGNALED_BIT }; vkCall(vkCreateFence(renderer->logical_device->vo_handle, &createInfo, VULKAN_ALLOCATION_CALLBACKS(renderer), &fence)); return fence; } +static INLINE_IF_RELEASE_MODE VkFence* create_signaled_fences(vulkan_renderer_t* renderer, u32 count) +{ + VkFence* fences = memory_allocator_alloc_obj_array(renderer->allocator, MEMORY_ALLOCATION_TYPE_OBJ_VKAPI_FENCE_ARRAY, VkFence, count); + for(u32 i = 0; i < count; i++) + fences[i] = create_signaled_fence(renderer); + return fences; +} +static void destroy_fences(vulkan_renderer_t* renderer, VkFence* fences, u32 count) +{ + for(u32 i = 0; i < count; i++) + vkDestroyFence(renderer->logical_device->vo_handle, fences[i], VULKAN_ALLOCATION_CALLBACKS(renderer)); + memory_allocator_dealloc(renderer->allocator, fences); +} #ifdef PLATFORM_LINUX # define PLATFORM_SPECIFIC_VK_SURFACE_EXTENSION "VK_KHR_xcb_surface" @@ -312,6 +338,8 @@ DEBUG_BLOCK // NOTE: if VkSurfaceCapabilitiesKHR::maxImageCount equals 0, then there is no maximum limit for image count u32 image_count = clamp_u32(3, surface_capabilities.minImageCount, (surface_capabilities.maxImageCount == 0) ? U32_MAX : surface_capabilities.maxImageCount); + debug_log_info("Image count: %" PRIu32, image_count); + // create logical device VkPhysicalDeviceFeatures* minimum_required_features = memory_allocator_alloc_obj(renderer->allocator, MEMORY_ALLOCATION_TYPE_OBJ_VKAPI_PHYSICAL_DEVICE_FEATURES, VkPhysicalDeviceFeatures); memzero(minimum_required_features, VkPhysicalDeviceFeatures); @@ -356,9 +384,10 @@ DEBUG_BLOCK ) // create semaphores - renderer->vo_image_available_semaphore = get_semaphore(renderer); - renderer->vo_render_finished_semaphore = get_semaphore(renderer); - renderer->vo_fence = get_unsigned_fence(renderer); + renderer->render_present_sync_primitives.primitive_count = image_count; + renderer->render_present_sync_primitives.vo_image_available_semaphores = create_semaphores(renderer, renderer->render_present_sync_primitives.primitive_count); + renderer->render_present_sync_primitives.vo_render_finished_semaphores = create_semaphores(renderer, renderer->render_present_sync_primitives.primitive_count); + renderer->render_present_sync_primitives.vo_fences = create_signaled_fences(renderer, renderer->render_present_sync_primitives.primitive_count); //Set up graphics queue vkGetDeviceQueue(renderer->logical_device->vo_handle, queue_family_indices[0], 0, &renderer->vo_graphics_queue); @@ -545,13 +574,19 @@ static vulkan_descriptor_set_layout_t create_global_set_layout(vulkan_renderer_t RENDERER_API void vulkan_renderer_begin_frame(vulkan_renderer_t* renderer) { - vulkan_swapchain_acquire_next_image(renderer->swapchain); + u32 current_frame_index = renderer->current_frame_index; + + /* wait for the rendering for the frame with index 'current_frame_index' to finish before we can use its resources like + * command buffers, and swapchain images etc. */ + vkCall(vkWaitForFences(renderer->logical_device->vo_handle, 1, &renderer->render_present_sync_primitives.vo_fences[current_frame_index], VK_TRUE, U64_MAX)); + vkCall(vkResetFences(renderer->logical_device->vo_handle, 1, &renderer->render_present_sync_primitives.vo_fences[current_frame_index])); + + vulkan_swapchain_acquire_next_image(renderer->swapchain, renderer->render_present_sync_primitives.vo_image_available_semaphores[current_frame_index]); - u32 current_index = renderer->swapchain->current_image_index; - VkCommandBuffer cb = renderer->vo_command_buffers[current_index]; + VkCommandBuffer cb = renderer->vo_command_buffers[current_frame_index]; // WARNING: enabling command buffer reset and dragging the window results in a crash, not sure why? - // vulkan_command_buffer_reset(renderer->vo_command_buffers[renderer->swapchain->current_image_index], VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); + // vulkan_command_buffer_reset(renderer->vo_command_buffers[renderer->current_frame_index], VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); vulkan_command_buffer_begin(cb, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); @@ -563,20 +598,20 @@ RENDERER_API void vulkan_renderer_begin_frame(vulkan_renderer_t* renderer) .baseArrayLayer = 0, .layerCount = 1 }; - vulkan_command_image_layout_transition(cb, renderer->swapchain->vo_images[current_index], + vulkan_command_image_layout_transition(cb, renderer->swapchain->vo_images[renderer->swapchain->current_image_index], &subresource, - /* oldLayout: */ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + /* oldLayout: */ VK_IMAGE_LAYOUT_UNDEFINED, /* newLayout: */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, /* srcAccess: */ VK_ACCESS_MEMORY_READ_BIT, /* dstAccess: */ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - /* srcStage: */ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + /* srcStage: */ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, /* dstStage: */ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); } RENDERER_API void vulkan_renderer_end_frame(vulkan_renderer_t* renderer) { - u32 current_index = renderer->swapchain->current_image_index; - VkCommandBuffer cb = renderer->vo_command_buffers[current_index]; + u32 current_frame_index = renderer->current_frame_index; + VkCommandBuffer cb = renderer->vo_command_buffers[current_frame_index]; VkImageSubresourceRange subresource = { @@ -586,37 +621,37 @@ RENDERER_API void vulkan_renderer_end_frame(vulkan_renderer_t* renderer) .baseArrayLayer = 0, .layerCount = 1 }; - vulkan_command_image_layout_transition(cb, renderer->swapchain->vo_images[current_index], + vulkan_command_image_layout_transition(cb, renderer->swapchain->vo_images[renderer->swapchain->current_image_index], &subresource, /* oldLayout: */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, /* newLayout: */ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, /* srcAccess: */ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, /* dstAccess: */ VK_ACCESS_MEMORY_READ_BIT, /* srcStage: */ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - /* dstStage: */ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); + /* dstStage: */ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); - vulkan_command_buffer_end(renderer->vo_command_buffers[current_index]); + vulkan_command_buffer_end(renderer->vo_command_buffers[current_frame_index]); } RENDERER_API void vulkan_renderer_update(vulkan_renderer_t* renderer) { - VkCommandBuffer cb = renderer->vo_command_buffers[renderer->swapchain->current_image_index]; + u32 current_frame_index = renderer->current_frame_index; + VkCommandBuffer cb = renderer->vo_command_buffers[current_frame_index]; vulkan_queue_submit(renderer->vo_graphics_queue, cb, - renderer->vo_image_available_semaphore, + renderer->render_present_sync_primitives.vo_image_available_semaphores[current_frame_index], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - renderer->vo_render_finished_semaphore, - renderer->vo_fence); - vkCall(vkWaitForFences(renderer->logical_device->vo_handle, 1, &renderer->vo_fence, VK_TRUE, U64_MAX)); - vkCall(vkResetFences(renderer->logical_device->vo_handle, 1, &renderer->vo_fence)); + renderer->render_present_sync_primitives.vo_render_finished_semaphores[current_frame_index], + renderer->render_present_sync_primitives.vo_fences[current_frame_index]); // NOTE: if this returns 'false', that means we need to recreate our swapchain and its images, // however, we can ignore the return value here, because the swapchain will be recreated automatically whenever window is resized vulkan_queue_present(renderer->vo_graphics_queue, renderer->swapchain->vo_handle, renderer->swapchain->current_image_index, - renderer->vo_render_finished_semaphore); + renderer->render_present_sync_primitives.vo_render_finished_semaphores[current_frame_index]); render_window_poll_events(renderer->window); + renderer->current_frame_index = (1u + renderer->current_frame_index) % renderer->swapchain->image_count; } RENDERER_API bool vulkan_renderer_is_running(vulkan_renderer_t* renderer) @@ -624,15 +659,18 @@ RENDERER_API bool vulkan_renderer_is_running(vulkan_renderer_t* renderer) return !render_window_should_close(renderer->window); } +RENDERER_API void vulkan_renderer_wait_idle(vulkan_renderer_t* renderer) +{ + vulkan_queue_wait_idle(renderer->vo_graphics_queue); +} + RENDERER_API void vulkan_renderer_terminate(vulkan_renderer_t* renderer) { + vulkan_renderer_wait_idle(renderer); + event_unsubscribe(renderer->window->on_resize_event, renderer->screen_info.update_handle); event_unsubscribe(renderer->window->on_resize_event, renderer->swapchain_recreate_handle); - // memory_allocator_dump(renderer->allocator, "memdump1.dump"); - - vulkan_queue_wait_idle(renderer->vo_graphics_queue); - // destroy camera system vulkan_camera_system_destroy(renderer->camera_system); vulkan_camera_system_release_resources(renderer->camera_system); @@ -683,11 +721,11 @@ RENDERER_API void vulkan_renderer_terminate(vulkan_renderer_t* renderer) vkDestroyCommandPool(renderer->logical_device->vo_handle, renderer->vo_command_pool, VULKAN_ALLOCATION_CALLBACKS(renderer)); // destroy fences - vkDestroyFence(renderer->logical_device->vo_handle, renderer->vo_fence, VULKAN_ALLOCATION_CALLBACKS(renderer)); + destroy_fences(renderer, renderer->render_present_sync_primitives.vo_fences, renderer->render_present_sync_primitives.primitive_count); // destroy semaphores - vkDestroySemaphore(renderer->logical_device->vo_handle, renderer->vo_image_available_semaphore, VULKAN_ALLOCATION_CALLBACKS(renderer)); - vkDestroySemaphore(renderer->logical_device->vo_handle, renderer->vo_render_finished_semaphore, VULKAN_ALLOCATION_CALLBACKS(renderer)); + destroy_semaphores(renderer, renderer->render_present_sync_primitives.vo_image_available_semaphores, renderer->render_present_sync_primitives.primitive_count); + destroy_semaphores(renderer, renderer->render_present_sync_primitives.vo_render_finished_semaphores, renderer->render_present_sync_primitives.primitive_count); // destroy logical device vulkan_logical_device_destroy(renderer->logical_device); diff --git a/source/renderer/vulkan/vulkan_swapchain.c b/source/renderer/vulkan/vulkan_swapchain.c index 4fdc656f..b7cc8ca3 100644 --- a/source/renderer/vulkan/vulkan_swapchain.c +++ b/source/renderer/vulkan/vulkan_swapchain.c @@ -84,9 +84,9 @@ RENDERER_API void vulkan_swapchain_release_resources(vulkan_swapchain_t* swapcha memory_allocator_dealloc(swapchain->renderer->allocator, swapchain); } -RENDERER_API u32 vulkan_swapchain_acquire_next_image(vulkan_swapchain_t* swapchain) +RENDERER_API u32 vulkan_swapchain_acquire_next_image(vulkan_swapchain_t* swapchain, VkSemaphore signal_semaphore) { - vkCall(vkAcquireNextImageKHR(swapchain->renderer->logical_device->vo_handle, swapchain->vo_handle, UINT64_MAX, swapchain->renderer->vo_image_available_semaphore, VK_NULL_HANDLE, &(swapchain->current_image_index))); + vkCall(vkAcquireNextImageKHR(swapchain->renderer->logical_device->vo_handle, swapchain->vo_handle, UINT64_MAX, signal_semaphore, VK_NULL_HANDLE, &(swapchain->current_image_index))); return swapchain->current_image_index; } diff --git a/source/renderer/vulkan/vulkan_text_mesh.c b/source/renderer/vulkan/vulkan_text_mesh.c index 5090f65b..676a6982 100644 --- a/source/renderer/vulkan/vulkan_text_mesh.c +++ b/source/renderer/vulkan/vulkan_text_mesh.c @@ -163,7 +163,7 @@ RENDERER_API void vulkan_text_mesh_draw(vulkan_text_mesh_t* text_mesh) vulkan_mesh_t* mesh = vulkan_glyph_mesh_pool_get_mesh(text_mesh->pool, glyph); vulkan_mesh_bind_all_vertex_buffers(mesh); u32 binding = 5; - vulkan_command_bind_vertex_buffers(text_mesh->renderer->vo_command_buffers[text_mesh->renderer->swapchain->current_image_index], &binding, &instance_buffer->device_buffer.vo_handle, 1); + vulkan_command_bind_vertex_buffers(text_mesh->renderer->vo_command_buffers[text_mesh->renderer->current_frame_index], &binding, &instance_buffer->device_buffer.vo_handle, 1); vulkan_mesh_draw_indexed_instanced_only(mesh, instance_buffer->device_buffer.count); } } From 7d3cf74413b6a973c83ef6e2912205a09b66b015 Mon Sep 17 00:00:00 2001 From: ravi688 Date: Thu, 23 May 2024 13:18:24 +0530 Subject: [PATCH 2/6] [WIP] [Do not checkout] Implementing correct subpass dependency resolution algo. --- .../vulkan_render_pass_create_info_builder.h | 2 + .../vulkan_render_pass_create_info_builder.c | 14 + source/renderer/vulkan/vulkan_shader.c | 607 +++++++++++++----- 3 files changed, 447 insertions(+), 176 deletions(-) diff --git a/include/renderer/internal/vulkan/vulkan_render_pass_create_info_builder.h b/include/renderer/internal/vulkan/vulkan_render_pass_create_info_builder.h index 7cee5c15..f3c12511 100644 --- a/include/renderer/internal/vulkan/vulkan_render_pass_create_info_builder.h +++ b/include/renderer/internal/vulkan/vulkan_render_pass_create_info_builder.h @@ -77,6 +77,7 @@ RENDERER_API void vulkan_render_pass_create_info_builder_destroy(vulkan_render_p RENDERER_API void vulkan_render_pass_create_info_builder_add(vulkan_render_pass_create_info_builder_t* builder, u32 count); RENDERER_API void vulkan_render_pass_create_info_builder_bind(vulkan_render_pass_create_info_builder_t* builder, u32 index); +RENDERER_API void vulkan_render_pass_create_info_builder_add_next(vulkan_render_pass_create_info_builder_t* builder); RENDERER_API vulkan_render_pass_create_info_t* vulkan_render_pass_create_info_builder_get(vulkan_render_pass_create_info_builder_t* builder); RENDERER_API u32 vulkan_render_pass_create_info_builder_get_count(vulkan_render_pass_create_info_builder_t* builder); @@ -94,6 +95,7 @@ RENDERER_API void vulkan_render_pass_create_info_builder_set_subpasses(vulkan_re RENDERER_API void vulkan_render_pass_create_info_builder_set_subpasses_builder(vulkan_render_pass_create_info_builder_t* builder, vulkan_subpass_create_info_builder_t* sci_builder, bool is_destroy); RENDERER_API void vulkan_render_pass_create_info_builder_add_dependencies(vulkan_render_pass_create_info_builder_t* builder, VkSubpassDependency* dependencies, u32 dependency_count); RENDERER_API void vulkan_render_pass_create_info_builder_set_dependencies(vulkan_render_pass_create_info_builder_t* builder, VkSubpassDependency* dependencies, u32 dependency_count); +RENDERER_API buffer_t* vulkan_render_pass_create_info_builder_get_dependencies_buffer(vulkan_render_pass_create_info_builder_t* builder); diff --git a/source/renderer/vulkan/vulkan_render_pass_create_info_builder.c b/source/renderer/vulkan/vulkan_render_pass_create_info_builder.c index 27b9717d..7f0bc4d1 100644 --- a/source/renderer/vulkan/vulkan_render_pass_create_info_builder.c +++ b/source/renderer/vulkan/vulkan_render_pass_create_info_builder.c @@ -85,6 +85,11 @@ RENDERER_API void vulkan_render_pass_create_info_builder_bind(vulkan_render_pass _debug_assert__(index < buf_get_element_count(&builder->build_info_array)); builder->bind_index = index; } +RENDERER_API void vulkan_render_pass_create_info_builder_add_next(vulkan_render_pass_create_info_builder_t* builder) +{ + vulkan_render_pass_create_info_builder_add(builder, 1); + vulkan_render_pass_create_info_builder_bind(builder, CAST_TO(u32, buf_get_element_count(&builder->build_info_array) - 1u)); +} static vulkan_render_pass_create_info_build_info_t* get_build_info(vulkan_render_pass_create_info_builder_t* builder, u32 index) { @@ -261,6 +266,15 @@ RENDERER_API void vulkan_render_pass_create_info_builder_add_dependencies(vulkan build_info->is_supbass_dependencies_internal = true; } +RENDERER_API buffer_t* vulkan_render_pass_create_info_builder_get_dependencies_buffer(vulkan_render_pass_create_info_builder_t* builder) +{ + AUTO build_info = get_bound_build_info(builder); + if(!build_info->is_supbass_dependencies_internal) + build_info->subpass_dependencies = memory_allocator_buf_new(builder->allocator, VkSubpassDependency); + build_info->is_supbass_dependencies_internal = true; + return &build_info->subpass_dependencies; +} + RENDERER_API void vulkan_render_pass_create_info_builder_set_dependencies(vulkan_render_pass_create_info_builder_t* builder, VkSubpassDependency* dependencies, u32 dependency_count) { AUTO create_info = get_bound_create_info(builder); diff --git a/source/renderer/vulkan/vulkan_shader.c b/source/renderer/vulkan/vulkan_shader.c index 1dd57901..d4cf84db 100644 --- a/source/renderer/vulkan/vulkan_shader.c +++ b/source/renderer/vulkan/vulkan_shader.c @@ -326,27 +326,26 @@ static bool u32_list_contains(const u32* const list, const u32 count, const u32 return false; } -#define is_next_subpass_reads_any_color(pass, prev_pass) is_next_subpass_reads_any((pass), (prev_pass)->color_attachments, (prev_pass)->color_attachment_count) -#define is_next_subpass_reads_depth(pass, prev_pass) is_next_subpass_reads_any((pass), &(prev_pass)->depth_stencil_attachment, ((prev_pass)->depth_stencil_attachment == U32_MAX) ? 0 : 1) -#define is_next_subpass_writes_any_color(pass, prev_pass) is_next_subpass_writes_any((pass), (prev_pass)->color_attachments, (prev_pass)->color_attachment_count) -#define is_next_subpass_writes_depth(pass, prev_pass) is_next_subpass_writes_any((pass), &(prev_pass)->depth_stencil_attachment, ((prev_pass)->depth_stencil_attachment == U32_MAX) ? 0 : 1) - -static bool is_next_subpass_reads_any(const vulkan_subpass_description_t* const pass, const u32* const attachments, u32 count) +static bool u32_list_contains_any(const u32* const list1, u32 count1, const u32* const list2, u32 count2) { - if(attachments == NULL) return false; - for(u32 i = 0; i < pass->input_attachment_count; i++) - if(u32_list_contains(attachments, count, pass->input_attachments[i])) + for(u32 i = 0; i < count2; i++) + if(u32_list_contains(list1, count1, list2[i])) return true; return false; } -static bool is_next_subpass_writes_any(const vulkan_subpass_description_t* const pass, const u32* const attachments, u32 count) +static bool VkAttachmentReference_list_contains(const VkAttachmentReference* const list, const u32 count, const u32 value) { - for(u32 i = 0; i < pass->color_attachment_count; i++) - if(u32_list_contains(attachments, count, pass->color_attachments[i])) + for(u32 i = 0; i < count; i++) + if(list[i].attachment == value) return true; - if(pass->depth_stencil_attachment != U32_MAX) - if(u32_list_contains(attachments, count, pass->depth_stencil_attachment)) + return false; +} + +static bool VkAttachmentReference_list_contains_any(const VkAttachmentReference* const list1, u32 count1, const VkAttachmentReference* const list2, u32 count2) +{ + for(u32 i = 0; i < count2; i++) + if(VkAttachmentReference_list_contains(list1, count1, list2[i].attachment)) return true; return false; } @@ -385,6 +384,7 @@ static bool is_renderpass_reads_depth(const vulkan_render_pass_description_t* co static void try_add_dependency(BUFFER* dependencies, const VkSubpassDependency* const in_dependency) { + /* check if a subpass dependency containing the same bits as in 'in_dependency' exists*/ u32 count = buf_get_element_count(dependencies); VkSubpassDependency* best_match = NULL; for(u32 i = 0; i < count; i++) @@ -393,18 +393,23 @@ static void try_add_dependency(BUFFER* dependencies, const VkSubpassDependency* if((dependency->srcSubpass == in_dependency->srcSubpass) && (dependency->dstSubpass == in_dependency->dstSubpass)) { best_match = dependency; + /* if yes */ if(((dependency->srcStageMask & in_dependency->srcStageMask) == in_dependency->srcStageMask) && ((dependency->dstStageMask & in_dependency->dstStageMask) == in_dependency->dstStageMask) && ((dependency->srcAccessMask & in_dependency->srcAccessMask) == in_dependency->srcAccessMask) && ((dependency->dstAccessMask & in_dependency->dstAccessMask) == in_dependency->dstAccessMask)) + /* then no need to add any thing */ return; } } + /* if no subpass dependency exists with the same srcSubpass and dstSubpass as in 'in_dependency' */ if(best_match == NULL) + /* then add this new dependency */ buf_push(dependencies, (VkSubpassDependency*)in_dependency); else { + /* otherwise, merge the dependency with the best matched existing one */ best_match->srcStageMask |= in_dependency->srcStageMask; best_match->dstStageMask |= in_dependency->dstStageMask; best_match->srcAccessMask |= in_dependency->srcAccessMask; @@ -425,159 +430,405 @@ static u32 get_most_recent_subpass_index_writing_to_depth(const vulkan_render_pa return index; } -static VkSubpassDependency* create_and_resolve_subpass_dependencies(vulkan_renderer_t* renderer, const vulkan_render_pass_description_t* pass, const vulkan_render_pass_description_t* next_pass, u32 OUT dependency_count) +typedef struct attachment_read_write_info_t { - BUFFER dependencies = memory_allocator_buf_new(renderer->allocator, VkSubpassDependency); - - for(u32 i = 0; i < pass->subpass_count; i++) + bool is_color_attachment_read; + bool is_color_attachment_write; + bool is_depth_attachment_read; + bool is_depth_attachment_write; +} attachment_read_write_info_t; + +static attachment_read_write_info_t get_attachment_read_write_info_between_subpass(vulkan_subpass_create_info_t* subpass, vulkan_subpass_create_info_t* next_subpass) +{ + attachment_read_write_info_t info = { }; + info.is_color_attachment_read = VkAttachmentReference_list_contains_any(next_subpass->input_attachments, next_subpass->input_attachment_count, subpass->color_attachments, subpass->color_attachment_count); + info.is_color_attachment_write = VkAttachmentReference_list_contains_any(next_subpass->color_attachments, next_subpass->color_attachment_count, subpass->color_attachments, subpass->color_attachment_count); + if(subpass->depth_stencil_attachment != NULL) { - vulkan_subpass_description_t* subpass = &pass->subpass_descriptions[i]; - vulkan_subpass_description_t* next_subpass = (i < (pass->subpass_count - 1)) ? (subpass + 1) : NULL; + info.is_depth_attachment_read = VkAttachmentReference_list_contains(next_subpass->input_attachments, next_subpass->input_attachment_count, subpass->depth_stencil_attachment->attachment); + if(next_subpass->depth_stencil_attachment != NULL) + info.is_depth_attachment_write = next_subpass->depth_stencil_attachment->attachment == subpass->depth_stencil_attachment->attachment; + } + return info; +} - if(subpass->depth_stencil_attachment != U32_MAX) - { - /* let the image load operation (clear) happen first - NOTE: VK_ATTACHMENT_LOAD_OP_CLEAR is a write operation - */ - VkSubpassDependency dependency = - { - .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, - .srcSubpass = VK_SUBPASS_EXTERNAL, - .dstSubpass = i, - .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT, - .dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, - .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT - }; +static bool is_subpass_depends_on_any(buffer_t* dependencies, u32 subpass_index) +{ + u32 dep_count = buf_get_element_count(dependencies); + for(u32 i = 0; i < dep_count; i++) + { + VkSubpassDependency* dep = buf_get_ptr_at_typeof(dependencies, VkSubpassDependency, i); + if(dep->dstSubpass == subpass_index) + return true; + } + return false; +} - try_add_dependency(&dependencies, &dependency); +static bool is_subpass_dominates_on_any(buffer_t* dependencies, u32 subpass_index) +{ + u32 dep_count = buf_get_element_count(dependencies); + for(u32 i = 0; i < dep_count; i++) + { + VkSubpassDependency* dep = buf_get_ptr_at_typeof(dependencies, VkSubpassDependency, i); + if(dep->srcSubpass == subpass_index) + return true; + } + return false; +} - /* let the image layout transition happen first - NOTE: VK_IMAGE_LAYOUT_UNDEFINED to VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL is a write operation) - */ - dependency = (VkSubpassDependency) +static attachment_read_write_info_t get_attachment_read_write_info(vulkan_subpass_create_info_t* subpass, VkAttachmentDescription* attachments, u32 attachment_count) +{ + attachment_read_write_info_t info = { }; + for(u32 i = 0; i < attachment_count; i++) + { + switch(attachments[i].format) + { + case VK_FORMAT_B8G8R8A8_SRGB: { - .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, - .srcSubpass = VK_SUBPASS_EXTERNAL, - .dstSubpass = i, - .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, - .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - .dstAccessMask = 0 - }; - - try_add_dependency(&dependencies, &dependency); + if(!info.is_color_attachment_read && VkAttachmentReference_list_contains(subpass->input_attachments, subpass->input_attachment_count, i)) + info.is_color_attachment_read = true; + if(!info.is_color_attachment_write && VkAttachmentReference_list_contains(subpass->color_attachments, subpass->color_attachment_count, i)) + info.is_color_attachment_write = true; + break; + } + case VK_FORMAT_D32_SFLOAT: + { + if(!info.is_depth_attachment_read && VkAttachmentReference_list_contains(subpass->input_attachments, subpass->input_attachment_count, i)) + info.is_depth_attachment_read = true; + if(!info.is_depth_attachment_write && (subpass->depth_stencil_attachment != NULL) && (subpass->depth_stencil_attachment->attachment == i)) + info.is_depth_attachment_write = true; + break; + } + default: + { + DEBUG_LOG_FETAL_ERROR("VkFormat: %u is not expected here!", attachments[i].format); + break; + } } + } + return info; +} - if(subpass->color_attachment_count > 0) - { - /* let the image layout transition happen first - NOTE: VK_IMAGE_LAYOUT_UNDEFINED to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL is a write operation - */ - VkSubpassDependency dependency = - { - .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, - .srcSubpass = VK_SUBPASS_EXTERNAL, - .dstSubpass = i, - .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT, - .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT - }; +static bool get_is_implicit_color_read(vulkan_subpass_create_info_t* subpass, VkAttachmentDescription* attachments, u32 attachment_count) +{ + for(u32 i = 0; i < subpass->color_attachment_count; i++) + { + if(attachments[subpass->color_attachments[i].attachment].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD) + return true; + } + return false; +} - try_add_dependency(&dependencies, &dependency); - } +static bool get_is_implicit_depth_read(vulkan_subpass_create_info_t* subpass, VkAttachmentDescription* attachments, u32 attachment_count) +{ + if(subpass->depth_stencil_attachment == NULL) + return false; + return attachments[subpass->depth_stencil_attachment->attachment].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD; +} + +static bool get_is_implicit_color_write(vulkan_subpass_create_info_t* subpass, VkAttachmentDescription* attachments, u32 attachment_count) +{ + for(u32 i = 0; i < subpass->color_attachment_count; i++) + { + AUTO ref = subpass->color_attachments[i]; + AUTO attachment = attachments[ref.attachment]; + if(attachment.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) + return true; + if(ref.layout != attachment.initialLayout) + return true; + } + return false; +} + +static bool get_is_implicit_depth_write(vulkan_subpass_create_info_t* subpass, VkAttachmentDescription* attachments, u32 attachment_count) +{ + AUTO ref = subpass->depth_stencil_attachment; + if(ref == NULL) + return false; + if(attachments[ref->attachment].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) + return true; + if(ref->layout != attachments[ref->attachment].initialLayout) + return true; + return false; +} - if(next_subpass != NULL) +static bool get_is_implicit_store_color_write(vulkan_subpass_create_info_t* subpass, VkAttachmentDescription* attachments, u32 attachment_count) +{ + for(u32 i = 0; i < subpass->color_attachment_count; i++) + { + AUTO ref = subpass->color_attachments[i]; + AUTO attachment = attachments[ref.attachment]; + if((attachment.storeOp == VK_ATTACHMENT_STORE_OP_STORE) || (attachment.storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE)) + return true; + if(ref.layout != attachment.finalLayout) + return true; + } + return false; +} + +static bool get_is_implicit_store_depth_write(vulkan_subpass_create_info_t* subpass, VkAttachmentDescription* attachments, u32 attachment_count) +{ + AUTO ref = subpass->depth_stencil_attachment; + if(ref == NULL) + return false; + AUTO attachment = attachments[ref->attachment]; + if((attachment.storeOp == VK_ATTACHMENT_STORE_OP_STORE) || (attachment.storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE)) + return true; + if(ref->layout != attachment.finalLayout) + return true; + return false; +} + +static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_render_pass_create_info_t* pass, const vulkan_render_pass_create_info_t* next_passes, u32 next_pass_count) +{ + for(u32 i = 0; i < pass->subpass_count; i++) + { + vulkan_subpass_create_info_t* subpass = &pass->subpasses[i]; + for(u32 j = i + 1; j < pass->subpass_count; j++) { - if(is_next_subpass_writes_any_color(next_subpass, subpass)) + vulkan_subpass_create_info_t* next_subpass = &pass->subpasses[j]; + AUTO info = get_attachment_read_write_info_between_subpass(subpass, next_subpass); + if(info.is_color_attachment_read) { - /* let the write from this subpass to complete then allow write in the next pass */ - VkSubpassDependency dependency = + /* color attachment write-after-read or read-after-write dependency */ + VkSubpassDependency dependency = { - .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, .srcSubpass = i, - .dstSubpass = i + 1, .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT + .dstSubpass = j, + .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT }; - - try_add_dependency(&dependencies, &dependency); + try_add_dependency(dependencies, &dependency); } - - if(is_next_subpass_reads_any_color(next_subpass, subpass)) + else if(info.is_color_attachment_write) { - /* let color write complete and then allow read in the next pass */ + /* color attachment write-after-write dependency */ VkSubpassDependency dependency = { - .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, .srcSubpass = i, - .dstSubpass = i + 1, .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstSubpass = j, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + if(info.is_depth_attachment_read) + { + /* depth attachment write-after-read or read-after-write dependency */ + VkSubpassDependency dependency = + { + .srcSubpass = i, + .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstSubpass = j, .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .dstAccessMask = VK_ACCESS_SHADER_READ_BIT + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT }; - - try_add_dependency(&dependencies, &dependency); + try_add_dependency(dependencies, &dependency); } - - /* if the next subpass writes to the same depth stencil attachment this subpass writes to, - add another subpass dependency to let this subpass write first and then the next subpass - */ - if(is_next_subpass_writes_depth(next_subpass, subpass)) + else if(info.is_depth_attachment_write) { + /* depth attachment write-after-write dependency */ VkSubpassDependency dependency = { - .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, .srcSubpass = i, - .dstSubpass = i + 1, - .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - .dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, - .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT + .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstSubpass = j, + .dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT }; - - try_add_dependency(&dependencies, &dependency); + try_add_dependency(dependencies, &dependency); } } } - if((next_pass != NULL) && is_renderpass_reads_depth(next_pass, pass)) + for(u32 i = 0; i < pass->subpass_count; i++) { - /* let the write complete and then allow read in the next pass */ - VkSubpassDependency dependency = + if(!is_subpass_depends_on_any(dependencies, i)) { - .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, - .srcSubpass = get_most_recent_subpass_index_writing_to_depth(pass), - .dstSubpass = VK_SUBPASS_EXTERNAL, - .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, - .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .dstAccessMask = VK_ACCESS_SHADER_READ_BIT - }; + AUTO subpass = &pass->subpasses[i]; + bool is_color_read = get_is_implicit_color_read(subpass, pass->framebuffer_layout_description.attachments, pass->framebuffer_layout_description.attachment_count); + bool is_color_write = get_is_implicit_color_write(subpass, pass->framebuffer_layout_description.attachments, pass->framebuffer_layout_description.attachment_count); + bool is_depth_read = get_is_implicit_depth_read(subpass, pass->framebuffer_layout_description.attachments, pass->framebuffer_layout_description.attachment_count); + bool is_depth_write = get_is_implicit_depth_write(subpass, pass->framebuffer_layout_description.attachments, pass->framebuffer_layout_description.attachment_count); + AUTO info = get_attachment_read_write_info(subpass, pass->framebuffer_layout_description.attachments, pass->framebuffer_layout_description.attachment_count); + + if(is_color_read && info.is_color_attachment_write) + { + VkSubpassDependency dependency = + { + .srcSubpass = VK_SUBPASS_EXTERNAL, + .srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT, + .dstSubpass = i, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + else if(is_color_write) + { + if(info.is_color_attachment_write) + { + VkSubpassDependency dependency = + { + .srcSubpass = VK_SUBPASS_EXTERNAL, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, + .dstSubpass = i, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + else if(info.is_color_attachment_read) + { + VkSubpassDependency dependency = + { + .srcSubpass = VK_SUBPASS_EXTERNAL, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, + .dstSubpass = i, + .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + } + if(is_depth_read && info.is_depth_attachment_write) + { + VkSubpassDependency dependency = + { + .srcSubpass = VK_SUBPASS_EXTERNAL, + .srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, + .dstSubpass = i, + .dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + else if(is_depth_write) + { + if(info.is_depth_attachment_write) + { + VkSubpassDependency dependency = + { + .srcSubpass = VK_SUBPASS_EXTERNAL, + .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstSubpass = i, + .dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + else if(info.is_depth_attachment_read) + { + VkSubpassDependency dependency = + { + .srcSubpass = VK_SUBPASS_EXTERNAL, + .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstSubpass = i, + .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + } + } - try_add_dependency(&dependencies, &dependency); + if(!is_subpass_dominates_on_any(dependencies, i)) + { + AUTO subpass = &pass->subpasses[i]; + bool is_color_write = get_is_implicit_store_color_write(subpass, pass->framebuffer_layout_description.attachments, pass->framebuffer_layout_description.attachment_count); + bool is_depth_write = get_is_implicit_store_depth_write(subpass, pass->framebuffer_layout_description.attachments, pass->framebuffer_layout_description.attachment_count); + AUTO info = get_attachment_read_write_info(subpass, pass->framebuffer_layout_description.attachments, pass->framebuffer_layout_description.attachment_count); + if(is_color_write) + { + if(info.is_color_attachment_write) + { + VkSubpassDependency dependency = + { + .srcSubpass = i, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + else if(info.is_color_attachment_read) + { + VkSubpassDependency dependency = + { + .srcSubpass = i, + .srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + } + if(is_depth_write) + { + if(info.is_depth_attachment_write) + { + VkSubpassDependency dependency = + { + .srcSubpass = i, + .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + else if(info.is_depth_attachment_read) + { + VkSubpassDependency dependency = + { + .srcSubpass = i, + .srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + } + } } - - OUT dependency_count = CAST_TO(u32, buf_get_element_count(&dependencies)); - return CAST_TO(VkSubpassDependency*, buf_get_ptr(&dependencies)); - } -typedef struct vulkan_render_pass_description_substitutions_t +static void convert_render_pass_description_to_create_info(vulkan_renderer_t* renderer, vulkan_render_pass_create_info_builder_t* builder, vulkan_render_pass_description_t* pass, vulkan_render_pass_description_t* next_passes, u32 next_pass_count) { - u32 subpass_dependency_count; - VkSubpassDependency* subpass_dependencies; -} vulkan_render_pass_description_substitutions_t; - -static vulkan_render_pass_create_info_builder_t* convert_render_pass_description_to_create_info(vulkan_renderer_t* renderer, vulkan_render_pass_description_t* pass, vulkan_render_pass_description_substitutions_t* subst, vulkan_render_pass_description_t* next_passes, u32 next_pass_count) -{ - vulkan_render_pass_create_info_builder_t* builder = vulkan_render_pass_create_info_builder_create(renderer->allocator); - vulkan_render_pass_create_info_builder_add(builder, 1); - vulkan_render_pass_create_info_builder_bind(builder, 0); + vulkan_render_pass_create_info_builder_add_next(builder); // number of frame buffers to create u32 framebuffer_count = get_framebuffer_count_from_render_pass_type(pass->type, renderer->swapchain->image_count); @@ -809,22 +1060,61 @@ static vulkan_render_pass_create_info_builder_t* convert_render_pass_description // for now we won't be using preserve attachments } - /* apply substitutions if any */ - VkSubpassDependency* subpass_dependencies = pass->subpass_dependencies; - u32 subpass_dependency_count = pass->subpass_dependency_count; - if(subst->subpass_dependency_count > 0) + if(pass->subpass_dependency_count > 0) + vulkan_render_pass_create_info_builder_add_dependencies(builder, pass->subpass_dependencies, pass->subpass_dependency_count); +} + +/* merges the subpass depedencies which targets the same subpass pair, + and removes duplicate subpass dependencies. + */ +static VkSubpassDependency* merge_subpass_dependencies(memory_allocator_t* allocator, VkSubpassDependency* dependencies, u32 dependency_count, u32 OUT merged_dep_count) +{ + buffer_t new_dependencies = memory_allocator_buf_new(allocator, VkSubpassDependency); + + for(u32 i = 0; i < dependency_count; i++) + try_add_dependency(&new_dependencies, &dependencies[i]); + + OUT merged_dep_count = buf_get_element_count(&new_dependencies); + + return ((*merged_dep_count) == 0) ? NULL : buf_get_ptr(&new_dependencies); +} + +static vulkan_render_pass_create_info_builder_t* convert_render_pass_descriptions_to_create_infos(vulkan_renderer_t* renderer, vulkan_render_pass_description_t* descriptions, u32 description_count) +{ + vulkan_render_pass_create_info_builder_t* builder = vulkan_render_pass_create_info_builder_create(renderer->allocator); + vulkan_render_pass_create_info_builder_add(builder, description_count); + + for(u32 i = 0; i < description_count; i++) { - subpass_dependency_count = subst->subpass_dependency_count; - subpass_dependencies = subst->subpass_dependencies; + /* number of subsequent render passes after this render pass */ + u32 next_count = description_count - i - 1; + convert_render_pass_description_to_create_info(renderer, builder, &descriptions[i], (next_count > 0) ? &descriptions[i + 1] : NULL, next_count); } - if(subpass_dependency_count > 0) - vulkan_render_pass_create_info_builder_set_dependencies(builder, subpass_dependencies, subpass_dependency_count); - + vulkan_render_pass_create_info_t* create_infos = vulkan_render_pass_create_info_builder_get(builder); + for(u32 i = 0; i < description_count; i++) + { + vulkan_render_pass_create_info_builder_bind(builder, i); + buffer_t* dependencies = vulkan_render_pass_create_info_builder_get_dependencies_buffer(builder); + vulkan_render_pass_create_info_t* pass = &create_infos[i]; + /* number of subsequent render passes after this render pass */ + u32 next_count = description_count - i - 1; + /* if there is no explicit subpass dependency provided by the description then create and resolve internally */ + if(pass->subpass_dependency_count == 0) + create_subpass_dependencies(dependencies, pass, (next_count > 0) ? &create_infos[i + 1] : NULL, next_count); + /* otherwise merge the subpass dependencies as much as possible */ + else + { + u32 merged_dep_count; + VkSubpassDependency* merged_deps = merge_subpass_dependencies(renderer->allocator, pass->subpass_dependencies, pass->subpass_dependency_count, &merged_dep_count); + buf_pushv(dependencies, merged_deps, merged_dep_count); + memory_allocator_dealloc(renderer->allocator, merged_deps); + } + } return builder; } -static vulkan_shader_render_pass_t* create_shader_render_passes(vulkan_renderer_t* renderer, vulkan_render_pass_description_t* descriptions, vulkan_render_pass_description_substitutions_t* substs, u32 description_count, vulkan_pipeline_common_data_t* common_data) +static vulkan_shader_render_pass_t* create_shader_render_passes(vulkan_renderer_t* renderer, vulkan_render_pass_description_t* descriptions, u32 description_count, vulkan_pipeline_common_data_t* common_data) { // allocate memory vulkan_shader_render_pass_t* passes = memory_allocator_alloc_obj_array(renderer->allocator, MEMORY_ALLOCATION_TYPE_OBJ_VK_SHADER_RENDER_PASS_ARRAY, vulkan_shader_render_pass_t, description_count); @@ -838,14 +1128,13 @@ static vulkan_shader_render_pass_t* create_shader_render_passes(vulkan_renderer_ buf_push(&set_layouts, &renderer->global_set_layout.vo_handle); vulkan_render_pass_pool_create_path(renderer->render_pass_pool); + + vulkan_render_pass_create_info_builder_t* create_info_builder = convert_render_pass_descriptions_to_create_infos(renderer, descriptions, description_count); + vulkan_render_pass_create_info_t* create_infos = vulkan_render_pass_create_info_builder_get(create_info_builder); for(u32 i = 0; i < description_count; i++) { // create a render pass object in the pool, no duplicate render pass would be created - - /* number of subsequent render passes after this render pass */ - u32 next_count = description_count - i - 1; - vulkan_render_pass_create_info_builder_t* create_info_builder = convert_render_pass_description_to_create_info(renderer, &descriptions[i], &substs[i], (next_count > 0) ? &descriptions[i + 1] : NULL, next_count); /* prepare render pass and submit input objects */ u32 subpass_count = passes[i].subpass_count = descriptions[i].subpass_count; @@ -867,7 +1156,7 @@ static vulkan_shader_render_pass_t* create_shader_render_passes(vulkan_renderer_ } /* create render pass for this shader */ - passes[i].handle = vulkan_render_pass_pool_create_pass(renderer->render_pass_pool, vulkan_render_pass_create_info_builder_get(create_info_builder), &input); + passes[i].handle = vulkan_render_pass_pool_create_pass(renderer->render_pass_pool, &create_infos[i], &input); /* destroy allocations made in vulkan_render_pass_input_info_t */ if(input.input_attachment_count > 0) @@ -880,8 +1169,6 @@ static vulkan_shader_render_pass_t* create_shader_render_passes(vulkan_renderer_ memory_allocator_dealloc(renderer->allocator, input.subpass_inputs); } - vulkan_render_pass_create_info_builder_destroy(create_info_builder); - /* create pipeline layout and graphics pipelines */ passes[i].subpasses = memory_allocator_alloc_obj_array(renderer->allocator, MEMORY_ALLOCATION_TYPE_OBJ_VK_SHADER_SUBPASS_ARRAY, vulkan_shader_subpass_t, subpass_count); @@ -936,6 +1223,8 @@ static vulkan_shader_render_pass_t* create_shader_render_passes(vulkan_renderer_ buf_pop(&set_layouts, NULL); } + vulkan_render_pass_create_info_builder_destroy(create_info_builder); + // pop out the GLOBAL_SET layout buf_pop(&set_layouts, NULL); @@ -967,22 +1256,6 @@ static void destroy_shader_render_passes(memory_allocator_t* allocator, vulkan_s memory_allocator_dealloc(allocator, passes); } -/* merges the subpass depedencies which targets the same subpass pair, - and removes duplicate subpass dependencies. - */ -static VkSubpassDependency* merge_subpass_dependencies(vulkan_renderer_t* renderer, VkSubpassDependency* dependencies, u32 OUT dependency_count) -{ - BUFFER new_dependencies = memory_allocator_buf_new(renderer->allocator, VkSubpassDependency); - - u32 count = *dependency_count; - for(u32 i = 0; i < count; i++) - try_add_dependency(&new_dependencies, &dependencies[i]); - - OUT dependency_count = count = buf_get_element_count(&new_dependencies); - - return (count == 0) ? NULL : buf_get_ptr(&new_dependencies); -} - static void recreate_graphics_pipelines(void* publisher_data, void* handler_data) { AUTO window = CAST_TO(render_window_t*, publisher_data); @@ -1022,26 +1295,8 @@ RENDERER_API vulkan_shader_t* vulkan_shader_create(vulkan_renderer_t* renderer, .material_set_layout = shader->material_set_layout, .pipeline_descriptions = create_info->pipeline_descriptions }; - - vulkan_render_pass_description_substitutions_t* substs = memory_allocator_alloc_obj_array(renderer->allocator, MEMORY_ALLOCATION_TYPE_OBJ_VK_RENDER_PASS_DESCRIPTION_SUBSTITUIONS_ARRAY, vulkan_render_pass_description_substitutions_t, create_info->render_pass_description_count); - memzerov(substs, vulkan_render_pass_description_substitutions_t, create_info->render_pass_description_count); - for(u32 i = 0; i < create_info->render_pass_description_count; i++) - { - vulkan_render_pass_description_t* pass = &create_info->render_pass_descriptions[i]; - vulkan_render_pass_description_t* next_pass = (i < (create_info->render_pass_description_count - 1)) ? (pass + 1) : NULL; - /* if there is no explicit subpass dependency provided by the description then create and resolve internally */ - if(pass->subpass_dependency_count == 0) - substs[i].subpass_dependencies = create_and_resolve_subpass_dependencies(renderer, pass, next_pass, &substs[i].subpass_dependency_count); - /* otherwise merge the subpass dependencies as much as possible */ - else - substs[i].subpass_dependencies = merge_subpass_dependencies(renderer, pass->subpass_dependencies, &substs[i].subpass_dependency_count); - } - shader->render_passes = create_shader_render_passes(renderer, create_info->render_pass_descriptions, substs, create_info->render_pass_description_count, &common_data); + shader->render_passes = create_shader_render_passes(renderer, create_info->render_pass_descriptions, create_info->render_pass_description_count, &common_data); shader->render_pass_count = create_info->render_pass_description_count; - for(u32 i = 0; i < create_info->render_pass_description_count; i++) - if(substs[i].subpass_dependency_count > 0) - memory_allocator_dealloc(renderer->allocator, substs[i].subpass_dependencies); - memory_allocator_dealloc(renderer->allocator, substs); shader->pass_counter = 0; shader->subpass_counter = 0; From 60581443e41bf2332f5a5a53873f5397ae6b5364 Mon Sep 17 00:00:00 2001 From: ravi688 Date: Thu, 23 May 2024 22:37:17 +0530 Subject: [PATCH 3/6] [WIP] [Do not checkout] Implementing correct subpass dependency resolution algo. --- source/renderer/vulkan/vulkan_shader.c | 168 +++++++++++++++++++++++-- 1 file changed, 157 insertions(+), 11 deletions(-) diff --git a/source/renderer/vulkan/vulkan_shader.c b/source/renderer/vulkan/vulkan_shader.c index d4cf84db..880ab6f2 100644 --- a/source/renderer/vulkan/vulkan_shader.c +++ b/source/renderer/vulkan/vulkan_shader.c @@ -579,7 +579,53 @@ static bool get_is_implicit_store_depth_write(vulkan_subpass_create_info_t* subp return false; } -static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_render_pass_create_info_t* pass, const vulkan_render_pass_create_info_t* next_passes, u32 next_pass_count) +typedef enum attachment_read_write_flag_t +{ + ATTACHMENT_NOOP = 0, + ATTACHMENT_READ, + ATTACHMENT_WRITE +} attachment_read_write_flag_t; + +static void get_attachment_read_write_flags(attachment_read_write_flag_t OUT flags, const vulkan_render_pass_create_info_t* pass, const vulkan_render_pass_description_t* next_passes, u32 next_pass_count) +{ + _debug_assert__(pass->framebuffer_layout_description.attachment_count > 0); + for(u32 i = 0; i < next_pass_count; i++) + { + AUTO input_attachment_count = next_passes[i].input_attachment_count; + AUTO input_attachments = next_passes[i].input_attachments; + for(u32 j = 0; j < input_attachment_count; j++) + { + _debug_assert__(input_attachments[i] < pass->framebuffer_layout_description.attachment_count); + flags[input_attachments[i]] = ATTACHMENT_READ; + } + } +} + +static attachment_read_write_info_t get_read_write_info_from_flags(vulkan_subpass_create_info_t* subpass, attachment_read_write_flag_t* flags, u32 flag_count) +{ + attachment_read_write_info_t info = { }; + for(u32 i = 0; i < subpass->color_attachment_count; i++) + { + _debug_assert__(subpass->color_attachments[i].attachment < flag_count); + if(flags[subpass->color_attachments[i].attachment] == ATTACHMENT_READ) + info.is_color_attachment_read = true; + else if(flags[subpass->color_attachments[i].attachment] == ATTACHMENT_WRITE) + info.is_color_attachment_write = true; + + if(info.is_color_attachment_write && info.is_color_attachment_read) + break; + } + if(subpass->depth_stencil_attachment != NULL) + { + if(flags[subpass->depth_stencil_attachment->attachment] == ATTACHMENT_READ) + info.is_depth_attachment_read = true; + else if(flags[subpass->depth_stencil_attachment->attachment] == ATTACHMENT_WRITE) + info.is_depth_attachment_write = true; + } + return info; +} + +static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_render_pass_create_info_t* pass, const vulkan_render_pass_description_t* next_passes, u32 next_pass_count) { for(u32 i = 0; i < pass->subpass_count; i++) { @@ -728,10 +774,10 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren VkSubpassDependency dependency = { .srcSubpass = VK_SUBPASS_EXTERNAL, - .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .dstSubpass = i, - .dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT }; @@ -742,7 +788,7 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren VkSubpassDependency dependency = { .srcSubpass = VK_SUBPASS_EXTERNAL, - .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .dstSubpass = i, .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, @@ -798,10 +844,10 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren VkSubpassDependency dependency = { .srcSubpass = i, - .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .dstSubpass = VK_SUBPASS_EXTERNAL, - .dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT }; @@ -815,7 +861,7 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren .srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, .dstSubpass = VK_SUBPASS_EXTERNAL, - .dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT }; @@ -824,6 +870,107 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren } } } + + attachment_read_write_flag_t flags[pass->framebuffer_layout_description.attachment_count] = { }; + + get_attachment_read_write_flags(flags, pass, next_passes, next_pass_count); + + for(u32 i = 0; i < pass->subpass_count; i++) + { + AUTO subpass = &pass->subpasses[i]; + AUTO np_info = get_read_write_info_from_flags(subpass, flags, pass->framebuffer_layout_description.attachment_count); + AUTO info = get_attachment_read_write_info(subpass, pass->framebuffer_layout_description.attachments, pass->framebuffer_layout_description.attachment_count); + if(info.is_color_attachment_read && np_info.is_color_attachment_write) + { + VkSubpassDependency dependency = + { + .srcSubpass = i, + .srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + else if(info.is_color_attachment_write) + { + if(np_info.is_color_attachment_read) + { + VkSubpassDependency dependency = + { + .srcSubpass = i, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + else if(np_info.is_color_attachment_write) + { + VkSubpassDependency dependency = + { + .srcSubpass = i, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + } + if(info.is_depth_attachment_read && np_info.is_depth_attachment_write) + { + VkSubpassDependency dependency = + { + .srcSubpass = i, + .srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + if(info.is_depth_attachment_write) + { + if(np_info.is_depth_attachment_read) + { + VkSubpassDependency dependency = + { + .srcSubpass = i, + .srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + else if(np_info.is_depth_attachment_write) + { + VkSubpassDependency dependency = + { + .srcSubpass = i, + .srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT + }; + try_add_dependency(dependencies, &dependency); + } + } + } } static void convert_render_pass_description_to_create_info(vulkan_renderer_t* renderer, vulkan_render_pass_create_info_builder_t* builder, vulkan_render_pass_description_t* pass, vulkan_render_pass_description_t* next_passes, u32 next_pass_count) @@ -1082,12 +1229,11 @@ static VkSubpassDependency* merge_subpass_dependencies(memory_allocator_t* alloc static vulkan_render_pass_create_info_builder_t* convert_render_pass_descriptions_to_create_infos(vulkan_renderer_t* renderer, vulkan_render_pass_description_t* descriptions, u32 description_count) { vulkan_render_pass_create_info_builder_t* builder = vulkan_render_pass_create_info_builder_create(renderer->allocator); - vulkan_render_pass_create_info_builder_add(builder, description_count); for(u32 i = 0; i < description_count; i++) { /* number of subsequent render passes after this render pass */ - u32 next_count = description_count - i - 1; + u32 next_count = (i < (description_count - 1u)) ? 1 : 0; // description_count - i - 1; // TODO: full support for more than one successor is needed convert_render_pass_description_to_create_info(renderer, builder, &descriptions[i], (next_count > 0) ? &descriptions[i + 1] : NULL, next_count); } @@ -1098,10 +1244,10 @@ static vulkan_render_pass_create_info_builder_t* convert_render_pass_description buffer_t* dependencies = vulkan_render_pass_create_info_builder_get_dependencies_buffer(builder); vulkan_render_pass_create_info_t* pass = &create_infos[i]; /* number of subsequent render passes after this render pass */ - u32 next_count = description_count - i - 1; + u32 next_count = (i < (description_count - 1u)) ? 1 : 0; // description_count - i - 1; // TODO: full support for more than one success is needed /* if there is no explicit subpass dependency provided by the description then create and resolve internally */ if(pass->subpass_dependency_count == 0) - create_subpass_dependencies(dependencies, pass, (next_count > 0) ? &create_infos[i + 1] : NULL, next_count); + create_subpass_dependencies(dependencies, pass, (next_count > 0) ? &descriptions[i + 1] : NULL, next_count); /* otherwise merge the subpass dependencies as much as possible */ else { From 0328ded8254f3b70f82a67580561430e1e146b04 Mon Sep 17 00:00:00 2001 From: ravi688 Date: Fri, 24 May 2024 06:19:17 +0530 Subject: [PATCH 4/6] [Fix] Reimplemented Subpass Dependency Resolution Algorithm - Now every test works as expected, however there are few visual artefacts which might need to be fixed - This change affects any tests which uses shader_load() or which doesn't supply subpass dependency explicits - As with shader_load(), the subpass dependencies are automatically resolved and created. --- source/renderer/vulkan/vulkan_shader.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/renderer/vulkan/vulkan_shader.c b/source/renderer/vulkan/vulkan_shader.c index 880ab6f2..9e8907c8 100644 --- a/source/renderer/vulkan/vulkan_shader.c +++ b/source/renderer/vulkan/vulkan_shader.c @@ -447,7 +447,7 @@ static attachment_read_write_info_t get_attachment_read_write_info_between_subpa { info.is_depth_attachment_read = VkAttachmentReference_list_contains(next_subpass->input_attachments, next_subpass->input_attachment_count, subpass->depth_stencil_attachment->attachment); if(next_subpass->depth_stencil_attachment != NULL) - info.is_depth_attachment_write = next_subpass->depth_stencil_attachment->attachment == subpass->depth_stencil_attachment->attachment; + info.is_depth_attachment_write = (next_subpass->depth_stencil_attachment->attachment == subpass->depth_stencil_attachment->attachment); } return info; } @@ -644,7 +644,7 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, .dstSubpass = j, .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT }; try_add_dependency(dependencies, &dependency); @@ -674,7 +674,7 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .dstSubpass = j, .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT }; try_add_dependency(dependencies, &dependency); @@ -747,7 +747,7 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, .dstSubpass = i, .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, + .dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT }; try_add_dependency(dependencies, &dependency); @@ -792,7 +792,7 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .dstSubpass = i, .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, + .dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT }; try_add_dependency(dependencies, &dependency); @@ -828,7 +828,7 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren { .srcSubpass = i, .srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, + .srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, .dstSubpass = VK_SUBPASS_EXTERNAL, .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, @@ -859,7 +859,7 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren { .srcSubpass = i, .srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, + .srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, .dstSubpass = VK_SUBPASS_EXTERNAL, .dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, @@ -886,7 +886,7 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren { .srcSubpass = i, .srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, + .srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, .dstSubpass = VK_SUBPASS_EXTERNAL, .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, @@ -905,7 +905,7 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, .dstSubpass = VK_SUBPASS_EXTERNAL, .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT }; try_add_dependency(dependencies, &dependency); @@ -931,7 +931,7 @@ static void create_subpass_dependencies(buffer_t* dependencies, const vulkan_ren { .srcSubpass = i, .srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, + .srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, .dstSubpass = VK_SUBPASS_EXTERNAL, .dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, From 46ed558ff3d97cf34bc96aea07cf613617ac65e7 Mon Sep 17 00:00:00 2001 From: ravi688 Date: Fri, 24 May 2024 06:21:01 +0530 Subject: [PATCH 5/6] [Fix] Wait for the command buffer execution to complete before changing the camera render target - Camera render target change might also involve framebuffer recreation, but the command buffers might still be executing and referencing the VkFramebuffer objects - Therefore, added vulkan_renderer_wait_idle() in vulkan_camera_set_render_target() function. - However, it does introduces some latency which need to be optimized via fine grained synchronzation in future. --- source/renderer/vulkan/vulkan_camera.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/renderer/vulkan/vulkan_camera.c b/source/renderer/vulkan/vulkan_camera.c index ce129779..7a292292 100644 --- a/source/renderer/vulkan/vulkan_camera.c +++ b/source/renderer/vulkan/vulkan_camera.c @@ -1370,6 +1370,11 @@ RENDERER_API void vulkan_camera_set_render_target(vulkan_camera_t* camera, vulka else camera->max_shot_count = 1; + /* setting to a different render targets might also destroy existing framebuffer objects + * , as per vulkan spec, VkFramebuffer object can only be destroyed if nothing is use it, + * therefore, make sure all of the command buffers have finished their execution and no one is referencing the VkFramebuffer objects */ + vulkan_renderer_wait_idle(camera->renderer); + switch(target_type) { case VULKAN_CAMERA_RENDER_TARGET_TYPE_COLOR: From 156c26ef8eeea8c45cac481f3886277bc8dc6b75 Mon Sep 17 00:00:00 2001 From: ravi688 Date: Fri, 24 May 2024 06:23:49 +0530 Subject: [PATCH 6/6] [Bug Fix] Do not use vulkan_camera_set_cube if the render target is not cube --- source/tests/TID-28.case2.c | 5 ++++- source/tests/TID-48.case1.c | 5 ++++- source/tests/point_light_shadows.load.c | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/source/tests/TID-28.case2.c b/source/tests/TID-28.case2.c index c27c3b2b..8ed6bcb3 100644 --- a/source/tests/TID-28.case2.c +++ b/source/tests/TID-28.case2.c @@ -197,7 +197,10 @@ TEST_ON_UPDATE(TID_28_CASE_2) angle += deltaTime; float _angle = (0.5f * sin(angle) + 0.5f) * 180.0f - 180.0f; vec3_t pos = vec3(0.8f * sin(_angle DEG), 0, 0.8f * cos(_angle DEG)); - vulkan_camera_set_position_cube(this->offscreenCamera, pos); + if(swap) + vulkan_camera_set_position(this->offscreenCamera, pos); + else + vulkan_camera_set_position_cube(this->offscreenCamera, pos); light_set_position(this->pointLight, pos); light_set_color(this->pointLight, vec3(pos.x * 0.5f + 0.5f, pos.y * 0.5f + 0.5f, pos.z * 0.5f + 0.5f)); render_object_set_transform(this->cubeObject, mat4_mul(2, mat4_translation(pos.x, pos.y, pos.z), diff --git a/source/tests/TID-48.case1.c b/source/tests/TID-48.case1.c index 55905ced..14943945 100644 --- a/source/tests/TID-48.case1.c +++ b/source/tests/TID-48.case1.c @@ -202,7 +202,10 @@ TEST_ON_UPDATE(TID_48_CASE_1) angle += deltaTime; float _angle = (0.5f * sin(angle) + 0.5f) * 180.0f - 180.0f; vec3_t pos = vec3(0.8f * sin(_angle DEG), 0, 0.8f * cos(_angle DEG)); - vulkan_camera_set_position_cube(this->offscreenCamera, pos); + if(swap) + vulkan_camera_set_position(this->offscreenCamera, pos); + else + vulkan_camera_set_position_cube(this->offscreenCamera, pos); light_set_position(this->pointLight, pos); light_set_color(this->pointLight, vec3(pos.x * 0.5f + 0.5f, pos.y * 0.5f + 0.5f, pos.z * 0.5f + 0.5f)); render_object_set_transform(this->cubeObject, mat4_mul(2, mat4_translation(pos.x, pos.y, pos.z), diff --git a/source/tests/point_light_shadows.load.c b/source/tests/point_light_shadows.load.c index 1bed11e3..ddfcdcc5 100644 --- a/source/tests/point_light_shadows.load.c +++ b/source/tests/point_light_shadows.load.c @@ -203,7 +203,10 @@ TEST_ON_UPDATE(POINT_LIGHT_SHADOWS_LOAD) angle += deltaTime; float _angle = (0.5f * sin(angle) + 0.5f) * 180.0f - 180.0f; vec3_t pos = vec3(0.8f * sin(_angle DEG), 0, 0.8f * cos(_angle DEG)); - vulkan_camera_set_position_cube(this->offscreenCamera, pos); + if(swap) + vulkan_camera_set_position(this->offscreenCamera, pos); + else + vulkan_camera_set_position_cube(this->offscreenCamera, pos); light_set_position(this->pointLight, pos); light_set_color(this->pointLight, vec3(pos.x * 0.5f + 0.5f, pos.y * 0.5f + 0.5f, pos.z * 0.5f + 0.5f)); render_object_set_transform(this->cubeObject, mat4_mul(2, mat4_translation(pos.x, pos.y, pos.z),