diff --git a/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.cpp b/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.cpp index 83972cc40e..cbe3e8eb12 100644 --- a/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.cpp +++ b/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.cpp @@ -37,6 +37,11 @@ public: CreateCommandPool(); CreateSyncPrimitives(); } + + void MakeCurrent() override + { + m_objectManager->RegisterRendererThread(dp::vulkan::VulkanObjectManager::Frontend); + } }; class UploadVulkanContext : public dp::vulkan::VulkanBaseContext @@ -51,8 +56,13 @@ public: nullptr /* pipeline */) {} + void MakeCurrent() override + { + m_objectManager->RegisterRendererThread(dp::vulkan::VulkanObjectManager::Backend); + } + void Present() override {} - void MakeCurrent() override {} + void Resize(int w, int h) override {} void SetFramebuffer(ref_ptr framebuffer) override {} void Init(dp::ApiVersion apiVersion) override diff --git a/drape/graphics_context.hpp b/drape/graphics_context.hpp index 6b8f54dc53..b8aef1c294 100644 --- a/drape/graphics_context.hpp +++ b/drape/graphics_context.hpp @@ -63,6 +63,7 @@ public: virtual void SetRenderingEnabled(bool /* enabled */) {} virtual void SetPresentAvailable(bool /* available */) {} virtual bool Validate() { return true; } + virtual void CollectMemory() {} virtual void Init(ApiVersion apiVersion) = 0; virtual ApiVersion GetApiVersion() const = 0; diff --git a/drape/vulkan/vulkan_base_context.cpp b/drape/vulkan/vulkan_base_context.cpp index 3807098987..d91134387f 100644 --- a/drape/vulkan/vulkan_base_context.cpp +++ b/drape/vulkan/vulkan_base_context.cpp @@ -1,6 +1,5 @@ #include "drape/vulkan/vulkan_base_context.hpp" -#include "drape/drape_routine.hpp" #include "drape/vulkan/vulkan_staging_buffer.hpp" #include "drape/vulkan/vulkan_texture.hpp" #include "drape/vulkan/vulkan_utils.hpp" @@ -107,6 +106,7 @@ std::string VulkanBaseContext::GetRendererVersion() const void VulkanBaseContext::Init(ApiVersion apiVersion) { + UNUSED_VALUE(apiVersion); m_defaultStagingBuffer = make_unique_dp(m_objectManager, kDefaultStagingBufferSizeInBytes); } @@ -413,27 +413,23 @@ void VulkanBaseContext::Present() for (auto const & h : m_handlers[static_cast(HandlerType::PostPresent)]) h.second(make_ref(this)); - // Resetting of the default staging buffer and collecting destroyed objects must be - // only after the finishing of rendering. It prevents data collisions. + // Resetting of the default staging buffer only after the finishing of rendering. + // It prevents data collisions. m_defaultStagingBuffer->Reset(); - m_objectManager->CollectObjectsSync(); - static uint8_t framesCounter = 0; - if (framesCounter % 10 == 0) - { - framesCounter = 0; - DrapeRoutine::Run([this]() { m_objectManager->CollectObjectsAsync(); }); - } - else - { - framesCounter++; - } + // Descriptors can be used only on the thread which renders. + m_objectManager->CollectDescriptorSetGroups(); m_pipelineKey = {}; m_stencilReferenceValue = 1; ClearParamDescriptors(); } +void VulkanBaseContext::CollectMemory() +{ + m_objectManager->CollectObjects(); +} + uint32_t VulkanBaseContext::RegisterHandler(HandlerType handlerType, ContextHandler && handler) { static uint32_t counter = 0; diff --git a/drape/vulkan/vulkan_base_context.hpp b/drape/vulkan/vulkan_base_context.hpp index 0fb6f91f93..cbd9449f3b 100644 --- a/drape/vulkan/vulkan_base_context.hpp +++ b/drape/vulkan/vulkan_base_context.hpp @@ -41,8 +41,8 @@ public: bool BeginRendering() override; void Present() override; - void MakeCurrent() override {}; - void DoneCurrent() override {}; + void CollectMemory() override; + void DoneCurrent() override {} bool Validate() override { return true; } void Resize(int w, int h) override; void SetFramebuffer(ref_ptr framebuffer) override; diff --git a/drape/vulkan/vulkan_memory_manager.cpp b/drape/vulkan/vulkan_memory_manager.cpp index 6015112b62..6954773b80 100644 --- a/drape/vulkan/vulkan_memory_manager.cpp +++ b/drape/vulkan/vulkan_memory_manager.cpp @@ -17,7 +17,7 @@ namespace std::array const kMinBlockSizeInBytes = {{ 1024 * 1024, // Geometry - 0, // Uniform (no minimal size) + 64 * 1024, // Uniform (no minimal size) 0, // Staging (no minimal size) 0, // Image (no minimal size) }}; diff --git a/drape/vulkan/vulkan_object_manager.cpp b/drape/vulkan/vulkan_object_manager.cpp index 0d59e983b8..3bfcad157a 100644 --- a/drape/vulkan/vulkan_object_manager.cpp +++ b/drape/vulkan/vulkan_object_manager.cpp @@ -1,5 +1,7 @@ #include "drape/vulkan/vulkan_object_manager.hpp" +#include "drape/drape_routine.hpp" + #include "base/macros.hpp" #include @@ -39,15 +41,18 @@ VulkanObjectManager::VulkanObjectManager(VkDevice device, VkPhysicalDeviceLimits , m_queueFamilyIndex(queueFamilyIndex) , m_memoryManager(device, deviceLimits, memoryProperties) { - m_queueToDestroy.reserve(50); + for (size_t i = 0; i < RendererType::Count; ++i) + m_queuesToDestroy[i].reserve(50); m_descriptorsToDestroy.reserve(50); CreateDescriptorPool(); } VulkanObjectManager::~VulkanObjectManager() { - CollectObjectsSync(); - CollectObjectsAsync(); + CollectDescriptorSetGroups(); + + for (size_t i = 0; i < RendererType::Count; ++i) + CollectObjectsImpl(m_queuesToDestroy[i]); for (auto const & s : m_samplers) vkDestroySampler(m_device, s.second, nullptr); @@ -56,6 +61,11 @@ VulkanObjectManager::~VulkanObjectManager() DestroyDescriptorPools(); } +void VulkanObjectManager::RegisterRendererThread(RendererType type) +{ + m_renderers[type] = std::this_thread::get_id(); +} + VulkanObject VulkanObjectManager::CreateBuffer(VulkanMemoryManager::ResourceType resourceType, uint32_t sizeInBytes, uint64_t batcherHash) { @@ -159,7 +169,7 @@ VulkanObject VulkanObjectManager::CreateImage(VkImageUsageFlags usageFlags, VkFo DescriptorSetGroup VulkanObjectManager::CreateDescriptorSetGroup(ref_ptr program) { - std::lock_guard lock(m_mutex); + CHECK(std::this_thread::get_id() == m_renderers[RendererType::Frontend], ()); CHECK(!m_descriptorPools.empty(), ()); @@ -194,59 +204,76 @@ DescriptorSetGroup VulkanObjectManager::CreateDescriptorSetGroup(ref_ptr lock(m_destroyMutex); - m_queueToDestroy.push_back(std::move(object)); + auto const currentThreadId = std::this_thread::get_id(); + if (currentThreadId == m_renderers[RendererType::Frontend]) + m_queuesToDestroy[RendererType::Frontend].push_back(std::move(object)); + else if (currentThreadId == m_renderers[RendererType::Backend]) + m_queuesToDestroy[RendererType::Backend].push_back(std::move(object)); + else + CHECK(false, ("Unknown thread.")); } void VulkanObjectManager::DestroyDescriptorSetGroup(DescriptorSetGroup group) { - std::lock_guard lock(m_destroyMutex); + CHECK(std::this_thread::get_id() == m_renderers[RendererType::Frontend], ()); m_descriptorsToDestroy.push_back(std::move(group)); } -void VulkanObjectManager::CollectObjectsSync() +void VulkanObjectManager::CollectDescriptorSetGroups() { - std::vector descriptorsToDestroy; - { - std::lock_guard lock(m_destroyMutex); - std::swap(m_descriptorsToDestroy, descriptorsToDestroy); - } - for (auto const & d : descriptorsToDestroy) + CHECK(std::this_thread::get_id() == m_renderers[RendererType::Frontend], ()); + for (auto const & d : m_descriptorsToDestroy) { CHECK_VK_CALL(vkFreeDescriptorSets(m_device, d.m_descriptorPool, 1 /* count */, &d.m_descriptorSet)); } + m_descriptorsToDestroy.clear(); } -void VulkanObjectManager::CollectObjectsAsync() +void VulkanObjectManager::CollectObjects() { + auto const currentThreadId = std::this_thread::get_id(); + if (currentThreadId == m_renderers[RendererType::Frontend]) + CollectObjectsForThread(RendererType::Frontend); + else if (currentThreadId == m_renderers[RendererType::Backend]) + CollectObjectsForThread(RendererType::Backend); + else + CHECK(false, ("Unknown thread.")); +} + +void VulkanObjectManager::CollectObjectsForThread(RendererType type) +{ + if (m_queuesToDestroy[type].empty()) + return; + std::vector queueToDestroy; + std::swap(m_queuesToDestroy[type], queueToDestroy); + DrapeRoutine::Run([this, queueToDestroy = std::move(queueToDestroy)]() { - std::lock_guard lock(m_destroyMutex); - std::swap(m_queueToDestroy, queueToDestroy); + CollectObjectsImpl(queueToDestroy); + }); +} + +void VulkanObjectManager::CollectObjectsImpl(std::vector const & objects) +{ + for (auto const & obj : objects) + { + if (obj.m_buffer != VK_NULL_HANDLE) + vkDestroyBuffer(m_device, obj.m_buffer, nullptr); + if (obj.m_imageView != VK_NULL_HANDLE) + vkDestroyImageView(m_device, obj.m_imageView, nullptr); + if (obj.m_image != VK_NULL_HANDLE) + vkDestroyImage(m_device, obj.m_image, nullptr); } - if (!queueToDestroy.empty()) + std::lock_guard lock(m_mutex); + m_memoryManager.BeginDeallocationSession(); + for (auto const & obj : objects) { - for (size_t i = 0; i < queueToDestroy.size(); ++i) - { - if (queueToDestroy[i].m_buffer != 0) - vkDestroyBuffer(m_device, queueToDestroy[i].m_buffer, nullptr); - if (queueToDestroy[i].m_imageView != 0) - vkDestroyImageView(m_device, queueToDestroy[i].m_imageView, nullptr); - if (queueToDestroy[i].m_image != 0) - vkDestroyImage(m_device, queueToDestroy[i].m_image, nullptr); - } - - std::lock_guard lock(m_mutex); - m_memoryManager.BeginDeallocationSession(); - for (size_t i = 0; i < queueToDestroy.size(); ++i) - { - if (queueToDestroy[i].m_allocation) - m_memoryManager.Deallocate(queueToDestroy[i].m_allocation); - } - m_memoryManager.EndDeallocationSession(); + if (obj.m_allocation) + m_memoryManager.Deallocate(obj.m_allocation); } + m_memoryManager.EndDeallocationSession(); } uint8_t * VulkanObjectManager::MapUnsafe(VulkanObject object) diff --git a/drape/vulkan/vulkan_object_manager.hpp b/drape/vulkan/vulkan_object_manager.hpp index 79f4ccb70a..33ff0f2123 100644 --- a/drape/vulkan/vulkan_object_manager.hpp +++ b/drape/vulkan/vulkan_object_manager.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace dp @@ -58,6 +59,14 @@ public: uint32_t queueFamilyIndex); ~VulkanObjectManager(); + enum RendererType + { + Frontend = 0, + Backend, + Count + }; + void RegisterRendererThread(RendererType type); + VulkanObject CreateBuffer(VulkanMemoryManager::ResourceType resourceType, uint32_t sizeInBytes, uint64_t batcherHash); VulkanObject CreateImage(VkImageUsageFlags usageFlags, VkFormat format, @@ -73,8 +82,8 @@ public: void DestroyObject(VulkanObject object); void DestroyDescriptorSetGroup(DescriptorSetGroup group); - void CollectObjectsSync(); - void CollectObjectsAsync(); + void CollectDescriptorSetGroups(); + void CollectObjects(); VkDevice GetDevice() const { return m_device; } VulkanMemoryManager const & GetMemoryManager() const { return m_memoryManager; }; @@ -83,11 +92,15 @@ public: private: void CreateDescriptorPool(); void DestroyDescriptorPools(); + void CollectObjectsForThread(RendererType type); + void CollectObjectsImpl(std::vector const & objects); VkDevice const m_device; uint32_t const m_queueFamilyIndex; VulkanMemoryManager m_memoryManager; - std::vector m_queueToDestroy; + + std::array m_renderers = {}; + std::array, RendererType::Count> m_queuesToDestroy = {}; std::vector m_descriptorPools; std::vector m_descriptorsToDestroy; diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index 0ce242b18c..109028e792 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -655,8 +655,11 @@ void BackendRenderer::Routine::Do() void BackendRenderer::RenderFrame() { CHECK(m_context != nullptr, ()); - if (m_context->Validate()) - ProcessSingleMessage(); + if (!m_context->Validate()) + return; + + ProcessSingleMessage(); + m_context->CollectMemory(); } void BackendRenderer::InitContextDependentResources() diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index b3d1245974..10f53219d4 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -1715,6 +1715,7 @@ void FrontendRenderer::RenderFrame() #ifndef DISABLE_SCREEN_PRESENTATION m_context->Present(); + m_context->CollectMemory(); #endif // Limit fps in following mode.