From 3a204d5cf370116a427361410a449dde002bc143 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Tue, 31 May 2022 15:53:51 -0500 Subject: [PATCH] vulkan/render_pass: Add a better helper for render pass inheritance Instead of making drivers dive into the render pass and framebuffer themselves, provide a helper that constructs a VkRenderingInfo for a render pass resume that they can use instead. This should reduce code duplication between driver implementations of BeginRendering and BeginCommandBuffer. Reviewed-by: Samuel Pitoiset Part-of: --- src/vulkan/runtime/vk_render_pass.c | 120 ++++++++++++++++++++++++++++ src/vulkan/runtime/vk_render_pass.h | 40 +++++++++- 2 files changed, 158 insertions(+), 2 deletions(-) diff --git a/src/vulkan/runtime/vk_render_pass.c b/src/vulkan/runtime/vk_render_pass.c index 6780baf75de..91f2a055d1e 100644 --- a/src/vulkan/runtime/vk_render_pass.c +++ b/src/vulkan/runtime/vk_render_pass.c @@ -820,6 +820,126 @@ vk_get_command_buffer_inheritance_rendering_info( COMMAND_BUFFER_INHERITANCE_RENDERING_INFO); } +const VkRenderingInfo * +vk_get_command_buffer_inheritance_as_rendering_resume( + VkCommandBufferLevel level, + const VkCommandBufferBeginInfo *pBeginInfo, + void *stack_data) +{ + struct vk_gcbiarr_data *data = stack_data; + + /* From the Vulkan 1.3.204 spec: + * + * "VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT specifies that a + * secondary command buffer is considered to be entirely inside a render + * pass. If this is a primary command buffer, then this bit is ignored." + * + * Since we're only concerned with the continue case here, we can ignore + * any primary command buffers. + */ + if (level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) + return NULL; + + if (!(pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) + return NULL; + + const VkCommandBufferInheritanceInfo *inheritance = + pBeginInfo->pInheritanceInfo; + + VK_FROM_HANDLE(vk_render_pass, pass, inheritance->renderPass); + if (pass == NULL) + return NULL; + + assert(inheritance->subpass < pass->subpass_count); + const struct vk_subpass *subpass = &pass->subpasses[inheritance->subpass]; + + VK_FROM_HANDLE(vk_framebuffer, fb, inheritance->framebuffer); + if (fb == NULL || (fb->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR)) + return NULL; + + data->rendering = (VkRenderingInfo) { + .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, + .flags = VK_RENDERING_RESUMING_BIT, + .renderArea = { + .offset = { 0, 0 }, + .extent = { fb->width, fb->height }, + }, + .layerCount = fb->layers, + .viewMask = pass->is_multiview ? subpass->view_mask : 0, + }; + + VkRenderingAttachmentInfo *attachments = data->attachments; + + for (unsigned i = 0; i < subpass->color_count; i++) { + const struct vk_subpass_attachment *sp_att = + &subpass->color_attachments[i]; + if (sp_att->attachment == VK_ATTACHMENT_UNUSED) { + attachments[i] = (VkRenderingAttachmentInfo) { + .imageView = VK_NULL_HANDLE, + }; + continue; + } + + assert(sp_att->attachment < pass->attachment_count); + attachments[i] = (VkRenderingAttachmentInfo) { + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .imageView = fb->attachments[sp_att->attachment], + .imageLayout = sp_att->layout, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + }; + } + data->rendering.colorAttachmentCount = subpass->color_count; + data->rendering.pColorAttachments = attachments; + attachments += subpass->color_count; + + if (subpass->depth_stencil_attachment) { + const struct vk_subpass_attachment *sp_att = + subpass->depth_stencil_attachment; + assert(sp_att->attachment < pass->attachment_count); + + VK_FROM_HANDLE(vk_image_view, iview, fb->attachments[sp_att->attachment]); + if (iview->image->aspects & VK_IMAGE_ASPECT_DEPTH_BIT) { + *attachments = (VkRenderingAttachmentInfo) { + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .imageView = vk_image_view_to_handle(iview), + .imageLayout = sp_att->layout, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + }; + data->rendering.pDepthAttachment = attachments++; + } + + if (iview->image->aspects & VK_IMAGE_ASPECT_STENCIL_BIT) { + *attachments = (VkRenderingAttachmentInfo) { + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .imageView = vk_image_view_to_handle(iview), + .imageLayout = sp_att->stencil_layout, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + }; + data->rendering.pStencilAttachment = attachments++; + } + } + + if (subpass->fragment_shading_rate_attachment) { + const struct vk_subpass_attachment *sp_att = + subpass->fragment_shading_rate_attachment; + assert(sp_att->attachment < pass->attachment_count); + + data->fsr_att = (VkRenderingFragmentShadingRateAttachmentInfoKHR) { + .sType = VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR, + .imageView = fb->attachments[sp_att->attachment], + .imageLayout = sp_att->layout, + .shadingRateAttachmentTexelSize = + subpass->fragment_shading_rate_attachment_texel_size, + }; + __vk_append_struct(&data->rendering, &data->fsr_att); + } + + return &data->rendering; +} + VKAPI_ATTR void VKAPI_CALL vk_common_DestroyRenderPass(VkDevice _device, VkRenderPass renderPass, diff --git a/src/vulkan/runtime/vk_render_pass.h b/src/vulkan/runtime/vk_render_pass.h index 8eb99455c93..59b40a25bf5 100644 --- a/src/vulkan/runtime/vk_render_pass.h +++ b/src/vulkan/runtime/vk_render_pass.h @@ -305,7 +305,7 @@ VK_DEFINE_NONDISP_HANDLE_CASTS(vk_render_pass, base, VkRenderPass, /** Returns the VkPipelineRenderingCreateInfo for a graphics pipeline * - * For render-pass-free drivers, this can be used in the implementaiton of + * For render-pass-free drivers, this can be used in the implementation of * vkCreateGraphicsPipelines to get the VkPipelineRenderingCreateInfo. If * VkGraphicsPipelineCreateInfo::renderPass is not VK_NULL_HANDLE, it will * return a representation of the specified subpass as a @@ -322,7 +322,7 @@ vk_get_pipeline_rendering_create_info(const VkGraphicsPipelineCreateInfo *info); * Returns the VkCommandBufferInheritanceRenderingInfo for secondary command * buffer execution * - * For render-pass-free drivers, this can be used in the implementaiton of + * For render-pass-free drivers, this can be used in the implementation of * vkCmdExecuteCommands to get the VkCommandBufferInheritanceRenderingInfo. * If VkCommandBufferInheritanceInfo::renderPass is not VK_NULL_HANDLE, it * will return a representation of the specified subpass as a @@ -339,6 +339,42 @@ vk_get_command_buffer_inheritance_rendering_info( VkCommandBufferLevel level, const VkCommandBufferBeginInfo *pBeginInfo); +struct vk_gcbiarr_data { + VkRenderingInfo rendering; + VkRenderingFragmentShadingRateAttachmentInfoKHR fsr_att; + VkRenderingAttachmentInfo attachments[]; +}; + +#define VK_GCBIARR_DATA_SIZE(max_color_rts) (\ + sizeof(struct vk_gcbiarr_data) + \ + sizeof(VkRenderingAttachmentInfo) * ((max_color_rts) + 2) \ +) + +/** + * Constructs a VkRenderingInfo for the inheritance rendering info + * + * For render-pass-free drivers, this can be used in the implementaiton of + * vkCmdExecuteCommands to get a VkRenderingInfo representing the subpass and + * framebuffer provided via the inheritance info for a command buffer created + * with VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT. The mental model + * here is that VkExecuteCommands() implicitly suspends the render pass and + * VkBeginCommandBuffer() resumes it. If a VkRenderingInfo cannot be + * constructed due to a missing framebuffer or similar, NULL will be + * returned. + * + * @param[in] level The nesting level of this command buffer + * @param[in] pBeginInfo The pBeginInfo from vkBeginCommandBuffer + * @param[out] stack_data An opaque blob of data which will be overwritten by + * this function, passed in from the caller to avoid + * heap allocations. It must be at least + * VK_GCBIARR_DATA_SIZE(max_color_rts) bytes. + */ +const VkRenderingInfo * +vk_get_command_buffer_inheritance_as_rendering_resume( + VkCommandBufferLevel level, + const VkCommandBufferBeginInfo *pBeginInfo, + void *stack_data); + #ifdef __cplusplus } #endif