radv: handle missing implicit subpass dependencies
authorSamuel Pitoiset <samuel.pitoiset@gmail.com>
Thu, 9 Jan 2020 09:55:54 +0000 (10:55 +0100)
committerSamuel Pitoiset <samuel.pitoiset@gmail.com>
Thu, 23 Jan 2020 10:25:41 +0000 (11:25 +0100)
When a subpass doesn't declare an explicit dependency from/to
VK_SUBPASS_EXTERNAL, Vulkan says there is an implicit dependency.

Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3330>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3330>

src/amd/vulkan/radv_pass.c

index 4c3cab6855f0849df0a08445e470168dcf0f40ca..89343d8a0d977ba68ad1b5caaca2fb9d49d1cbd6 100644 (file)
@@ -59,6 +59,90 @@ radv_render_pass_add_subpass_dep(struct radv_render_pass *pass,
        }
 }
 
+static void
+radv_render_pass_add_implicit_deps(struct radv_render_pass *pass,
+                                  bool has_ingoing_dep, bool has_outgoing_dep)
+{
+       /* From the Vulkan 1.0.39 spec:
+       *
+       *    If there is no subpass dependency from VK_SUBPASS_EXTERNAL to the
+       *    first subpass that uses an attachment, then an implicit subpass
+       *    dependency exists from VK_SUBPASS_EXTERNAL to the first subpass it is
+       *    used in. The subpass dependency operates as if defined with the
+       *    following parameters:
+       *
+       *    VkSubpassDependency implicitDependency = {
+       *        .srcSubpass = VK_SUBPASS_EXTERNAL;
+       *        .dstSubpass = firstSubpass; // First subpass attachment is used in
+       *        .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+       *        .dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+       *        .srcAccessMask = 0;
+       *        .dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
+       *                         VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+       *                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+       *                         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
+       *                         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+       *        .dependencyFlags = 0;
+       *    };
+       *
+       *    Similarly, if there is no subpass dependency from the last subpass
+       *    that uses an attachment to VK_SUBPASS_EXTERNAL, then an implicit
+       *    subpass dependency exists from the last subpass it is used in to
+       *    VK_SUBPASS_EXTERNAL. The subpass dependency operates as if defined
+       *    with the following parameters:
+       *
+       *    VkSubpassDependency implicitDependency = {
+       *        .srcSubpass = lastSubpass; // Last subpass attachment is used in
+       *        .dstSubpass = VK_SUBPASS_EXTERNAL;
+       *        .srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+       *        .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+       *        .srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
+       *                         VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+       *                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+       *                         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
+       *                         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+       *        .dstAccessMask = 0;
+       *        .dependencyFlags = 0;
+       *    };
+       */
+
+       if (!has_ingoing_dep) {
+               const VkSubpassDependency2KHR implicit_ingoing_dep = {
+                       .srcSubpass = VK_SUBPASS_EXTERNAL,
+                       .dstSubpass = 0,
+                       .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                       .dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+                       .srcAccessMask = 0,
+                       .dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
+                                        VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+                                        VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+                                        VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
+                                        VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
+                       .dependencyFlags = 0,
+               };
+
+               radv_render_pass_add_subpass_dep(pass, &implicit_ingoing_dep);
+       }
+
+       if (!has_outgoing_dep) {
+               const VkSubpassDependency2KHR implicit_outgoing_dep = {
+                       .srcSubpass = 0,
+                       .dstSubpass = VK_SUBPASS_EXTERNAL,
+                       .srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+                       .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                       .srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
+                                        VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+                                        VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+                                        VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
+                                        VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
+                       .dstAccessMask = 0,
+                       .dependencyFlags = 0,
+               };
+
+               radv_render_pass_add_subpass_dep(pass, &implicit_outgoing_dep);
+       }
+}
+
 static void
 radv_render_pass_compile(struct radv_render_pass *pass)
 {
@@ -314,6 +398,9 @@ VkResult radv_CreateRenderPass(
                }
        }
 
+       bool has_ingoing_dep = false;
+       bool has_outgoing_dep = false;
+
        for (unsigned i = 0; i < pCreateInfo->dependencyCount; ++i) {
                /* Convert to a Dependency2 */
                struct VkSubpassDependency2 dep2 = {
@@ -326,8 +413,19 @@ VkResult radv_CreateRenderPass(
                        .dependencyFlags  = pCreateInfo->pDependencies[i].dependencyFlags,
                };
                radv_render_pass_add_subpass_dep(pass, &dep2);
+
+               /* Determine if the subpass has explicit dependencies from/to
+                * VK_SUBPASS_EXTERNAL.
+                */
+               if (pCreateInfo->pDependencies[i].srcSubpass == VK_SUBPASS_EXTERNAL)
+                       has_ingoing_dep = true;
+               if (pCreateInfo->pDependencies[i].dstSubpass == VK_SUBPASS_EXTERNAL)
+                       has_outgoing_dep = true;
        }
 
+       radv_render_pass_add_implicit_deps(pass,
+                                          has_ingoing_dep, has_outgoing_dep);
+
        radv_render_pass_compile(pass);
 
        *pRenderPass = radv_render_pass_to_handle(pass);
@@ -511,11 +609,25 @@ VkResult radv_CreateRenderPass2(
                }
        }
 
+       bool has_ingoing_dep = false;
+       bool has_outgoing_dep = false;
+
        for (unsigned i = 0; i < pCreateInfo->dependencyCount; ++i) {
                radv_render_pass_add_subpass_dep(pass,
                                                 &pCreateInfo->pDependencies[i]);
+
+               /* Determine if the subpass has explicit dependencies from/to
+                * VK_SUBPASS_EXTERNAL.
+                */
+               if (pCreateInfo->pDependencies[i].srcSubpass == VK_SUBPASS_EXTERNAL)
+                       has_ingoing_dep = true;
+               if (pCreateInfo->pDependencies[i].dstSubpass == VK_SUBPASS_EXTERNAL)
+                       has_outgoing_dep = true;
        }
 
+       radv_render_pass_add_implicit_deps(pass,
+                                          has_ingoing_dep, has_outgoing_dep);
+
        radv_render_pass_compile(pass);
 
        *pRenderPass = radv_render_pass_to_handle(pass);