From 680a6f348ba815fa8cd51ac4f45c1e9a6e63c128 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 18 May 2019 08:12:46 +0200 Subject: [PATCH] - use one render pass for the entire scene or until postprocess or command buffer flushing forces it to end --- .../vulkan/renderer/vk_renderpass.cpp | 51 +++++++++------- src/rendering/vulkan/renderer/vk_renderpass.h | 31 ++-------- .../vulkan/renderer/vk_renderstate.cpp | 58 ++++++++----------- .../vulkan/renderer/vk_renderstate.h | 3 +- 4 files changed, 59 insertions(+), 84 deletions(-) diff --git a/src/rendering/vulkan/renderer/vk_renderpass.cpp b/src/rendering/vulkan/renderer/vk_renderpass.cpp index bea7ba7d6..e76b00711 100644 --- a/src/rendering/vulkan/renderer/vk_renderpass.cpp +++ b/src/rendering/vulkan/renderer/vk_renderpass.cpp @@ -200,12 +200,11 @@ std::unique_ptr VkRenderPassManager::AllocateTextureDescrip ///////////////////////////////////////////////////////////////////////////// -VkRenderPassSetup::VkRenderPassSetup(const VkRenderPassKey &key) +VkRenderPassSetup::VkRenderPassSetup(const VkRenderPassKey &key) : PassKey(key) { - CreateRenderPass(key); } -void VkRenderPassSetup::CreateRenderPass(const VkRenderPassKey &key) +std::unique_ptr VkRenderPassSetup::CreateRenderPass(int clearTargets) { auto buffers = GetVulkanFrameBuffer()->GetBuffers(); @@ -214,31 +213,31 @@ void VkRenderPassSetup::CreateRenderPass(const VkRenderPassKey &key) RenderPassBuilder builder; builder.addAttachment( - key.DrawBufferFormat, (VkSampleCountFlagBits)key.Samples, - (key.ClearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + PassKey.DrawBufferFormat, (VkSampleCountFlagBits)PassKey.Samples, + (clearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - for (int i = 1; i < key.DrawBuffers; i++) + for (int i = 1; i < PassKey.DrawBuffers; i++) { builder.addAttachment( drawBufferFormats[i], buffers->GetSceneSamples(), - (key.ClearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + (clearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } - if (key.UsesDepthStencil()) + if (PassKey.DepthStencil) { builder.addDepthStencilAttachment( - buffers->SceneDepthStencilFormat, key.DrawBufferFormat == VK_FORMAT_R8G8B8A8_UNORM ? VK_SAMPLE_COUNT_1_BIT : buffers->GetSceneSamples(), - (key.ClearTargets & CT_Depth) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, - (key.ClearTargets & CT_Stencil) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + buffers->SceneDepthStencilFormat, PassKey.DrawBufferFormat == VK_FORMAT_R8G8B8A8_UNORM ? VK_SAMPLE_COUNT_1_BIT : buffers->GetSceneSamples(), + (clearTargets & CT_Depth) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + (clearTargets & CT_Stencil) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); } builder.addSubpass(); - for (int i = 0; i < key.DrawBuffers; i++) + for (int i = 0; i < PassKey.DrawBuffers; i++) builder.addSubpassColorAttachmentRef(i, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - if (key.UsesDepthStencil()) + if (PassKey.DepthStencil) { - builder.addSubpassDepthStencilAttachmentRef(key.DrawBuffers, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + builder.addSubpassDepthStencilAttachmentRef(PassKey.DrawBuffers, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); builder.addExternalSubpassDependency( VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, @@ -253,8 +252,16 @@ void VkRenderPassSetup::CreateRenderPass(const VkRenderPassKey &key) VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT); } - RenderPass = builder.create(GetVulkanFrameBuffer()->device); - RenderPass->SetDebugName("VkRenderPassSetup.RenderPass"); + auto renderpass = builder.create(GetVulkanFrameBuffer()->device); + renderpass->SetDebugName("VkRenderPassSetup.RenderPass"); + return renderpass; +} + +VulkanRenderPass *VkRenderPassSetup::GetRenderPass(int clearTargets) +{ + if (!RenderPasses[clearTargets]) + RenderPasses[clearTargets] = CreateRenderPass(clearTargets); + return RenderPasses[clearTargets].get(); } VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key) @@ -273,11 +280,11 @@ std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipeli VkShaderProgram *program; if (key.SpecialEffect != EFF_NONE) { - program = fb->GetShaderManager()->GetEffect(key.SpecialEffect, key.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS); + program = fb->GetShaderManager()->GetEffect(key.SpecialEffect, PassKey.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS); } else { - program = fb->GetShaderManager()->Get(key.EffectState, key.AlphaTest, key.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS); + program = fb->GetShaderManager()->Get(key.EffectState, key.AlphaTest, PassKey.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS); } builder.addVertexShader(program->vert.get()); builder.addFragmentShader(program->frag.get()); @@ -305,7 +312,7 @@ std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipeli inputLocations[attr.location] = true; } - // To do: does vulkan absolutely needs a binding for each location or not? What happens if it isn't specified? Better be safe than sorry.. + // Vulkan requires an attribute binding for each location specified in the shader for (int i = 0; i < 6; i++) { if (!inputLocations[i]) @@ -350,11 +357,11 @@ std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipeli builder.setColorWriteMask((VkColorComponentFlags)key.ColorMask); builder.setStencil(VK_STENCIL_OP_KEEP, op2vk[key.StencilPassOp], VK_STENCIL_OP_KEEP, VK_COMPARE_OP_EQUAL, 0xffffffff, 0xffffffff, 0); builder.setBlendMode(key.RenderStyle); - builder.setSubpassColorAttachmentCount(key.DrawBuffers); - builder.setRasterizationSamples((VkSampleCountFlagBits)key.Samples); + builder.setSubpassColorAttachmentCount(PassKey.DrawBuffers); + builder.setRasterizationSamples((VkSampleCountFlagBits)PassKey.Samples); builder.setLayout(fb->GetRenderPassManager()->GetPipelineLayout(key.NumTextureLayers)); - builder.setRenderPass(RenderPass.get()); + builder.setRenderPass(GetRenderPass(0)); auto pipeline = builder.create(fb->device); pipeline->SetDebugName("VkRenderPassSetup.Pipeline"); return pipeline; diff --git a/src/rendering/vulkan/renderer/vk_renderpass.h b/src/rendering/vulkan/renderer/vk_renderpass.h index 141e627f0..fc746ed61 100644 --- a/src/rendering/vulkan/renderer/vk_renderpass.h +++ b/src/rendering/vulkan/renderer/vk_renderpass.h @@ -28,13 +28,7 @@ public: int CullMode; int VertexFormat; int DrawType; - int Samples; - int ClearTargets; - int DrawBuffers; int NumTextureLayers; - VkFormat DrawBufferFormat; - - bool UsesDepthStencil() const { return DepthTest || DepthWrite || StencilTest || (ClearTargets & (CT_Depth | CT_Stencil)); } bool operator<(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) < 0; } bool operator==(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) == 0; } @@ -44,28 +38,11 @@ public: class VkRenderPassKey { public: - VkRenderPassKey() = default; - VkRenderPassKey(const VkPipelineKey &key) - { - DepthWrite = key.DepthWrite; - DepthTest = key.DepthTest; - StencilTest = key.StencilTest; - Samples = key.Samples; - ClearTargets = key.ClearTargets; - DrawBuffers = key.DrawBuffers; - DrawBufferFormat = key.DrawBufferFormat; - } - - int DepthWrite; - int DepthTest; - int StencilTest; + int DepthStencil; int Samples; - int ClearTargets; int DrawBuffers; VkFormat DrawBufferFormat; - bool UsesDepthStencil() const { return DepthTest || DepthWrite || StencilTest || (ClearTargets & (CT_Depth | CT_Stencil)); } - bool operator<(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) < 0; } bool operator==(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) == 0; } bool operator!=(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) != 0; } @@ -76,14 +53,16 @@ class VkRenderPassSetup public: VkRenderPassSetup(const VkRenderPassKey &key); + VulkanRenderPass *GetRenderPass(int clearTargets); VulkanPipeline *GetPipeline(const VkPipelineKey &key); - std::unique_ptr RenderPass; + VkRenderPassKey PassKey; + std::unique_ptr RenderPasses[8]; std::map> Pipelines; std::map> Framebuffer; private: - void CreateRenderPass(const VkRenderPassKey &key); + std::unique_ptr CreateRenderPass(int clearTargets); std::unique_ptr CreatePipeline(const VkPipelineKey &key); }; diff --git a/src/rendering/vulkan/renderer/vk_renderstate.cpp b/src/rendering/vulkan/renderer/vk_renderstate.cpp index 32c18e512..1e02d0dfd 100644 --- a/src/rendering/vulkan/renderer/vk_renderstate.cpp +++ b/src/rendering/vulkan/renderer/vk_renderstate.cpp @@ -195,9 +195,8 @@ void VkRenderState::ApplyDepthBias() void VkRenderState::ApplyRenderPass(int dt) { - // Find a render pass that matches our state + // Find a pipeline that matches our state VkPipelineKey pipelineKey; - pipelineKey.ClearTargets = mPipelineKey.ClearTargets | mClearTargets; pipelineKey.DrawType = dt; pipelineKey.VertexFormat = static_cast(mVertexBuffer)->VertexFormat; pipelineKey.RenderStyle = mRenderStyle; @@ -210,9 +209,6 @@ void VkRenderState::ApplyRenderPass(int dt) pipelineKey.StencilPassOp = mStencilOp; pipelineKey.ColorMask = mColorMask; pipelineKey.CullMode = mCullMode; - pipelineKey.DrawBufferFormat = mRenderTarget.Format; - pipelineKey.Samples = mRenderTarget.Samples; - pipelineKey.DrawBuffers = mRenderTarget.DrawBuffers; pipelineKey.NumTextureLayers = mMaterial.mMaterial ? mMaterial.mMaterial->GetLayers() : 0; if (mSpecialEffect > EFF_NONE) { @@ -228,44 +224,25 @@ void VkRenderState::ApplyRenderPass(int dt) pipelineKey.AlphaTest = mAlphaThreshold >= 0.f; } - // Is this the one we already have or do we need to change pipeline? - bool changingPipeline = (pipelineKey != mPipelineKey); + // Is this the one we already have? bool inRenderPass = mCommandBuffer; + bool changingPipeline = (!inRenderPass) || (pipelineKey != mPipelineKey); if (!inRenderPass) { mCommandBuffer = GetVulkanFrameBuffer()->GetDrawCommands(); - changingPipeline = true; mScissorChanged = true; mViewportChanged = true; mStencilRefChanged = true; mBias.mChanged = true; + + BeginRenderPass(mCommandBuffer); } if (changingPipeline) { - pipelineKey.ClearTargets = mClearTargets; - - // Only clear depth+stencil if the render target actually has that - if (!mRenderTarget.DepthStencil) - pipelineKey.ClearTargets &= ~(CT_Depth | CT_Stencil); - - // Begin new render pass if needed - VkRenderPassKey passKey = pipelineKey; - if (!inRenderPass || passKey != VkRenderPassKey(mPipelineKey)) - { - if (inRenderPass) - mCommandBuffer->endRenderPass(); - - BeginRenderPass(passKey, mCommandBuffer); - } - - // Bind the pipeline - VkRenderPassSetup *passSetup = GetVulkanFrameBuffer()->GetRenderPassManager()->GetRenderPass(passKey); - mCommandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->GetPipeline(pipelineKey)); - + mCommandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mPassSetup->GetPipeline(pipelineKey)); mPipelineKey = pipelineKey; - mClearTargets = 0; } } @@ -563,32 +540,42 @@ void VkRenderState::SetRenderTarget(VulkanImageView *view, VulkanImageView *dept mRenderTarget.Samples = samples; } -void VkRenderState::BeginRenderPass(const VkRenderPassKey &key, VulkanCommandBuffer *cmdbuffer) +void VkRenderState::BeginRenderPass(VulkanCommandBuffer *cmdbuffer) { auto fb = GetVulkanFrameBuffer(); - VkRenderPassSetup *passSetup = fb->GetRenderPassManager()->GetRenderPass(key); + VkRenderPassKey key = {}; + key.DrawBufferFormat = mRenderTarget.Format; + key.Samples = mRenderTarget.Samples; + key.DrawBuffers = mRenderTarget.DrawBuffers; + key.DepthStencil = !!mRenderTarget.DepthStencil; - auto &framebuffer = passSetup->Framebuffer[mRenderTarget.View->view]; + mPassSetup = fb->GetRenderPassManager()->GetRenderPass(key); + + auto &framebuffer = mPassSetup->Framebuffer[mRenderTarget.View->view]; if (!framebuffer) { auto buffers = fb->GetBuffers(); FramebufferBuilder builder; - builder.setRenderPass(passSetup->RenderPass.get()); + builder.setRenderPass(mPassSetup->GetRenderPass(0)); builder.setSize(mRenderTarget.Width, mRenderTarget.Height); builder.addAttachment(mRenderTarget.View); if (key.DrawBuffers > 1) builder.addAttachment(buffers->SceneFog.View.get()); if (key.DrawBuffers > 2) builder.addAttachment(buffers->SceneNormal.View.get()); - if (key.UsesDepthStencil()) + if (key.DepthStencil) builder.addAttachment(mRenderTarget.DepthStencil); framebuffer = builder.create(GetVulkanFrameBuffer()->device); framebuffer->SetDebugName("VkRenderPassSetup.Framebuffer"); } + // Only clear depth+stencil if the render target actually has that + if (!mRenderTarget.DepthStencil) + mClearTargets &= ~(CT_Depth | CT_Stencil); + RenderPassBegin beginInfo; - beginInfo.setRenderPass(passSetup->RenderPass.get()); + beginInfo.setRenderPass(mPassSetup->GetRenderPass(mClearTargets)); beginInfo.setRenderArea(0, 0, mRenderTarget.Width, mRenderTarget.Height); beginInfo.setFramebuffer(framebuffer.get()); beginInfo.addClearColor(screen->mSceneClearColor[0], screen->mSceneClearColor[1], screen->mSceneClearColor[2], screen->mSceneClearColor[3]); @@ -600,6 +587,7 @@ void VkRenderState::BeginRenderPass(const VkRenderPassKey &key, VulkanCommandBuf cmdbuffer->beginRenderPass(beginInfo); mMaterial.mChanged = true; + mClearTargets = 0; } ///////////////////////////////////////////////////////////////////////////// diff --git a/src/rendering/vulkan/renderer/vk_renderstate.h b/src/rendering/vulkan/renderer/vk_renderstate.h index 776342ff1..522410a2e 100644 --- a/src/rendering/vulkan/renderer/vk_renderstate.h +++ b/src/rendering/vulkan/renderer/vk_renderstate.h @@ -62,11 +62,12 @@ protected: void ApplyVertexBuffers(); void ApplyMaterial(); - void BeginRenderPass(const VkRenderPassKey &key, VulkanCommandBuffer *cmdbuffer); + void BeginRenderPass(VulkanCommandBuffer *cmdbuffer); bool mDepthClamp = true; VulkanCommandBuffer *mCommandBuffer = nullptr; VkPipelineKey mPipelineKey = {}; + VkRenderPassSetup *mPassSetup = nullptr; int mClearTargets = 0; bool mNeedApply = true;