From ffe0632608fecb8b9e53aa6149f3dfa7df342353 Mon Sep 17 00:00:00 2001 From: GPUCode Date: Sat, 6 Apr 2024 03:38:58 +0300 Subject: [PATCH] renderer_vulkan: Address vulkan surface recreation issues --- .../app/src/main/jni/emu_window/emu_window.cpp | 8 ++++++-- .../app/src/main/jni/emu_window/emu_window.h | 2 +- src/android/app/src/main/jni/native.cpp | 5 +++-- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../renderer_vulkan/vk_present_window.cpp | 2 +- src/video_core/renderer_vulkan/vk_swapchain.cpp | 16 ++++++++++------ 6 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp index 436442acd..8e1c40cd7 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp @@ -27,14 +27,18 @@ static void UpdateLandscapeScreenLayout() { IDCache::GetNativeLibraryClass(), IDCache::GetLandscapeScreenLayout())); } -void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { - render_window = surface; +bool EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { + if (render_window == surface) { + return false; + } + render_window = surface; window_info.type = Frontend::WindowSystemType::Android; window_info.render_surface = surface; StopPresenting(); OnFramebufferSizeChanged(); + return true; } bool EmuWindow_Android::OnTouchEvent(int x, int y, bool pressed) { diff --git a/src/android/app/src/main/jni/emu_window/emu_window.h b/src/android/app/src/main/jni/emu_window/emu_window.h index 64ead5c7f..4266fd1bb 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.h +++ b/src/android/app/src/main/jni/emu_window/emu_window.h @@ -17,7 +17,7 @@ public: ~EmuWindow_Android(); /// Called by the onSurfaceChanges() method to change the surface - void OnSurfaceChanged(ANativeWindow* surface); + bool OnSurfaceChanged(ANativeWindow* surface); /// Handles touch event that occur.(Touched or released) bool OnTouchEvent(int x, int y, bool pressed); diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 13dbc0f2c..cb6cd4289 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -288,12 +288,13 @@ void Java_org_citra_citra_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jobject surf) { s_surf = ANativeWindow_fromSurface(env, surf); + bool notify = false; if (window) { - window->OnSurfaceChanged(s_surf); + notify = window->OnSurfaceChanged(s_surf); } auto& system = Core::System::GetInstance(); - if (system.IsPoweredOn()) { + if (notify && system.IsPoweredOn()) { system.GPU().Renderer().NotifySurfaceChanged(); } diff --git a/src/android/gradle/wrapper/gradle-wrapper.properties b/src/android/gradle/wrapper/gradle-wrapper.properties index 10cba3572..03ef85ab3 100644 --- a/src/android/gradle/wrapper/gradle-wrapper.properties +++ b/src/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip diff --git a/src/video_core/renderer_vulkan/vk_present_window.cpp b/src/video_core/renderer_vulkan/vk_present_window.cpp index 273b20e8e..5f096ad4b 100644 --- a/src/video_core/renderer_vulkan/vk_present_window.cpp +++ b/src/video_core/renderer_vulkan/vk_present_window.cpp @@ -473,7 +473,7 @@ void PresentWindow::CopyToSwapchain(Frame* frame) { .pSignalSemaphores = &present_ready, }; - std::scoped_lock submit_lock{scheduler.submit_mutex}; + std::scoped_lock submit_lock{scheduler.submit_mutex, recreate_surface_mutex}; try { graphics_queue.submit(submit_info, frame->present_done); diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 5e725be1e..4fe70bfe0 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -78,9 +78,13 @@ void Swapchain::Create(u32 width_, u32 height_, vk::SurfaceKHR surface_) { } bool Swapchain::AcquireNextImage() { + if (needs_recreation) { + return false; + } + MICROPROFILE_SCOPE(Vulkan_Acquire); - vk::Device device = instance.GetDevice(); - vk::Result result = + const vk::Device device = instance.GetDevice(); + const vk::Result result = device.acquireNextImageKHR(swapchain, std::numeric_limits::max(), image_acquired[frame_index], VK_NULL_HANDLE, &image_index); @@ -102,10 +106,6 @@ bool Swapchain::AcquireNextImage() { } void Swapchain::Present() { - if (needs_recreation) { - return; - } - const vk::PresentInfoKHR present_info = { .waitSemaphoreCount = 1, .pWaitSemaphores = &present_ready[image_index], @@ -119,6 +119,10 @@ void Swapchain::Present() { [[maybe_unused]] vk::Result result = instance.GetPresentQueue().presentKHR(present_info); } catch (vk::OutOfDateKHRError&) { needs_recreation = true; + return; + } catch (vk::SurfaceLostKHRError&) { + needs_recreation = true; + return; } catch (const vk::SystemError& err) { LOG_CRITICAL(Render_Vulkan, "Swapchain presentation failed {}", err.what()); UNREACHABLE();