From 098e2c4077f62890f83c0785e858080e9e18296c Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 1 Jun 2023 20:07:18 -0700 Subject: [PATCH] android: renderer_vulkan: Fix crash with surface recreation. --- src/android/app/src/main/jni/native.cpp | 1 + src/video_core/renderer_base.h | 3 +++ .../renderer_vulkan/renderer_vulkan.h | 4 ++++ .../renderer_vulkan/vk_present_manager.cpp | 24 ++++++++++++++++++- .../renderer_vulkan/vk_present_manager.h | 5 ++++ 5 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index d503ef61d..b87e04b3d 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -148,6 +148,7 @@ public: return; } m_window->OnSurfaceChanged(m_native_window); + m_system.Renderer().NotifySurfaceChanged(); } Core::SystemResultStatus InitializeEmulation(const std::string& filepath) { diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 78ea5208b..3e12a8813 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h @@ -89,6 +89,9 @@ public: void RequestScreenshot(void* data, std::function callback, const Layout::FramebufferLayout& layout); + /// This is called to notify the rendering backend of a surface change + virtual void NotifySurfaceChanged() {} + protected: Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle. std::unique_ptr context; diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 3c63a2004..b2e8cbd1b 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -54,6 +54,10 @@ public: return device.GetDriverName(); } + void NotifySurfaceChanged() override { + present_manager.NotifySurfaceChanged(); + } + private: void Report() const; diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index 77832720d..dc42982e9 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp @@ -291,6 +291,13 @@ void PresentManager::PresentThread(std::stop_token token) { } } +void PresentManager::NotifySurfaceChanged() { +#ifdef ANDROID + std::scoped_lock lock{recreate_surface_mutex}; + recreate_surface_cv.notify_one(); +#endif +} + void PresentManager::CopyToSwapchain(Frame* frame) { MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain); @@ -299,7 +306,22 @@ void PresentManager::CopyToSwapchain(Frame* frame) { image_count = swapchain.GetImageCount(); }; + const auto needs_recreation = [&] { + if (last_render_surface != render_window.GetWindowInfo().render_surface) { + return true; + } + if (swapchain.NeedsRecreation(frame->is_srgb)) { + return true; + } + return false; + }; + #ifdef ANDROID + std::unique_lock lock{recreate_surface_mutex}; + + recreate_surface_cv.wait_for(lock, std::chrono::milliseconds(400), + [&]() { return !needs_recreation(); }); + // If the frontend recreated the surface, recreate the renderer surface and swapchain. if (last_render_surface != render_window.GetWindowInfo().render_surface) { last_render_surface = render_window.GetWindowInfo().render_surface; @@ -450,7 +472,7 @@ void PresentManager::CopyToSwapchain(Frame* frame) { // Submit the image copy/blit to the swapchain { - std::scoped_lock lock{scheduler.submit_mutex}; + std::scoped_lock submit_lock{scheduler.submit_mutex}; switch (const VkResult result = device.GetGraphicsQueue().Submit(submit_info, *frame->present_done)) { case VK_SUCCESS: diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h index 3cbfce4ed..4ac2e2395 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.h +++ b/src/video_core/renderer_vulkan/vk_present_manager.h @@ -55,6 +55,9 @@ public: /// Waits for the present thread to finish presenting all queued frames. void WaitPresent(); + /// This is called to notify the rendering backend of a surface change + void NotifySurfaceChanged(); + private: void PresentThread(std::stop_token token); @@ -74,7 +77,9 @@ private: std::queue free_queue; std::condition_variable_any frame_cv; std::condition_variable free_cv; + std::condition_variable recreate_surface_cv; std::mutex swapchain_mutex; + std::mutex recreate_surface_mutex; std::mutex queue_mutex; std::mutex free_mutex; std::jthread present_thread;