mirror of
				https://git.tardis.systems/mirrors/yuzu
				synced 2025-10-31 10:44:49 +01:00 
			
		
		
		
	Merge pull request #11656 from liamwhite/recreate-surface-automatically
vk_present_manager: recreate surface on any surface loss
This commit is contained in:
		
						commit
						bd42bba71c
					
				| @ -218,7 +218,6 @@ public: | ||||
|             return; | ||||
|         } | ||||
|         m_window->OnSurfaceChanged(m_native_window); | ||||
|         m_system.Renderer().NotifySurfaceChanged(); | ||||
|     } | ||||
| 
 | ||||
|     void ConfigureFilesystemProvider(const std::string& filepath) { | ||||
|  | ||||
| @ -89,9 +89,6 @@ public: | ||||
|     void RequestScreenshot(void* data, std::function<void(bool)> 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<Core::Frontend::GraphicsContext> context; | ||||
|  | ||||
| @ -56,10 +56,6 @@ public: | ||||
|         return device.GetDriverName(); | ||||
|     } | ||||
| 
 | ||||
|     void NotifySurfaceChanged() override { | ||||
|         present_manager.NotifySurfaceChanged(); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     void Report() const; | ||||
| 
 | ||||
|  | ||||
| @ -103,8 +103,7 @@ PresentManager::PresentManager(const vk::Instance& instance_, | ||||
|       surface{surface_}, blit_supported{CanBlitToSwapchain(device.GetPhysical(), | ||||
|                                                            swapchain.GetImageViewFormat())}, | ||||
|       use_present_thread{Settings::values.async_presentation.GetValue()}, | ||||
|       image_count{swapchain.GetImageCount()}, last_render_surface{ | ||||
|                                                   render_window_.GetWindowInfo().render_surface} { | ||||
|       image_count{swapchain.GetImageCount()} { | ||||
| 
 | ||||
|     auto& dld = device.GetLogical(); | ||||
|     cmdpool = dld.CreateCommandPool({ | ||||
| @ -289,44 +288,36 @@ 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::RecreateSwapchain(Frame* frame) { | ||||
|     swapchain.Create(*surface, frame->width, frame->height, frame->is_srgb); | ||||
|     image_count = swapchain.GetImageCount(); | ||||
| } | ||||
| 
 | ||||
| void PresentManager::CopyToSwapchain(Frame* frame) { | ||||
|     MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain); | ||||
|     bool requires_recreation = false; | ||||
| 
 | ||||
|     const auto recreate_swapchain = [&] { | ||||
|         swapchain.Create(*surface, frame->width, frame->height, frame->is_srgb); | ||||
|         image_count = swapchain.GetImageCount(); | ||||
|     }; | ||||
|     while (true) { | ||||
|         try { | ||||
|             // Recreate surface and swapchain if needed.
 | ||||
|             if (requires_recreation) { | ||||
|                 surface = CreateSurface(instance, render_window.GetWindowInfo()); | ||||
|                 RecreateSwapchain(frame); | ||||
|             } | ||||
| 
 | ||||
| #ifdef ANDROID | ||||
|     std::unique_lock lock{recreate_surface_mutex}; | ||||
|             // Draw to swapchain.
 | ||||
|             return CopyToSwapchainImpl(frame); | ||||
|         } catch (const vk::Exception& except) { | ||||
|             if (except.GetResult() != VK_ERROR_SURFACE_LOST_KHR) { | ||||
|                 throw; | ||||
|             } | ||||
| 
 | ||||
|     const auto needs_recreation = [&] { | ||||
|         if (last_render_surface != render_window.GetWindowInfo().render_surface) { | ||||
|             return true; | ||||
|             requires_recreation = true; | ||||
|         } | ||||
|         if (swapchain.NeedsRecreation(frame->is_srgb)) { | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     }; | ||||
| 
 | ||||
|     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; | ||||
|         surface = CreateSurface(instance, render_window.GetWindowInfo()); | ||||
|         recreate_swapchain(); | ||||
|     } | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void PresentManager::CopyToSwapchainImpl(Frame* frame) { | ||||
|     MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain); | ||||
| 
 | ||||
|     // If the size or colorspace of the incoming frames has changed, recreate the swapchain
 | ||||
|     // to account for that.
 | ||||
| @ -334,11 +325,11 @@ void PresentManager::CopyToSwapchain(Frame* frame) { | ||||
|     const bool size_changed = | ||||
|         swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height; | ||||
|     if (srgb_changed || size_changed) { | ||||
|         recreate_swapchain(); | ||||
|         RecreateSwapchain(frame); | ||||
|     } | ||||
| 
 | ||||
|     while (swapchain.AcquireNextImage()) { | ||||
|         recreate_swapchain(); | ||||
|         RecreateSwapchain(frame); | ||||
|     } | ||||
| 
 | ||||
|     const vk::CommandBuffer cmdbuf{frame->cmdbuf}; | ||||
| @ -488,4 +479,4 @@ void PresentManager::CopyToSwapchain(Frame* frame) { | ||||
|     swapchain.Present(render_semaphore); | ||||
| } | ||||
| 
 | ||||
| } // namespace Vulkan
 | ||||
| } // namespace Vulkan
 | ||||
|  | ||||
| @ -54,14 +54,15 @@ 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); | ||||
| 
 | ||||
|     void CopyToSwapchain(Frame* frame); | ||||
| 
 | ||||
|     void CopyToSwapchainImpl(Frame* frame); | ||||
| 
 | ||||
|     void RecreateSwapchain(Frame* frame); | ||||
| 
 | ||||
| private: | ||||
|     const vk::Instance& instance; | ||||
|     Core::Frontend::EmuWindow& render_window; | ||||
| @ -76,16 +77,13 @@ private: | ||||
|     std::queue<Frame*> 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; | ||||
|     bool blit_supported; | ||||
|     bool use_present_thread; | ||||
|     std::size_t image_count{}; | ||||
|     void* last_render_surface{}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Vulkan
 | ||||
|  | ||||
| @ -117,6 +117,9 @@ public: | ||||
|     virtual ~Exception() = default; | ||||
| 
 | ||||
|     const char* what() const noexcept override; | ||||
|     VkResult GetResult() const noexcept { | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     VkResult result; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user