From 381f1dd2c993847fdef65b2c9da4c7ec29079553 Mon Sep 17 00:00:00 2001
From: lat9nq <lat9nq@gmail.com>
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 b0cfee3ee..c60a784c3 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 <lat9nq@gmail.com>
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 e413a520a..b3bffecb2 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 <lat9nq@gmail.com>
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 329bf4def..2f2594585 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -50,6 +50,7 @@ std::unique_ptr<Tegra::GPU> 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;
     }