android: More robust surface recreation

This commit is contained in:
GPUCode
2023-08-25 03:33:57 +03:00
parent ff10decc2c
commit a608e33593
4 changed files with 14 additions and 17 deletions

View File

@ -35,6 +35,7 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
window_info.render_surface = surface; window_info.render_surface = surface;
StopPresenting(); StopPresenting();
OnFramebufferSizeChanged();
} }
bool EmuWindow_Android::OnTouchEvent(int x, int y, bool pressed) { bool EmuWindow_Android::OnTouchEvent(int x, int y, bool pressed) {

View File

@ -100,8 +100,8 @@ PresentWindow::PresentWindow(Frontend::EmuWindow& emu_window_, const Instance& i
Scheduler& scheduler_) Scheduler& scheduler_)
: emu_window{emu_window_}, instance{instance_}, scheduler{scheduler_}, : emu_window{emu_window_}, instance{instance_}, scheduler{scheduler_},
surface{CreateSurface(instance.GetInstance(), emu_window)}, surface{CreateSurface(instance.GetInstance(), emu_window)},
swapchain{instance, emu_window.GetFramebufferLayout().width, next_surface{surface}, swapchain{instance, emu_window.GetFramebufferLayout().width,
emu_window.GetFramebufferLayout().height, surface}, emu_window.GetFramebufferLayout().height, surface},
graphics_queue{instance.GetGraphicsQueue()}, present_renderpass{CreateRenderpass()}, graphics_queue{instance.GetGraphicsQueue()}, present_renderpass{CreateRenderpass()},
vsync_enabled{Settings::values.use_vsync_new.GetValue()}, vsync_enabled{Settings::values.use_vsync_new.GetValue()},
blit_supported{ blit_supported{
@ -328,32 +328,26 @@ void PresentWindow::PresentThread(std::stop_token token) {
void PresentWindow::NotifySurfaceChanged() { void PresentWindow::NotifySurfaceChanged() {
#ifdef ANDROID #ifdef ANDROID
std::scoped_lock lock{recreate_surface_mutex}; std::scoped_lock lock{recreate_surface_mutex};
next_surface = CreateSurface(instance.GetInstance(), emu_window);
recreate_surface_cv.notify_one(); recreate_surface_cv.notify_one();
#endif #endif
} }
void PresentWindow::CopyToSwapchain(Frame* frame) { void PresentWindow::CopyToSwapchain(Frame* frame) {
const auto recreate_swapchain = [&] { const auto recreate_swapchain = [&] {
#ifdef ANDROID
{
std::unique_lock lock{recreate_surface_mutex};
recreate_surface_cv.wait(lock, [this]() { return surface != next_surface; });
surface = next_surface;
}
#endif
std::scoped_lock submit_lock{scheduler.submit_mutex}; std::scoped_lock submit_lock{scheduler.submit_mutex};
graphics_queue.waitIdle(); graphics_queue.waitIdle();
swapchain.Create(frame->width, frame->height, surface); swapchain.Create(frame->width, frame->height, surface);
}; };
#ifdef ANDROID #ifndef ANDROID
std::unique_lock lock{recreate_surface_mutex};
recreate_surface_cv.wait_for(lock, std::chrono::milliseconds(400), [&]() {
return last_render_surface == emu_window.GetWindowInfo().render_surface;
});
// If the frontend recreated the surface, recreate the renderer surface and swapchain.
void* const render_surface = emu_window.GetWindowInfo().render_surface;
if (last_render_surface != render_surface) {
last_render_surface = render_surface;
surface = CreateSurface(instance.GetInstance(), emu_window);
recreate_swapchain();
}
#else
const bool use_vsync = Settings::values.use_vsync_new.GetValue(); const bool use_vsync = Settings::values.use_vsync_new.GetValue();
const bool size_changed = const bool size_changed =
swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height; swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height;

View File

@ -75,6 +75,7 @@ private:
const Instance& instance; const Instance& instance;
Scheduler& scheduler; Scheduler& scheduler;
vk::SurfaceKHR surface; vk::SurfaceKHR surface;
vk::SurfaceKHR next_surface{};
Swapchain swapchain; Swapchain swapchain;
vk::CommandPool command_pool; vk::CommandPool command_pool;
vk::Queue graphics_queue; vk::Queue graphics_queue;

View File

@ -88,6 +88,7 @@ bool Swapchain::AcquireNextImage() {
case vk::Result::eSuccess: case vk::Result::eSuccess:
break; break;
case vk::Result::eSuboptimalKHR: case vk::Result::eSuboptimalKHR:
case vk::Result::eErrorSurfaceLostKHR:
case vk::Result::eErrorOutOfDateKHR: case vk::Result::eErrorOutOfDateKHR:
needs_recreation = true; needs_recreation = true;
break; break;