diff --git a/drape/mesh_object.cpp b/drape/mesh_object.cpp index d9e1796773..1cd82f2f98 100644 --- a/drape/mesh_object.cpp +++ b/drape/mesh_object.cpp @@ -90,8 +90,6 @@ public: m_VAO = 0; } - void ResetCache(dp::RenderState const & state) override {} - void UpdateBuffer(ref_ptr context, uint32_t bufferInd) override { UNUSED_VALUE(context); @@ -206,12 +204,6 @@ void MeshObject::Reset() m_initialized = false; } -void MeshObject::ResetCache(dp::RenderState const & state) -{ - CHECK(m_impl != nullptr, ()); - m_impl->ResetCache(state); -} - void MeshObject::UpdateBuffer(ref_ptr context, uint32_t bufferInd, std::vector && vertices) { diff --git a/drape/mesh_object.hpp b/drape/mesh_object.hpp index f1893b0012..4e52f49a32 100644 --- a/drape/mesh_object.hpp +++ b/drape/mesh_object.hpp @@ -55,8 +55,6 @@ public: dp::RenderState const & state, ref_ptr paramsSetter, TParams const & params) { - ResetCache(state); - Bind(context, program); ApplyState(context, program, state); @@ -72,7 +70,6 @@ public: bool IsInitialized() const { return m_initialized; } void Build(ref_ptr context, ref_ptr program); void Reset(); - void ResetCache(dp::RenderState const & state); static std::vector GenerateNormalsForTriangles(std::vector const & vertices, size_t componentsCount); @@ -133,7 +130,6 @@ public: virtual ~MeshObjectImpl() = default; virtual void Build(ref_ptr context, ref_ptr program) = 0; virtual void Reset() = 0; - virtual void ResetCache(dp::RenderState const & state) = 0; virtual void UpdateBuffer(ref_ptr context, uint32_t bufferInd) = 0; virtual void Bind(ref_ptr program) = 0; virtual void Unbind() = 0; diff --git a/drape/metal/metal_mesh_object_impl.mm b/drape/metal/metal_mesh_object_impl.mm index d3ca9faa4f..65d210ca2a 100644 --- a/drape/metal/metal_mesh_object_impl.mm +++ b/drape/metal/metal_mesh_object_impl.mm @@ -66,8 +66,6 @@ public: m_geometryBuffers.clear(); } - void ResetCache(dp::RenderState const & state) override {} - void UpdateBuffer(ref_ptr context, uint32_t bufferInd) override { UNUSED_VALUE(context); diff --git a/drape/vulkan/vulkan_base_context.cpp b/drape/vulkan/vulkan_base_context.cpp index 4432e30dc9..d1995e8128 100644 --- a/drape/vulkan/vulkan_base_context.cpp +++ b/drape/vulkan/vulkan_base_context.cpp @@ -164,6 +164,8 @@ bool VulkanBaseContext::BeginRendering() if (!m_presentAvailable) return false; + m_frameCounter++; + // For commands that wait indefinitely for device execution // a return value of VK_ERROR_DEVICE_LOST is equivalent to VK_SUCCESS. VkResult res = vkWaitForFences(m_device, 1, &m_fence, VK_TRUE, UINT64_MAX); @@ -649,11 +651,11 @@ VkPipeline VulkanBaseContext::GetCurrentPipeline() return m_pipeline->GetPipeline(m_device, m_pipelineKey); } -DescriptorSetGroup VulkanBaseContext::GetCurrentDescriptorSetGroup() +std::vector const & VulkanBaseContext::GetCurrentParamDescriptors() const { CHECK(m_pipelineKey.m_program != nullptr, ()); CHECK(!m_paramDescriptors.empty(), ("Shaders parameters are not set.")); - return m_objectManager->CreateDescriptorSetGroup(m_pipelineKey.m_program, m_paramDescriptors); + return m_paramDescriptors; } VkPipelineLayout VulkanBaseContext::GetCurrentPipelineLayout() const diff --git a/drape/vulkan/vulkan_base_context.hpp b/drape/vulkan/vulkan_base_context.hpp index 21271b0107..e1e745f4bb 100644 --- a/drape/vulkan/vulkan_base_context.hpp +++ b/drape/vulkan/vulkan_base_context.hpp @@ -94,12 +94,16 @@ public: ref_ptr GetDefaultStagingBuffer() const; VkPipeline GetCurrentPipeline(); - DescriptorSetGroup GetCurrentDescriptorSetGroup(); VkPipelineLayout GetCurrentPipelineLayout() const; uint32_t GetCurrentDynamicBufferOffset() const; + std::vector const & GetCurrentParamDescriptors() const; + ref_ptr GetCurrentProgram() const { return m_pipelineKey.m_program; } + uint32_t GetCurrentFrameIndex() const { return m_frameCounter; } VkSampler GetSampler(SamplerKey const & key); + void UpdateDescriptorSetGroup(DescriptorSetGroup & descriptorSetGroup); + enum class HandlerType : uint8_t { PrePresent = 0, @@ -206,6 +210,7 @@ protected: drape_ptr m_defaultStagingBuffer; std::atomic m_presentAvailable; + uint32_t m_frameCounter = 0; }; } // namespace vulkan } // namespace dp diff --git a/drape/vulkan/vulkan_mesh_object_impl.cpp b/drape/vulkan/vulkan_mesh_object_impl.cpp index 52c4ac9bbc..a767c3a21a 100644 --- a/drape/vulkan/vulkan_mesh_object_impl.cpp +++ b/drape/vulkan/vulkan_mesh_object_impl.cpp @@ -42,6 +42,7 @@ public: ref_ptr vulkanContext = context; m_objectManager = vulkanContext->GetObjectManager(); + ResetDescriptorSetGroup(); m_geometryBuffers.resize(m_mesh->m_buffers.size()); m_bindingInfoCount = static_cast(m_mesh->m_buffers.size()); CHECK_LESS_OR_EQUAL(m_bindingInfoCount, kMaxBindingInfo, ()); @@ -73,15 +74,12 @@ public: void Reset() override { + ResetDescriptorSetGroup(); for (auto const & b : m_geometryBuffers) m_objectManager->DestroyObject(b); m_geometryBuffers.clear(); } - void ResetCache(dp::RenderState const & state) override - { - } - void UpdateBuffer(ref_ptr context, uint32_t bufferInd) override { CHECK_LESS(bufferInd, static_cast(m_geometryBuffers.size()), ()); @@ -153,12 +151,13 @@ public: vulkanContext->SetPrimitiveTopology(GetPrimitiveType(m_mesh->m_drawPrimitive)); vulkanContext->SetBindingInfo(m_bindingInfo, m_bindingInfoCount); - auto descriptorSetGroup = vulkanContext->GetCurrentDescriptorSetGroup(); + UpdateDescriptorSetGroup(vulkanContext); uint32_t dynamicOffset = vulkanContext->GetCurrentDynamicBufferOffset(); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkanContext->GetCurrentPipelineLayout(), 0, 1, - &descriptorSetGroup.m_descriptorSet, 1, &dynamicOffset); + &m_descriptorSetGroups[m_descriptorSetIndex].m_descriptorSet, + 1, &dynamicOffset); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkanContext->GetCurrentPipeline()); @@ -168,19 +167,54 @@ public: vkCmdBindVertexBuffers(commandBuffer, i, 1, &m_geometryBuffers[i].m_buffer, offsets); vkCmdDraw(commandBuffer, verticesCount, 1, 0, 0); - - m_objectManager->DestroyDescriptorSetGroup(descriptorSetGroup); } void Bind(ref_ptr program) override {} void Unbind() override {} private: + void ResetDescriptorSetGroup() + { + for (auto const & g : m_descriptorSetGroups) + m_objectManager->DestroyDescriptorSetGroup(g); + m_descriptorSetGroups.clear(); + } + + void UpdateDescriptorSetGroup(ref_ptr vulkanContext) + { + if (m_program != vulkanContext->GetCurrentProgram()) + { + ResetDescriptorSetGroup(); + m_program = vulkanContext->GetCurrentProgram(); + } + + if (m_updateDescriptorFrame != vulkanContext->GetCurrentFrameIndex()) + { + m_updateDescriptorFrame = vulkanContext->GetCurrentFrameIndex(); + m_descriptorSetIndex = 0; + } + else + { + m_descriptorSetIndex++; + } + + CHECK_LESS_OR_EQUAL(m_descriptorSetIndex, m_descriptorSetGroups.size(), ()); + if (m_descriptorSetIndex == m_descriptorSetGroups.size()) + m_descriptorSetGroups.emplace_back(m_objectManager->CreateDescriptorSetGroup(m_program)); + + m_descriptorSetGroups[m_descriptorSetIndex].Update(vulkanContext->GetDevice(), + vulkanContext->GetCurrentParamDescriptors()); + } + ref_ptr m_mesh; ref_ptr m_objectManager; std::vector m_geometryBuffers; BindingInfoArray m_bindingInfo; uint8_t m_bindingInfoCount = 0; + std::vector m_descriptorSetGroups; + ref_ptr m_program; + uint32_t m_updateDescriptorFrame = 0; + uint32_t m_descriptorSetIndex = 0; }; } // namespace vulkan diff --git a/drape/vulkan/vulkan_object_manager.cpp b/drape/vulkan/vulkan_object_manager.cpp index f0f7b9e6e8..0d59e983b8 100644 --- a/drape/vulkan/vulkan_object_manager.cpp +++ b/drape/vulkan/vulkan_object_manager.cpp @@ -157,8 +157,7 @@ VulkanObject VulkanObjectManager::CreateImage(VkImageUsageFlags usageFlags, VkFo return result; } -DescriptorSetGroup VulkanObjectManager::CreateDescriptorSetGroup(ref_ptr program, - std::vector const & descriptors) +DescriptorSetGroup VulkanObjectManager::CreateDescriptorSetGroup(ref_ptr program) { std::lock_guard lock(m_mutex); @@ -190,36 +189,6 @@ DescriptorSetGroup VulkanObjectManager::CreateDescriptorSetGroup(ref_ptr writeDescriptorSets(descriptors.size()); - for (size_t i = 0; i < writeDescriptorSets.size(); ++i) - { - auto const & p = descriptors[i]; - - writeDescriptorSets[i] = {}; - writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[i].dstSet = s.m_descriptorSet; - writeDescriptorSets[i].descriptorCount = 1; - if (p.m_type == ParamDescriptor::Type::DynamicUniformBuffer) - { - writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - writeDescriptorSets[i].dstBinding = 0; - writeDescriptorSets[i].pBufferInfo = &p.m_bufferDescriptor; - } - else if (p.m_type == ParamDescriptor::Type::Texture) - { - writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptorSets[i].dstBinding = static_cast(p.m_textureSlot); - writeDescriptorSets[i].pImageInfo = &p.m_imageDescriptor; - } - else - { - CHECK(false, ("Unsupported param descriptor type.")); - } - } - - vkUpdateDescriptorSets(m_device, static_cast(writeDescriptorSets.size()), - writeDescriptorSets.data(), 0, nullptr); return s; } diff --git a/drape/vulkan/vulkan_object_manager.hpp b/drape/vulkan/vulkan_object_manager.hpp index 20a2fe41a1..d456cf26ff 100644 --- a/drape/vulkan/vulkan_object_manager.hpp +++ b/drape/vulkan/vulkan_object_manager.hpp @@ -61,8 +61,7 @@ public: uint32_t sizeInBytes, uint64_t batcherHash); VulkanObject CreateImage(VkImageUsageFlags usageFlags, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t width, uint32_t height); - DescriptorSetGroup CreateDescriptorSetGroup(ref_ptr program, - std::vector const & descriptors); + DescriptorSetGroup CreateDescriptorSetGroup(ref_ptr program); // Use unsafe function ONLY if an object exists on the only thread, otherwise // use safe Fill function. diff --git a/drape/vulkan/vulkan_utils.cpp b/drape/vulkan/vulkan_utils.cpp index e5d99459e7..d6ae47b63a 100644 --- a/drape/vulkan/vulkan_utils.cpp +++ b/drape/vulkan/vulkan_utils.cpp @@ -1,5 +1,7 @@ #include "drape/vulkan/vulkan_utils.hpp" +#include + namespace dp { namespace vulkan @@ -103,5 +105,36 @@ bool SamplerKey::operator<(SamplerKey const & rhs) const { return m_sampler < rhs.m_sampler; } + +void DescriptorSetGroup::Update(VkDevice device, std::vector const & descriptors) +{ + std::vector writeDescriptorSets(descriptors.size()); + for (size_t i = 0; i < writeDescriptorSets.size(); ++i) + { + writeDescriptorSets[i] = {}; + writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[i].dstSet = m_descriptorSet; + writeDescriptorSets[i].descriptorCount = 1; + if (descriptors[i].m_type == ParamDescriptor::Type::DynamicUniformBuffer) + { + writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + writeDescriptorSets[i].dstBinding = 0; + writeDescriptorSets[i].pBufferInfo = &descriptors[i].m_bufferDescriptor; + } + else if (descriptors[i].m_type == ParamDescriptor::Type::Texture) + { + writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSets[i].dstBinding = static_cast(descriptors[i].m_textureSlot); + writeDescriptorSets[i].pImageInfo = &descriptors[i].m_imageDescriptor; + } + else + { + CHECK(false, ("Unsupported param descriptor type.")); + } + } + + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), + writeDescriptorSets.data(), 0, nullptr); +} } // namespace vulkan } // namespace dp diff --git a/drape/vulkan/vulkan_utils.hpp b/drape/vulkan/vulkan_utils.hpp index bee3953593..5c63e93e5f 100644 --- a/drape/vulkan/vulkan_utils.hpp +++ b/drape/vulkan/vulkan_utils.hpp @@ -9,6 +9,7 @@ #include #include +#include namespace dp { @@ -44,6 +45,8 @@ struct DescriptorSetGroup return m_descriptorSet != VK_NULL_HANDLE && m_descriptorPool != VK_NULL_HANDLE; } + + void Update(VkDevice device, std::vector const & descriptors); }; template diff --git a/drape/vulkan/vulkan_vertex_array_buffer_impl.cpp b/drape/vulkan/vulkan_vertex_array_buffer_impl.cpp index 2cbe1e3110..3c05cbd720 100644 --- a/drape/vulkan/vulkan_vertex_array_buffer_impl.cpp +++ b/drape/vulkan/vulkan_vertex_array_buffer_impl.cpp @@ -32,6 +32,11 @@ public: , m_bindingInfoCount(bindingInfoCount) {} + ~VulkanVertexArrayBufferImpl() override + { + ResetDescriptorSetGroup(); + } + bool Build(ref_ptr program) override { UNUSED_VALUE(program); @@ -53,12 +58,13 @@ public: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); vulkanContext->SetBindingInfo(m_bindingInfo, m_bindingInfoCount); - auto descriptorSetGroup = vulkanContext->GetCurrentDescriptorSetGroup(); + UpdateDescriptorSetGroup(vulkanContext); uint32_t dynamicOffset = vulkanContext->GetCurrentDynamicBufferOffset(); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkanContext->GetCurrentPipelineLayout(), 0, 1, - &descriptorSetGroup.m_descriptorSet, 1, &dynamicOffset); + &m_descriptorSetGroups[m_descriptorSetIndex].m_descriptorSet, + 1, &dynamicOffset); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkanContext->GetCurrentPipeline()); @@ -86,15 +92,50 @@ public: vkCmdBindIndexBuffer(commandBuffer, vulkanIndexBuffer, 0, indexType); vkCmdDrawIndexed(commandBuffer, range.m_idxCount, 1, range.m_idxStart, 0, 0); - - m_objectManager->DestroyDescriptorSetGroup(descriptorSetGroup); } private: + void ResetDescriptorSetGroup() + { + for (auto const & g : m_descriptorSetGroups) + m_objectManager->DestroyDescriptorSetGroup(g); + m_descriptorSetGroups.clear(); + } + + void UpdateDescriptorSetGroup(ref_ptr vulkanContext) + { + if (m_program != vulkanContext->GetCurrentProgram()) + { + ResetDescriptorSetGroup(); + m_program = vulkanContext->GetCurrentProgram(); + } + + if (m_updateDescriptorFrame != vulkanContext->GetCurrentFrameIndex()) + { + m_updateDescriptorFrame = vulkanContext->GetCurrentFrameIndex(); + m_descriptorSetIndex = 0; + } + else + { + m_descriptorSetIndex++; + } + + CHECK_LESS_OR_EQUAL(m_descriptorSetIndex, m_descriptorSetGroups.size(), ()); + if (m_descriptorSetIndex == m_descriptorSetGroups.size()) + m_descriptorSetGroups.emplace_back(m_objectManager->CreateDescriptorSetGroup(m_program)); + + m_descriptorSetGroups[m_descriptorSetIndex].Update(vulkanContext->GetDevice(), + vulkanContext->GetCurrentParamDescriptors()); + } + ref_ptr m_vertexArrayBuffer; ref_ptr m_objectManager; BindingInfoArray m_bindingInfo; uint8_t m_bindingInfoCount = 0; + std::vector m_descriptorSetGroups; + ref_ptr m_program; + uint32_t m_updateDescriptorFrame = 0; + uint32_t m_descriptorSetIndex = 0; }; } // namespace vulkan