android: renderer_vulkan: Fix crash with surface recreation.
This commit is contained in:
		| @@ -148,6 +148,7 @@ public: | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         m_window->OnSurfaceChanged(m_native_window); |         m_window->OnSurfaceChanged(m_native_window); | ||||||
|  |         m_system.Renderer().NotifySurfaceChanged(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     Core::SystemResultStatus InitializeEmulation(const std::string& filepath) { |     Core::SystemResultStatus InitializeEmulation(const std::string& filepath) { | ||||||
|   | |||||||
| @@ -89,6 +89,9 @@ public: | |||||||
|     void RequestScreenshot(void* data, std::function<void(bool)> callback, |     void RequestScreenshot(void* data, std::function<void(bool)> callback, | ||||||
|                            const Layout::FramebufferLayout& layout); |                            const Layout::FramebufferLayout& layout); | ||||||
|  |  | ||||||
|  |     /// This is called to notify the rendering backend of a surface change | ||||||
|  |     virtual void NotifySurfaceChanged() {} | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|     Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle. |     Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle. | ||||||
|     std::unique_ptr<Core::Frontend::GraphicsContext> context; |     std::unique_ptr<Core::Frontend::GraphicsContext> context; | ||||||
|   | |||||||
| @@ -54,6 +54,10 @@ public: | |||||||
|         return device.GetDriverName(); |         return device.GetDriverName(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     void NotifySurfaceChanged() override { | ||||||
|  |         present_manager.NotifySurfaceChanged(); | ||||||
|  |     } | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     void Report() const; |     void Report() const; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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) { | void PresentManager::CopyToSwapchain(Frame* frame) { | ||||||
|     MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain); |     MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain); | ||||||
|  |  | ||||||
| @@ -299,7 +306,22 @@ void PresentManager::CopyToSwapchain(Frame* frame) { | |||||||
|         image_count = swapchain.GetImageCount(); |         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 | #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 the frontend recreated the surface, recreate the renderer surface and swapchain. | ||||||
|     if (last_render_surface != render_window.GetWindowInfo().render_surface) { |     if (last_render_surface != render_window.GetWindowInfo().render_surface) { | ||||||
|         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 |     // 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 = |         switch (const VkResult result = | ||||||
|                     device.GetGraphicsQueue().Submit(submit_info, *frame->present_done)) { |                     device.GetGraphicsQueue().Submit(submit_info, *frame->present_done)) { | ||||||
|         case VK_SUCCESS: |         case VK_SUCCESS: | ||||||
|   | |||||||
| @@ -55,6 +55,9 @@ public: | |||||||
|     /// Waits for the present thread to finish presenting all queued frames. |     /// Waits for the present thread to finish presenting all queued frames. | ||||||
|     void WaitPresent(); |     void WaitPresent(); | ||||||
|  |  | ||||||
|  |     /// This is called to notify the rendering backend of a surface change | ||||||
|  |     void NotifySurfaceChanged(); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     void PresentThread(std::stop_token token); |     void PresentThread(std::stop_token token); | ||||||
|  |  | ||||||
| @@ -74,7 +77,9 @@ private: | |||||||
|     std::queue<Frame*> free_queue; |     std::queue<Frame*> free_queue; | ||||||
|     std::condition_variable_any frame_cv; |     std::condition_variable_any frame_cv; | ||||||
|     std::condition_variable free_cv; |     std::condition_variable free_cv; | ||||||
|  |     std::condition_variable recreate_surface_cv; | ||||||
|     std::mutex swapchain_mutex; |     std::mutex swapchain_mutex; | ||||||
|  |     std::mutex recreate_surface_mutex; | ||||||
|     std::mutex queue_mutex; |     std::mutex queue_mutex; | ||||||
|     std::mutex free_mutex; |     std::mutex free_mutex; | ||||||
|     std::jthread present_thread; |     std::jthread present_thread; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user