android: renderer_vulkan: Fix crash with surface recreation.

This commit is contained in:
bunnei 2023-06-01 20:07:18 -07:00
parent 057117f009
commit 098e2c4077
5 changed files with 36 additions and 1 deletions

View file

@ -148,6 +148,7 @@ public:
return;
}
m_window->OnSurfaceChanged(m_native_window);
m_system.Renderer().NotifySurfaceChanged();
}
Core::SystemResultStatus InitializeEmulation(const std::string& filepath) {

View file

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

View file

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

View file

@ -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:

View file

@ -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<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;