Merge pull request #11656 from liamwhite/recreate-surface-automatically

vk_present_manager: recreate surface on any surface loss
This commit is contained in:
liamwhite 2023-10-07 12:49:54 -04:00 committed by GitHub
commit bd42bba71c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 33 additions and 49 deletions

View File

@ -218,7 +218,6 @@ public:
return; return;
} }
m_window->OnSurfaceChanged(m_native_window); m_window->OnSurfaceChanged(m_native_window);
m_system.Renderer().NotifySurfaceChanged();
} }
void ConfigureFilesystemProvider(const std::string& filepath) { void ConfigureFilesystemProvider(const std::string& filepath) {

View File

@ -89,9 +89,6 @@ 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;

View File

@ -56,10 +56,6 @@ public:
return device.GetDriverName(); return device.GetDriverName();
} }
void NotifySurfaceChanged() override {
present_manager.NotifySurfaceChanged();
}
private: private:
void Report() const; void Report() const;

View File

@ -103,8 +103,7 @@ PresentManager::PresentManager(const vk::Instance& instance_,
surface{surface_}, blit_supported{CanBlitToSwapchain(device.GetPhysical(), surface{surface_}, blit_supported{CanBlitToSwapchain(device.GetPhysical(),
swapchain.GetImageViewFormat())}, swapchain.GetImageViewFormat())},
use_present_thread{Settings::values.async_presentation.GetValue()}, use_present_thread{Settings::values.async_presentation.GetValue()},
image_count{swapchain.GetImageCount()}, last_render_surface{ image_count{swapchain.GetImageCount()} {
render_window_.GetWindowInfo().render_surface} {
auto& dld = device.GetLogical(); auto& dld = device.GetLogical();
cmdpool = dld.CreateCommandPool({ cmdpool = dld.CreateCommandPool({
@ -289,44 +288,36 @@ void PresentManager::PresentThread(std::stop_token token) {
} }
} }
void PresentManager::NotifySurfaceChanged() { void PresentManager::RecreateSwapchain(Frame* frame) {
#ifdef ANDROID swapchain.Create(*surface, frame->width, frame->height, frame->is_srgb);
std::scoped_lock lock{recreate_surface_mutex}; image_count = swapchain.GetImageCount();
recreate_surface_cv.notify_one();
#endif
} }
void PresentManager::CopyToSwapchain(Frame* frame) { void PresentManager::CopyToSwapchain(Frame* frame) {
MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain); bool requires_recreation = false;
const auto recreate_swapchain = [&] { while (true) {
swapchain.Create(*surface, frame->width, frame->height, frame->is_srgb); try {
image_count = swapchain.GetImageCount(); // Recreate surface and swapchain if needed.
}; if (requires_recreation) {
surface = CreateSurface(instance, render_window.GetWindowInfo());
RecreateSwapchain(frame);
}
#ifdef ANDROID // Draw to swapchain.
std::unique_lock lock{recreate_surface_mutex}; return CopyToSwapchainImpl(frame);
} catch (const vk::Exception& except) {
if (except.GetResult() != VK_ERROR_SURFACE_LOST_KHR) {
throw;
}
const auto needs_recreation = [&] { requires_recreation = true;
if (last_render_surface != render_window.GetWindowInfo().render_surface) {
return 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 // If the size or colorspace of the incoming frames has changed, recreate the swapchain
// to account for that. // to account for that.
@ -334,11 +325,11 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
const bool size_changed = const bool size_changed =
swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height; swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height;
if (srgb_changed || size_changed) { if (srgb_changed || size_changed) {
recreate_swapchain(); RecreateSwapchain(frame);
} }
while (swapchain.AcquireNextImage()) { while (swapchain.AcquireNextImage()) {
recreate_swapchain(); RecreateSwapchain(frame);
} }
const vk::CommandBuffer cmdbuf{frame->cmdbuf}; const vk::CommandBuffer cmdbuf{frame->cmdbuf};

View File

@ -54,14 +54,15 @@ 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);
void CopyToSwapchain(Frame* frame); void CopyToSwapchain(Frame* frame);
void CopyToSwapchainImpl(Frame* frame);
void RecreateSwapchain(Frame* frame);
private: private:
const vk::Instance& instance; const vk::Instance& instance;
Core::Frontend::EmuWindow& render_window; Core::Frontend::EmuWindow& render_window;
@ -76,16 +77,13 @@ 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;
bool blit_supported; bool blit_supported;
bool use_present_thread; bool use_present_thread;
std::size_t image_count{}; std::size_t image_count{};
void* last_render_surface{};
}; };
} // namespace Vulkan } // namespace Vulkan

View File

@ -117,6 +117,9 @@ public:
virtual ~Exception() = default; virtual ~Exception() = default;
const char* what() const noexcept override; const char* what() const noexcept override;
VkResult GetResult() const noexcept {
return result;
}
private: private:
VkResult result; VkResult result;