From f43935b030fa0c4188513dc5a80a0bee5ba856c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 17 Mar 2018 12:26:55 +0100 Subject: [PATCH] Merge framebuffer layout pre-transitions into render pass subpass dependencies. With this, drivers should be able to completely get rid of layout transitions into render passes that use CLEAR, at least. --- ext/native/thin3d/VulkanQueueRunner.cpp | 126 ++++++++++++------------ ext/native/thin3d/VulkanQueueRunner.h | 5 +- ext/native/thin3d/VulkanRenderManager.h | 6 +- 3 files changed, 70 insertions(+), 67 deletions(-) diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 6e1f7380c0..6b990bdf55 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -150,8 +150,8 @@ void VulkanQueueRunner::InitBackbufferRenderPass() { assert(res == VK_SUCCESS); } -VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadAction, VKRRenderPassAction depthLoadAction, VKRRenderPassAction stencilLoadAction) { - RPKey key{ colorLoadAction, depthLoadAction, stencilLoadAction }; +VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadAction, VKRRenderPassAction depthLoadAction, VKRRenderPassAction stencilLoadAction, VkImageLayout prevColorLayout, VkImageLayout prevDepthLayout) { + RPKey key{ colorLoadAction, depthLoadAction, stencilLoadAction, prevColorLayout, prevDepthLayout }; auto pass = renderPasses_.Get(key); if (pass) { return pass; @@ -179,7 +179,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadActio attachments[0].initialLayout = VK_IMAGE_LAYOUT_GENERAL; attachments[0].finalLayout = VK_IMAGE_LAYOUT_GENERAL; // TODO: Look into auto-transitioning to SAMPLED when appropriate. #else - attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachments[0].initialLayout = prevColorLayout; attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // TODO: Look into auto-transitioning to SAMPLED when appropriate. #endif attachments[0].flags = 0; @@ -214,7 +214,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadActio attachments[1].initialLayout = VK_IMAGE_LAYOUT_GENERAL; attachments[1].finalLayout = VK_IMAGE_LAYOUT_GENERAL; #else - attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachments[1].initialLayout = prevDepthLayout; attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; #endif attachments[1].flags = 0; @@ -239,12 +239,65 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadActio subpass.preserveAttachmentCount = 0; subpass.pPreserveAttachments = nullptr; + VkSubpassDependency dep{}; + dep.srcSubpass = VK_SUBPASS_EXTERNAL; + dep.dstSubpass = 0; + dep.dependencyFlags = 0; + + switch (prevColorLayout) { + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + // Already the right color layout. Unclear that we need to do a lot here.. + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + dep.srcAccessMask |= VK_ACCESS_SHADER_READ_BIT; + dep.srcStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + dep.srcAccessMask |= VK_ACCESS_TRANSFER_WRITE_BIT; + dep.srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + dep.srcAccessMask |= VK_ACCESS_TRANSFER_READ_BIT; + dep.srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + default: + _dbg_assert_msg_(G3D, false, "GetRenderPass: Unexpected color layout %d", (int)prevColorLayout); + break; + } + + switch (prevDepthLayout) { + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + // Already the right depth layout. Unclear that we need to do a lot here.. + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + dep.srcAccessMask |= VK_ACCESS_SHADER_READ_BIT; + dep.srcStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + dep.srcAccessMask |= VK_ACCESS_TRANSFER_READ_BIT; + dep.srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + dep.srcAccessMask |= VK_ACCESS_TRANSFER_WRITE_BIT; + dep.srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + default: + _dbg_assert_msg_(G3D, false, "PerformBindRT: Unexpected depth layout %d", (int)prevDepthLayout); + break; + } + dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + dep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + VkRenderPassCreateInfo rp{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; rp.attachmentCount = 2; rp.pAttachments = attachments; rp.subpassCount = 1; rp.pSubpasses = &subpass; - rp.dependencyCount = 0; + + if (dep.srcAccessMask) { + rp.dependencyCount = 1; + rp.pDependencies = &dep; + } VkResult res = vkCreateRenderPass(vulkan_->GetDevice(), &rp, nullptr, &pass); _assert_(res == VK_SUCCESS); @@ -605,67 +658,12 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step framebuf = fb->framebuf; w = fb->width; h = fb->height; - // Now, if the image needs transitioning, let's transition. - // The backbuffer does not, that's handled by VulkanContext. - if (step.render.framebuffer->color.layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { - VkAccessFlags srcAccessMask = 0; - VkPipelineStageFlags srcStage = 0; - switch (fb->color.layout) { - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - default: - _dbg_assert_msg_(G3D, false, "PerformBindRT: Unexpected color layout %d", (int)fb->color.layout); - break; - } - // Due to a known bug in the Mali driver, pass the level count explicitly. - TransitionImageLayout2(cmd, fb->color.image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, - fb->color.layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - srcStage, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - srcAccessMask, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT); - fb->color.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } - if (fb->depth.layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { - VkAccessFlags srcAccessMask = 0; - VkPipelineStageFlags srcStage = 0; + renderPass = GetRenderPass(step.render.color, step.render.depth, step.render.stencil, fb->color.layout, fb->depth.layout); + // We now do any layout pretransitions as part of the render pass. + fb->color.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + fb->depth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - switch (fb->depth.layout) { - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - default: - _dbg_assert_msg_(G3D, false, "PerformBindRT: Unexpected depth layout %d", (int)fb->color.layout); - break; - } - - // Due to a known bug in the Mali driver, pass the level count explicitly (last param). - TransitionImageLayout2(cmd, fb->depth.image, 0, 1, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, - fb->depth.layout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - srcStage, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - srcAccessMask, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT); - fb->depth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } - - renderPass = GetRenderPass(step.render.color, step.render.depth, step.render.stencil); if (step.render.color == VKRRenderPassAction::CLEAR) { Uint8x4ToFloat4(clearVal[0].color.float32, step.render.clearColor); numClearVals = 1; diff --git a/ext/native/thin3d/VulkanQueueRunner.h b/ext/native/thin3d/VulkanQueueRunner.h index f10326ff95..31afe09e4a 100644 --- a/ext/native/thin3d/VulkanQueueRunner.h +++ b/ext/native/thin3d/VulkanQueueRunner.h @@ -161,7 +161,8 @@ public: VkRenderPass GetBackbufferRenderPass() const { return backbufferRenderPass_; } - VkRenderPass GetRenderPass(VKRRenderPassAction colorLoadAction, VKRRenderPassAction depthLoadAction, VKRRenderPassAction stencilLoadAction); + VkRenderPass GetRenderPass(VKRRenderPassAction colorLoadAction, VKRRenderPassAction depthLoadAction, VKRRenderPassAction stencilLoadAction, + VkImageLayout prevColorLayout, VkImageLayout prevDepthLayout); inline int RPIndex(VKRRenderPassAction color, VKRRenderPassAction depth) { return (int)depth * 3 + (int)color; @@ -202,6 +203,8 @@ private: VKRRenderPassAction colorAction; VKRRenderPassAction depthAction; VKRRenderPassAction stencilAction; + VkImageLayout prevColorLayout; + VkImageLayout prevDepthLayout; }; // Renderpasses, all combinations of preserving or clearing or dont-care-ing fb contents. diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index f27de5d85d..a57a21c02c 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -205,14 +205,16 @@ public: VkCommandBuffer GetInitCmd(); VkRenderPass GetRenderPass(VKRRenderPassAction colorLoadAction, VKRRenderPassAction depthLoadAction, VKRRenderPassAction stencilLoadAction) { - return queueRunner_.GetRenderPass(colorLoadAction, depthLoadAction, stencilLoadAction); + return queueRunner_.GetRenderPass(colorLoadAction, depthLoadAction, stencilLoadAction, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); } VkRenderPass GetBackbufferRenderPass() { return queueRunner_.GetBackbufferRenderPass(); } VkRenderPass GetCompatibleRenderPass() { if (curRenderStep_ && curRenderStep_->render.framebuffer != nullptr) { - return queueRunner_.GetRenderPass(VKRRenderPassAction::CLEAR, VKRRenderPassAction::CLEAR, VKRRenderPassAction::CLEAR); + return queueRunner_.GetRenderPass(VKRRenderPassAction::CLEAR, VKRRenderPassAction::CLEAR, VKRRenderPassAction::CLEAR, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); } else { return queueRunner_.GetBackbufferRenderPass(); }