From cbc896c8f8230a92cffbfdf1c57017b245a0cdb6 Mon Sep 17 00:00:00 2001 From: lynxnb Date: Thu, 14 Jul 2022 20:01:48 +0200 Subject: [PATCH] Fix `waitForFences` crash on Mali drivers Mali GPU drivers utilize the `ppoll()` syscall inside `waitForFences` which isn't correctly restarted after a signal, which we can receive at any time on a guest thread. This commit fixes that by recursively calling the function on failure till it succeeds or returns an unexpected error. Co-authored-by: PixelyIon Co-authored-by: Billy Laws --- app/src/main/cpp/skyline/gpu/fence_cycle.h | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu/fence_cycle.h b/app/src/main/cpp/skyline/gpu/fence_cycle.h index 70148fc1..70933016 100644 --- a/app/src/main/cpp/skyline/gpu/fence_cycle.h +++ b/app/src/main/cpp/skyline/gpu/fence_cycle.h @@ -68,7 +68,20 @@ namespace skyline::gpu { void Wait() { if (signalled.test(std::memory_order_consume)) return; - while (device.waitForFences(fence, false, std::numeric_limits::max()) != vk::Result::eSuccess); + + vk::Result waitResult; + while ((waitResult = (*device).waitForFences(1, &fence, false, std::numeric_limits::max(), *device.getDispatcher())) != vk::Result::eSuccess) { + if (waitResult == vk::Result::eTimeout) + // Retry if the waiting time out + continue; + + if (waitResult == vk::Result::eErrorInitializationFailed) + // eErrorInitializationFailed occurs on Mali GPU drivers due to them using the ppoll() syscall which isn't correctly restarted after a signal, we need to manually retry waiting in that case + continue; + + throw exception("An error occurred while waiting for fence 0x{:X}: {}", static_cast(fence), vk::to_string(waitResult)); + } + if (!signalled.test_and_set(std::memory_order_release)) DestroyDependencies(); } @@ -80,7 +93,7 @@ namespace skyline::gpu { bool Wait(std::chrono::duration timeout) { if (signalled.test(std::memory_order_consume)) return true; - if (device.waitForFences(fence, false, timeout.count()) == vk::Result::eSuccess) { + if ((*device).waitForFences(1, &fence, false, std::numeric_limits::max(), *device.getDispatcher()) == vk::Result::eSuccess) { if (!signalled.test_and_set(std::memory_order_release)) DestroyDependencies(); return true; @@ -144,8 +157,8 @@ namespace skyline::gpu { } } - auto& dependency{*dependencies.begin()}; - auto& lastDependency{*std::prev(dependencies.end())}; + auto &dependency{*dependencies.begin()}; + auto &lastDependency{*std::prev(dependencies.end())}; lastDependency->next = std::atomic_load_explicit(&list, std::memory_order_acquire); do {