From 8d144bfd385a47cda0ca739b34088abedc92b1b7 Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Wed, 20 Feb 2019 09:13:34 +0300 Subject: [PATCH] [vulkan] Fixed frame buffers recreation --- android/jni/com/mapswithme/maps/Framework.cpp | 3 +- .../vulkan/android_vulkan_context_factory.cpp | 12 ++- .../vulkan/android_vulkan_context_factory.hpp | 2 +- drape/graphics_context.hpp | 2 +- drape/vertex_array_buffer.cpp | 15 ++- drape/vulkan/vulkan_base_context.cpp | 96 +++++++++++++------ drape/vulkan/vulkan_base_context.hpp | 10 +- drape/vulkan/vulkan_mesh_object_impl.cpp | 7 +- drape_frontend/frontend_renderer.cpp | 8 +- 9 files changed, 104 insertions(+), 51 deletions(-) diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp index df98407f11..97bb206d60 100644 --- a/android/jni/com/mapswithme/maps/Framework.cpp +++ b/android/jni/com/mapswithme/maps/Framework.cpp @@ -303,7 +303,8 @@ void Framework::DetachSurface(bool destroyContext) // destroyed in ResetSurface(). m_work.SetRenderingDisabled(false /* destroyContext */); - CastFactory(m_vulkanContextFactory)->ResetSurface(); + // Allow pipeline dump only on enter background. + CastFactory(m_vulkanContextFactory)->ResetSurface(destroyContext /* allowPipelineDump */); } else { 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 659b0e2646..4607d50323 100644 --- a/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.cpp +++ b/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.cpp @@ -30,7 +30,13 @@ public: renderingQueueFamilyIndex, objectManager, make_unique_dp( device, appVersionCode)) - {} + { + VkQueue queue; + vkGetDeviceQueue(device, renderingQueueFamilyIndex, 0, &queue); + SetRenderingQueue(queue); + CreateCommandPool(); + CreateSyncPrimitives(); + } }; class UploadVulkanContext : public dp::vulkan::VulkanBaseContext @@ -334,9 +340,9 @@ bool AndroidVulkanContextFactory::QuerySurfaceSize() return true; } -void AndroidVulkanContextFactory::ResetSurface() +void AndroidVulkanContextFactory::ResetSurface(bool allowPipelineDump) { - ResetVulkanSurface(true /* allowPipelineDump */); + ResetVulkanSurface(allowPipelineDump); ANativeWindow_release(m_nativeWindow); m_nativeWindow = nullptr; diff --git a/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.hpp b/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.hpp index 49ed3f23ca..5adf4d852f 100644 --- a/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.hpp +++ b/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.hpp @@ -32,7 +32,7 @@ public: void SetPresentAvailable(bool available) override; void SetSurface(JNIEnv * env, jobject jsurface); - void ResetSurface(); + void ResetSurface(bool allowPipelineDump); void ChangeSurface(JNIEnv * env, jobject jsurface, int w, int h); int GetWidth() const; diff --git a/drape/graphics_context.hpp b/drape/graphics_context.hpp index 1019ec6d9f..6b8f54dc53 100644 --- a/drape/graphics_context.hpp +++ b/drape/graphics_context.hpp @@ -51,7 +51,7 @@ class GraphicsContext { public: virtual ~GraphicsContext() = default; - virtual void BeginRendering() {} + virtual bool BeginRendering() { return true; } virtual void Present() = 0; virtual void MakeCurrent() = 0; virtual void DoneCurrent() {} diff --git a/drape/vertex_array_buffer.cpp b/drape/vertex_array_buffer.cpp index b77dce0389..5409e5646c 100644 --- a/drape/vertex_array_buffer.cpp +++ b/drape/vertex_array_buffer.cpp @@ -436,16 +436,13 @@ ref_ptr VertexArrayBuffer::GetIndexBuffer() const void VertexArrayBuffer::CollectBindingInfo(dp::BindingInfo const & bindingInfo) { - auto const id = bindingInfo.GetID(); - auto const it = std::find_if(m_bindingInfo.begin(), m_bindingInfo.end(), - [id](dp::BindingInfo const & info) + for (size_t i = 0; i < m_bindingInfoCount; ++i) { - return info.GetID() == id; - }); - if (it != m_bindingInfo.end()) - { - CHECK(*it == bindingInfo, ("Incorrect binding info.")); - return; + if (m_bindingInfo[i].GetID() == bindingInfo.GetID()) + { + CHECK(m_bindingInfo[i] == bindingInfo, ("Incorrect binding info.")); + return; + } } CHECK_LESS(m_bindingInfoCount, kMaxBindingInfo, ()); diff --git a/drape/vulkan/vulkan_base_context.cpp b/drape/vulkan/vulkan_base_context.cpp index 7a9bc0809e..1cea51e2a9 100644 --- a/drape/vulkan/vulkan_base_context.cpp +++ b/drape/vulkan/vulkan_base_context.cpp @@ -54,13 +54,8 @@ VulkanBaseContext::VulkanBaseContext(VkInstance vulkanInstance, VkPhysicalDevice , m_renderingQueueFamilyIndex(renderingQueueFamilyIndex) , m_objectManager(std::move(objectManager)) , m_pipeline(std::move(pipeline)) -{ - //TODO: do it for draw context only. - // Get a graphics queue from the device - vkGetDeviceQueue(m_device, m_renderingQueueFamilyIndex, 0, &m_queue); - CreateCommandPool(); - CreateSyncPrimitives(); -} + , m_presentAvailable(true) +{} VulkanBaseContext::~VulkanBaseContext() { @@ -104,21 +99,41 @@ void VulkanBaseContext::Init(ApiVersion apiVersion) kDefaultStagingBufferSizeInBytes); } +void VulkanBaseContext::SetPresentAvailable(bool available) +{ + LOG(LINFO, ("Present available: ", available)); + m_presentAvailable = available; +} + void VulkanBaseContext::SetSurface(VkSurfaceKHR surface, VkSurfaceFormatKHR surfaceFormat, VkSurfaceCapabilitiesKHR const & surfaceCapabilities) { m_surface = surface; m_surfaceFormat = surfaceFormat; m_surfaceCapabilities = surfaceCapabilities; - CreateCommandBuffers(); - RecreateDepthTexture(); - RecreateSwapchain(); + RecreateSwapchainAndDependencies(); } void VulkanBaseContext::ResetSurface(bool allowPipelineDump) { vkDeviceWaitIdle(m_device); + ResetSwapchainAndDependencies(); + m_surface.reset(); + if (m_pipeline && allowPipelineDump) + m_pipeline->Dump(m_device); +} + +void VulkanBaseContext::RecreateSwapchainAndDependencies() +{ + ResetSwapchainAndDependencies(); + CreateCommandBuffers(); + RecreateDepthTexture(); + RecreateSwapchain(); +} + +void VulkanBaseContext::ResetSwapchainAndDependencies() +{ if (m_pipeline) m_pipeline->ResetCache(m_device); @@ -127,11 +142,11 @@ void VulkanBaseContext::ResetSurface(bool allowPipelineDump) DestroyCommandBuffers(); DestroySwapchain(); +} - m_surface.reset(); - - if (m_pipeline && allowPipelineDump) - m_pipeline->Dump(m_device); +void VulkanBaseContext::SetRenderingQueue(VkQueue queue) +{ + m_queue = queue; } void VulkanBaseContext::Resize(int w, int h) @@ -148,13 +163,20 @@ void VulkanBaseContext::Resize(int w, int h) m_surfaceCapabilities.currentExtent.width = static_cast(w); m_surfaceCapabilities.currentExtent.height = static_cast(h); - RecreateDepthTexture(); - RecreateSwapchain(); + RecreateSwapchainAndDependencies(); } -void VulkanBaseContext::BeginRendering() +bool VulkanBaseContext::BeginRendering() { - CHECK_VK_CALL(vkWaitForFences(m_device, 1, &m_fence, VK_TRUE, UINT64_MAX)); + if (!m_presentAvailable) + return false; + + // 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); + if (res != VK_SUCCESS && res != VK_ERROR_DEVICE_LOST) + CHECK_RESULT_VK_CALL(vkWaitForFences, res); + CHECK_VK_CALL(vkResetFences(m_device, 1, &m_fence)); VkCommandBufferBeginInfo commandBufferBeginInfo = {}; @@ -163,12 +185,14 @@ void VulkanBaseContext::BeginRendering() CHECK_VK_CALL(vkBeginCommandBuffer(m_memoryCommandBuffer, &commandBufferBeginInfo)); CHECK_VK_CALL(vkBeginCommandBuffer(m_renderingCommandBuffer, &commandBufferBeginInfo)); - VkResult res = vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX, m_presentComplete, - (VkFence)nullptr, &m_imageIndex); + res = vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX, m_presentComplete, + VK_NULL_HANDLE, &m_imageIndex); if (res == VK_ERROR_OUT_OF_DATE_KHR || res == VK_SUBOPTIMAL_KHR) - RecreateSwapchain(); + RecreateSwapchainAndDependencies(); else CHECK_RESULT_VK_CALL(vkAcquireNextImageKHR, res); + + return true; } void VulkanBaseContext::SetFramebuffer(ref_ptr framebuffer) @@ -365,12 +389,16 @@ void VulkanBaseContext::Present() if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR) { if (res == VK_ERROR_OUT_OF_DATE_KHR) - RecreateSwapchain(); + RecreateSwapchainAndDependencies(); else CHECK_RESULT_VK_CALL(vkQueuePresentKHR, res); } - CHECK_VK_CALL(vkQueueWaitIdle(m_queue)); + // For commands that wait indefinitely for device execution + // a return value of VK_ERROR_DEVICE_LOST is equivalent to VK_SUCCESS. + res = vkQueueWaitIdle(m_queue); + if (res != VK_SUCCESS && res != VK_ERROR_DEVICE_LOST) + CHECK_RESULT_VK_CALL(vkQueueWaitIdle, res); for (auto const & h : m_handlers[static_cast(HandlerType::PostPresent)]) h.second(make_ref(this)); @@ -751,11 +779,13 @@ void VulkanBaseContext::CreateCommandPool() void VulkanBaseContext::DestroyCommandPool() { - vkDestroyCommandPool(m_device, m_commandPool, nullptr); + if (m_commandPool != VK_NULL_HANDLE) + vkDestroyCommandPool(m_device, m_commandPool, nullptr); } void VulkanBaseContext::CreateCommandBuffers() { + CHECK(m_commandPool != VK_NULL_HANDLE, ()); VkCommandBufferAllocateInfo cmdBufAllocateInfo = {}; cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; cmdBufAllocateInfo.commandPool = m_commandPool; @@ -767,8 +797,11 @@ void VulkanBaseContext::CreateCommandBuffers() void VulkanBaseContext::DestroyCommandBuffers() { - vkFreeCommandBuffers(m_device, m_commandPool, 1, &m_memoryCommandBuffer); - vkFreeCommandBuffers(m_device, m_commandPool, 1, &m_renderingCommandBuffer); + if (m_memoryCommandBuffer != VK_NULL_HANDLE) + vkFreeCommandBuffers(m_device, m_commandPool, 1, &m_memoryCommandBuffer); + + if (m_renderingCommandBuffer != VK_NULL_HANDLE) + vkFreeCommandBuffers(m_device, m_commandPool, 1, &m_renderingCommandBuffer); } void VulkanBaseContext::CreateSyncPrimitives() @@ -788,9 +821,14 @@ void VulkanBaseContext::CreateSyncPrimitives() void VulkanBaseContext::DestroySyncPrimitives() { - vkDestroyFence(m_device, m_fence, nullptr); - vkDestroySemaphore(m_device, m_presentComplete, nullptr); - vkDestroySemaphore(m_device, m_renderComplete, nullptr); + if (m_fence != VK_NULL_HANDLE) + vkDestroyFence(m_device, m_fence, nullptr); + + if (m_presentComplete != VK_NULL_HANDLE) + vkDestroySemaphore(m_device, m_presentComplete, nullptr); + + if (m_renderComplete != VK_NULL_HANDLE) + vkDestroySemaphore(m_device, m_renderComplete, nullptr); } void VulkanBaseContext::RecreateDepthTexture() diff --git a/drape/vulkan/vulkan_base_context.hpp b/drape/vulkan/vulkan_base_context.hpp index a487addcde..21271b0107 100644 --- a/drape/vulkan/vulkan_base_context.hpp +++ b/drape/vulkan/vulkan_base_context.hpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -37,7 +38,7 @@ public: using ContextHandler = std::function)>; - void BeginRendering() override; + bool BeginRendering() override; void Present() override; void MakeCurrent() override {}; void DoneCurrent() override {}; @@ -46,6 +47,7 @@ public: void SetFramebuffer(ref_ptr framebuffer) override; void ApplyFramebuffer(std::string const & framebufferLabel) override; void Init(ApiVersion apiVersion) override; + void SetPresentAvailable(bool available) override; ApiVersion GetApiVersion() const override { return dp::ApiVersion::Vulkan; } std::string GetRendererName() const override; std::string GetRendererVersion() const override; @@ -109,6 +111,8 @@ public: void UnregisterHandler(uint32_t id); protected: + void SetRenderingQueue(VkQueue queue); + void RecreateSwapchain(); void DestroySwapchain(); @@ -125,6 +129,9 @@ protected: void RecreateDepthTexture(); + void RecreateSwapchainAndDependencies(); + void ResetSwapchainAndDependencies(); + struct AttachmentOp { VkAttachmentLoadOp m_loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; @@ -198,6 +205,7 @@ protected: std::vector m_paramDescriptors; drape_ptr m_defaultStagingBuffer; + std::atomic m_presentAvailable; }; } // namespace vulkan } // namespace dp diff --git a/drape/vulkan/vulkan_mesh_object_impl.cpp b/drape/vulkan/vulkan_mesh_object_impl.cpp index f02baf9b10..67187c0186 100644 --- a/drape/vulkan/vulkan_mesh_object_impl.cpp +++ b/drape/vulkan/vulkan_mesh_object_impl.cpp @@ -84,9 +84,10 @@ public: void ResetCache(dp::RenderState const & state) override { - if (state.GetColorTexture() != m_lastColorTexture) + auto newTex = state.GetColorTexture()->GetHardwareTexture(); + if (newTex != m_lastColorTexture) { - m_lastColorTexture = state.GetColorTexture(); + m_lastColorTexture = newTex; ResetDescriptorSetGroup(); } } @@ -199,7 +200,7 @@ private: BindingInfoArray m_bindingInfo; uint8_t m_bindingInfoCount = 0; DescriptorSetGroup m_descriptorSetGroup; - ref_ptr m_lastColorTexture; + ref_ptr m_lastColorTexture; }; } // namespace vulkan diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index b66108494c..2d26e0374f 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -1115,7 +1115,7 @@ void FrontendRenderer::OnResize(ScreenBase const & screen) m_viewport.SetViewport(0, 0, sx, sy); } - if (viewportChanged || m_needRestoreSize) + if (viewportChanged || m_needRestoreSize || m_apiVersion == dp::ApiVersion::Vulkan) { CHECK(m_context != nullptr, ()); m_context->Resize(sx, sy); @@ -1595,7 +1595,8 @@ void FrontendRenderer::RenderEmptyFrame() if (!m_context->Validate()) return; - m_context->BeginRendering(); + if (!m_context->BeginRendering()) + return; m_context->SetFramebuffer(nullptr /* default */); auto const c = dp::Extract(drule::rules().GetBgColor(1 /* scale */), 255); @@ -1622,7 +1623,8 @@ void FrontendRenderer::RenderFrame() auto & scaleFpsHelper = gui::DrapeGui::Instance().GetScaleFpsHelper(); m_frameData.m_timer.Reset(); - m_context->BeginRendering(); + if (!m_context->BeginRendering()) + return; ScreenBase modelView = ProcessEvents(m_frameData.m_modelViewChanged, m_frameData.m_viewportChanged); if (m_frameData.m_viewportChanged)