From 381f1dd2c993847fdef65b2c9da4c7ec29079553 Mon Sep 17 00:00:00 2001 From: lat9nq Date: Mon, 7 Mar 2022 01:39:16 -0500 Subject: [PATCH 1/3] core: Don't shutdown a null GPU When CreateGPU fails, yuzu would try and shutdown the GPU instance regardless of whether any instance was actually created. Check for nullptr before calling its methods to prevent a crash. --- src/core/core.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index b0cfee3ee0..c60a784c3e 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -326,7 +326,9 @@ struct System::Impl { is_powered_on = false; exit_lock = false; - gpu_core->NotifyShutdown(); + if (gpu_core != nullptr) { + gpu_core->NotifyShutdown(); + } services.reset(); service_manager.reset(); From 1f24a4e520004d48799a27b159432aa0b8634628 Mon Sep 17 00:00:00 2001 From: lat9nq Date: Mon, 7 Mar 2022 03:35:34 -0500 Subject: [PATCH 2/3] emu_window: Create a way to Cancel the exit of a Scoped If a GraphicsContext is destroyed before its Scoped is destroyed, this causes a crash as the Scoped tries to call a method in the destroyed context on exit. Add a way to Cancel the call when we know that calling the GraphicsContext will not work. --- src/core/frontend/emu_window.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index e413a520ab..b3bffecb22 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -42,11 +42,20 @@ public: context.MakeCurrent(); } ~Scoped() { - context.DoneCurrent(); + if (active) { + context.DoneCurrent(); + } + } + + /// In the event that context was destroyed before the Scoped is destroyed, this provides a + /// mechanism to prevent calling a destroyed object's method during the deconstructor + void Cancel() { + active = false; } private: GraphicsContext& context; + bool active{true}; }; /// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value From b5e60ae1b0568d6c9e47134dd2bda70906a2dad9 Mon Sep 17 00:00:00 2001 From: lat9nq Date: Mon, 7 Mar 2022 03:37:54 -0500 Subject: [PATCH 3/3] video_core: Cancel Scoped's exit call on GPU failure When CreateRenderer fails, the GraphicsContext that was std::move'd into it is destroyed before the Scoped that was created to manage its currency. In that case, the GraphicsContext::Scoped will still call its destructor at the ending of the function. And because the context is destroyed, the Scoped will cause a crash as it attempts to call a destroyed object's DoneCurrent function. Since we know when the call would be invalid, call the Scoped's Cancel method. This prevents it from calling a method on a destroyed object. --- src/video_core/video_core.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index 329bf4defd..2f25945858 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -50,6 +50,7 @@ std::unique_ptr CreateGPU(Core::Frontend::EmuWindow& emu_window, Cor gpu->BindRenderer(std::move(renderer)); return gpu; } catch (const std::runtime_error& exception) { + scope.Cancel(); LOG_ERROR(HW_GPU, "Failed to initialize GPU: {}", exception.what()); return nullptr; }