From 7e37d640dcaa1784b87666468a299cc3f321bd6a Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 18 May 2019 06:54:35 +0200 Subject: [PATCH] - avoid creating a new render pass if a pipeline bind will suffice --- .../vulkan/renderer/vk_renderpass.cpp | 16 +++- src/rendering/vulkan/renderer/vk_renderpass.h | 38 +++++++- .../vulkan/renderer/vk_renderstate.cpp | 93 ++++++++++--------- .../vulkan/renderer/vk_renderstate.h | 2 +- 4 files changed, 99 insertions(+), 50 deletions(-) diff --git a/src/rendering/vulkan/renderer/vk_renderpass.cpp b/src/rendering/vulkan/renderer/vk_renderpass.cpp index 9fc5b9ab61c..bea7ba7d66e 100644 --- a/src/rendering/vulkan/renderer/vk_renderpass.cpp +++ b/src/rendering/vulkan/renderer/vk_renderpass.cpp @@ -203,7 +203,6 @@ std::unique_ptr VkRenderPassManager::AllocateTextureDescrip VkRenderPassSetup::VkRenderPassSetup(const VkRenderPassKey &key) { CreateRenderPass(key); - CreatePipeline(key); } void VkRenderPassSetup::CreateRenderPass(const VkRenderPassKey &key) @@ -258,7 +257,15 @@ void VkRenderPassSetup::CreateRenderPass(const VkRenderPassKey &key) RenderPass->SetDebugName("VkRenderPassSetup.RenderPass"); } -void VkRenderPassSetup::CreatePipeline(const VkRenderPassKey &key) +VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key) +{ + auto &item = Pipelines[key]; + if (!item) + item = CreatePipeline(key); + return item.get(); +} + +std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key) { auto fb = GetVulkanFrameBuffer(); GraphicsPipelineBuilder builder; @@ -348,6 +355,7 @@ void VkRenderPassSetup::CreatePipeline(const VkRenderPassKey &key) builder.setLayout(fb->GetRenderPassManager()->GetPipelineLayout(key.NumTextureLayers)); builder.setRenderPass(RenderPass.get()); - Pipeline = builder.create(fb->device); - Pipeline->SetDebugName("VkRenderPassSetup.Pipeline"); + 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 dab149a19da..141e627f012 100644 --- a/src/rendering/vulkan/renderer/vk_renderpass.h +++ b/src/rendering/vulkan/renderer/vk_renderpass.h @@ -10,7 +10,7 @@ class VKDataBuffer; -class VkRenderPassKey +class VkPipelineKey { public: FRenderStyle RenderStyle; @@ -36,6 +36,36 @@ class VkRenderPassKey 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; } + bool operator!=(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) != 0; } +}; + +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 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; } @@ -46,13 +76,15 @@ class VkRenderPassSetup public: VkRenderPassSetup(const VkRenderPassKey &key); + VulkanPipeline *GetPipeline(const VkPipelineKey &key); + std::unique_ptr RenderPass; - std::unique_ptr Pipeline; + std::map> Pipelines; std::map> Framebuffer; private: - void CreatePipeline(const VkRenderPassKey &key); void CreateRenderPass(const VkRenderPassKey &key); + std::unique_ptr CreatePipeline(const VkPipelineKey &key); }; class VkVertexFormat diff --git a/src/rendering/vulkan/renderer/vk_renderstate.cpp b/src/rendering/vulkan/renderer/vk_renderstate.cpp index e9474f092c6..32c18e512f7 100644 --- a/src/rendering/vulkan/renderer/vk_renderstate.cpp +++ b/src/rendering/vulkan/renderer/vk_renderstate.cpp @@ -196,65 +196,75 @@ void VkRenderState::ApplyDepthBias() void VkRenderState::ApplyRenderPass(int dt) { // Find a render pass that matches our state - VkRenderPassKey passKey; - passKey.ClearTargets = mRenderPassKey.ClearTargets | mClearTargets; - passKey.DrawType = dt; - passKey.VertexFormat = static_cast(mVertexBuffer)->VertexFormat; - passKey.RenderStyle = mRenderStyle; - passKey.DepthTest = mDepthTest; - passKey.DepthWrite = mDepthTest && mDepthWrite; - passKey.DepthFunc = mDepthFunc; - passKey.DepthClamp = mDepthClamp; - passKey.DepthBias = !(mBias.mFactor == 0 && mBias.mUnits == 0); - passKey.StencilTest = mStencilTest; - passKey.StencilPassOp = mStencilOp; - passKey.ColorMask = mColorMask; - passKey.CullMode = mCullMode; - passKey.DrawBufferFormat = mRenderTarget.Format; - passKey.Samples = mRenderTarget.Samples; - passKey.DrawBuffers = mRenderTarget.DrawBuffers; - passKey.NumTextureLayers = mMaterial.mMaterial ? mMaterial.mMaterial->GetLayers() : 0; + VkPipelineKey pipelineKey; + pipelineKey.ClearTargets = mPipelineKey.ClearTargets | mClearTargets; + pipelineKey.DrawType = dt; + pipelineKey.VertexFormat = static_cast(mVertexBuffer)->VertexFormat; + pipelineKey.RenderStyle = mRenderStyle; + pipelineKey.DepthTest = mDepthTest; + pipelineKey.DepthWrite = mDepthTest && mDepthWrite; + pipelineKey.DepthFunc = mDepthFunc; + pipelineKey.DepthClamp = mDepthClamp; + pipelineKey.DepthBias = !(mBias.mFactor == 0 && mBias.mUnits == 0); + pipelineKey.StencilTest = mStencilTest; + 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) { - passKey.SpecialEffect = mSpecialEffect; - passKey.EffectState = 0; - passKey.AlphaTest = false; + pipelineKey.SpecialEffect = mSpecialEffect; + pipelineKey.EffectState = 0; + pipelineKey.AlphaTest = false; } else { int effectState = mMaterial.mOverrideShader >= 0 ? mMaterial.mOverrideShader : (mMaterial.mMaterial ? mMaterial.mMaterial->GetShaderIndex() : 0); - passKey.SpecialEffect = EFF_NONE; - passKey.EffectState = mTextureEnabled ? effectState : SHADER_NoTexture; - passKey.AlphaTest = mAlphaThreshold >= 0.f; + pipelineKey.SpecialEffect = EFF_NONE; + pipelineKey.EffectState = mTextureEnabled ? effectState : SHADER_NoTexture; + pipelineKey.AlphaTest = mAlphaThreshold >= 0.f; } - // Is this the one we already have or do we need to change render pass? - bool changingRenderPass = (passKey != mRenderPassKey); + // Is this the one we already have or do we need to change pipeline? + bool changingPipeline = (pipelineKey != mPipelineKey); + bool inRenderPass = mCommandBuffer; - if (!mCommandBuffer) + if (!inRenderPass) { mCommandBuffer = GetVulkanFrameBuffer()->GetDrawCommands(); - changingRenderPass = true; + changingPipeline = true; mScissorChanged = true; mViewportChanged = true; mStencilRefChanged = true; mBias.mChanged = true; } - else if (changingRenderPass) - { - mCommandBuffer->endRenderPass(); - } - if (changingRenderPass) + if (changingPipeline) { - passKey.ClearTargets = mClearTargets; + pipelineKey.ClearTargets = mClearTargets; // Only clear depth+stencil if the render target actually has that if (!mRenderTarget.DepthStencil) - passKey.ClearTargets &= ~(CT_Depth | CT_Stencil); + 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)); - BeginRenderPass(passKey, mCommandBuffer); - mRenderPassKey = passKey; + mPipelineKey = pipelineKey; mClearTargets = 0; } } @@ -385,7 +395,7 @@ void VkRenderState::ApplyPushConstants() auto fb = GetVulkanFrameBuffer(); auto passManager = fb->GetRenderPassManager(); - mCommandBuffer->pushConstants(passManager->GetPipelineLayout(mRenderPassKey.NumTextureLayers), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &mPushConstants); + mCommandBuffer->pushConstants(passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &mPushConstants); } template @@ -471,7 +481,7 @@ void VkRenderState::ApplyMaterial() { auto fb = GetVulkanFrameBuffer(); auto passManager = fb->GetRenderPassManager(); - mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mRenderPassKey.NumTextureLayers), 1, base->GetDescriptorSet(mMaterial)); + mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 1, base->GetDescriptorSet(mMaterial)); } mMaterial.mChanged = false; @@ -486,7 +496,7 @@ void VkRenderState::ApplyDynamicSet() auto passManager = fb->GetRenderPassManager(); uint32_t offsets[3] = { mViewpointOffset, mMatricesOffset, mStreamDataOffset }; - mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mRenderPassKey.NumTextureLayers), 0, passManager->DynamicSet.get(), 3, offsets); + mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 0, passManager->DynamicSet.get(), 3, offsets); mLastViewpointOffset = mViewpointOffset; mLastMatricesOffset = mMatricesOffset; @@ -515,7 +525,7 @@ void VkRenderState::EndRenderPass() { mCommandBuffer->endRenderPass(); mCommandBuffer = nullptr; - mRenderPassKey = {}; + mPipelineKey = {}; mLastViewpointOffset = 0xffffffff; mLastVertexBuffer = nullptr; @@ -588,7 +598,6 @@ void VkRenderState::BeginRenderPass(const VkRenderPassKey &key, VulkanCommandBuf beginInfo.addClearColor(0.0f, 0.0f, 0.0f, 0.0f); beginInfo.addClearDepthStencil(1.0f, 0); cmdbuffer->beginRenderPass(beginInfo); - cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->Pipeline.get()); mMaterial.mChanged = true; } diff --git a/src/rendering/vulkan/renderer/vk_renderstate.h b/src/rendering/vulkan/renderer/vk_renderstate.h index bf33b18d103..776342ff161 100644 --- a/src/rendering/vulkan/renderer/vk_renderstate.h +++ b/src/rendering/vulkan/renderer/vk_renderstate.h @@ -66,7 +66,7 @@ class VkRenderState : public FRenderState bool mDepthClamp = true; VulkanCommandBuffer *mCommandBuffer = nullptr; - VkRenderPassKey mRenderPassKey = {}; + VkPipelineKey mPipelineKey = {}; int mClearTargets = 0; bool mNeedApply = true;