diff --git a/src/common/rendering/vulkan/vk_renderdevice.h b/src/common/rendering/vulkan/vk_renderdevice.h index d49ca9092..699b2e82a 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.h +++ b/src/common/rendering/vulkan/vk_renderdevice.h @@ -21,7 +21,6 @@ class VkHardwareDataBuffer; class VkHardwareTexture; class VkRenderBuffers; class VkPostprocess; -class SWSceneDrawer; class VulkanRenderDevice : public SystemBaseFrameBuffer { @@ -87,6 +86,7 @@ public: void WaitForCommands(bool finish) override; int MaxThreads = 8; // To do: this may need to be limited by how much memory is available for dedicated buffer mapping (i.e. is resizeable bar available or not) + std::mutex ThreadMutex; private: void RenderTextureView(FCanvasTexture* tex, std::function renderFunc) override; diff --git a/src/common/rendering/vulkan/vk_renderstate.cpp b/src/common/rendering/vulkan/vk_renderstate.cpp index efdfb7c4a..89f53416f 100644 --- a/src/common/rendering/vulkan/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/vk_renderstate.cpp @@ -420,8 +420,7 @@ void VkRenderState::ApplyPushConstants() mPushConstants.uLightIndex = mLightIndex >= 0 ? (mLightIndex % MAX_LIGHT_DATA) : -1; mPushConstants.uBoneIndexBase = mBoneIndexBase; - auto passManager = fb->GetRenderPassManager(); - mCommandBuffer->pushConstants(passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &mPushConstants); + mCommandBuffer->pushConstants(GetPipelineLayout(mPipelineKey.NumTextureLayers), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &mPushConstants); } void VkRenderState::ApplyMatrices() @@ -481,15 +480,16 @@ void VkRenderState::ApplyMaterial() { if (mMaterial.mChanged) { - auto passManager = fb->GetRenderPassManager(); auto descriptors = fb->GetDescriptorSetManager(); + VulkanPipelineLayout* layout = GetPipelineLayout(mPipelineKey.NumTextureLayers); - if (mMaterial.mMaterial && mMaterial.mMaterial->Source()->isHardwareCanvas()) static_cast(mMaterial.mMaterial->Source()->GetTexture())->NeedUpdate(); + if (mMaterial.mMaterial && mMaterial.mMaterial->Source()->isHardwareCanvas()) + static_cast(mMaterial.mMaterial->Source()->GetTexture())->NeedUpdate(); VulkanDescriptorSet* descriptorset = mMaterial.mMaterial ? static_cast(mMaterial.mMaterial)->GetDescriptorSet(mMaterial) : descriptors->GetNullTextureDescriptorSet(); - mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.NumTextureLayers), 0, fb->GetDescriptorSetManager()->GetFixedDescriptorSet()); - mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 2, descriptorset); + mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptors->GetFixedDescriptorSet()); + mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 2, descriptorset); mMaterial.mChanged = false; } } @@ -501,12 +501,12 @@ void VkRenderState::ApplyBufferSets() uint32_t lightsOffset = mLightIndex >= 0 ? (uint32_t)(mLightIndex / MAX_LIGHT_DATA) * sizeof(LightBufferUBO) : mLastLightsOffset; if (mViewpointOffset != mLastViewpointOffset || matrixOffset != mLastMatricesOffset || streamDataOffset != mLastStreamDataOffset || lightsOffset != mLastLightsOffset) { - auto passManager = fb->GetRenderPassManager(); auto descriptors = fb->GetDescriptorSetManager(); + VulkanPipelineLayout* layout = GetPipelineLayout(mPipelineKey.NumTextureLayers); uint32_t offsets[4] = { mViewpointOffset, matrixOffset, streamDataOffset, lightsOffset }; - mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 0, fb->GetDescriptorSetManager()->GetFixedDescriptorSet()); - mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 1, descriptors->GetRSBufferDescriptorSet(threadIndex), 4, offsets); + mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptors->GetFixedDescriptorSet()); + mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 1, descriptors->GetRSBufferDescriptorSet(threadIndex), 4, offsets); mLastViewpointOffset = mViewpointOffset; mLastMatricesOffset = matrixOffset; @@ -755,7 +755,7 @@ void VkRenderState::BeginRenderPass(VulkanCommandBuffer *cmdbuffer) key.DrawBuffers = mRenderTarget.DrawBuffers; key.DepthStencil = !!mRenderTarget.DepthStencil; - mPassSetup = fb->GetRenderPassManager()->GetRenderPass(key); + mPassSetup = GetRenderPass(key); auto &framebuffer = mRenderTarget.Image->RSFramebuffers[key]; if (!framebuffer) @@ -795,6 +795,55 @@ void VkRenderState::BeginRenderPass(VulkanCommandBuffer *cmdbuffer) mClearTargets = 0; } +VkThreadRenderPassSetup* VkRenderState::GetRenderPass(const VkRenderPassKey& key) +{ + auto& item = mRenderPassSetups[key]; + if (!item) + item.reset(new VkThreadRenderPassSetup(fb, key)); + return item.get(); +} + +VulkanPipelineLayout* VkRenderState::GetPipelineLayout(int numLayers) +{ + if (mPipelineLayouts.size() <= (size_t)numLayers) + mPipelineLayouts.resize(numLayers + 1); + + auto& layout = mPipelineLayouts[numLayers]; + if (layout) + return layout; + + std::unique_lock lock(fb->ThreadMutex); + layout = fb->GetRenderPassManager()->GetPipelineLayout(numLayers); + return layout; +} + +///////////////////////////////////////////////////////////////////////////// + +VkThreadRenderPassSetup::VkThreadRenderPassSetup(VulkanRenderDevice* fb, const VkRenderPassKey& key) : PassKey(key), fb(fb) +{ +} + +VulkanRenderPass* VkThreadRenderPassSetup::GetRenderPass(int clearTargets) +{ + if (RenderPasses[clearTargets]) + return RenderPasses[clearTargets]; + + std::unique_lock lock(fb->ThreadMutex); + RenderPasses[clearTargets] = fb->GetRenderPassManager()->GetRenderPass(PassKey)->GetRenderPass(clearTargets); + return RenderPasses[clearTargets]; +} + +VulkanPipeline* VkThreadRenderPassSetup::GetPipeline(const VkPipelineKey& key) +{ + auto& item = Pipelines[key]; + if (item) + return item; + + std::unique_lock lock(fb->ThreadMutex); + item = fb->GetRenderPassManager()->GetRenderPass(PassKey)->GetPipeline(key); + return item; +} + ///////////////////////////////////////////////////////////////////////////// void VkRenderStateMolten::Draw(int dt, int index, int count, bool apply) diff --git a/src/common/rendering/vulkan/vk_renderstate.h b/src/common/rendering/vulkan/vk_renderstate.h index e89cc436c..0f9a6c279 100644 --- a/src/common/rendering/vulkan/vk_renderstate.h +++ b/src/common/rendering/vulkan/vk_renderstate.h @@ -12,7 +12,7 @@ #include "hw_material.h" class VulkanRenderDevice; -class VkRenderPassSetup; +class VkThreadRenderPassSetup; class VkTextureImage; class VkRenderState : public FRenderState @@ -78,6 +78,9 @@ protected: void BeginRenderPass(VulkanCommandBuffer *cmdbuffer); void WaitForStreamBuffers(); + VkThreadRenderPassSetup* GetRenderPass(const VkRenderPassKey& key); + VulkanPipelineLayout* GetPipelineLayout(int numLayers); + VulkanRenderDevice* fb = nullptr; int threadIndex = 0; @@ -86,7 +89,7 @@ protected: bool mDepthClamp = true; VulkanCommandBuffer *mCommandBuffer = nullptr; VkPipelineKey mPipelineKey = {}; - VkRenderPassSetup *mPassSetup = nullptr; + VkThreadRenderPassSetup* mPassSetup = nullptr; int mClearTargets = 0; bool mNeedApply = true; @@ -138,6 +141,24 @@ protected: VkSampleCountFlagBits Samples = VK_SAMPLE_COUNT_1_BIT; int DrawBuffers = 1; } mRenderTarget; + + std::map> mRenderPassSetups; + std::vector mPipelineLayouts; +}; + +class VkThreadRenderPassSetup +{ +public: + VkThreadRenderPassSetup(VulkanRenderDevice* fb, const VkRenderPassKey& key); + + VulkanRenderPass* GetRenderPass(int clearTargets); + VulkanPipeline* GetPipeline(const VkPipelineKey& key); + +private: + VkRenderPassKey PassKey; + VulkanRenderDevice* fb; + VulkanRenderPass* RenderPasses[8] = {}; + std::map Pipelines; }; class VkRenderStateMolten : public VkRenderState