From 6069fac76de008a452cf6012abaf41704bc644a6 Mon Sep 17 00:00:00 2001
From: Steveice10 <1269164+Steveice10@users.noreply.github.com>
Date: Sun, 7 Jan 2024 10:29:43 -0800
Subject: [PATCH] video_core: Fix crash when no debug context is provided.
 (#7324)

---
 src/video_core/gpu.cpp            | 16 +++++++++-----
 src/video_core/pica/pica_core.cpp | 35 ++++++++++++++++++++-----------
 src/video_core/pica/pica_core.h   |  4 ++--
 3 files changed, 36 insertions(+), 19 deletions(-)

diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 3def26757..cc06078b9 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -29,7 +29,7 @@ struct GPU::Impl {
     Core::Timing& timing;
     Core::System& system;
     Memory::MemorySystem& memory;
-    Pica::DebugContext& debug_context;
+    std::shared_ptr<Pica::DebugContext> debug_context;
     Pica::PicaCore pica;
     GraphicsDebugger gpu_debugger;
     std::unique_ptr<RendererBase> renderer;
@@ -41,7 +41,7 @@ struct GPU::Impl {
     explicit Impl(Core::System& system, Frontend::EmuWindow& emu_window,
                   Frontend::EmuWindow* secondary_window)
         : timing{system.CoreTiming()}, system{system}, memory{system.Memory()},
-          debug_context{*Pica::g_debug_context}, pica{memory, debug_context},
+          debug_context{Pica::g_debug_context}, pica{memory, debug_context},
           renderer{VideoCore::CreateRenderer(emu_window, secondary_window, pica, system)},
           rasterizer{renderer->Rasterizer()}, sw_blitter{std::make_unique<SwRenderer::SwBlitter>(
                                                   memory, rasterizer)} {}
@@ -201,7 +201,9 @@ void GPU::Execute(const Service::GSP::Command& command) {
     }
 
     // Notify debugger that a GSP command was processed.
-    impl->debug_context.OnEvent(Pica::DebugContext::Event::GSPCommandProcessed, &command);
+    if (impl->debug_context) {
+        impl->debug_context->OnEvent(Pica::DebugContext::Event::GSPCommandProcessed, &command);
+    }
 }
 
 void GPU::SetBufferSwap(u32 screen_id, const Service::GSP::FrameBufferInfo& info) {
@@ -223,7 +225,9 @@ void GPU::SetBufferSwap(u32 screen_id, const Service::GSP::FrameBufferInfo& info
     framebuffer.active_fb = info.shown_fb;
 
     // Notify debugger about the buffer swap.
-    impl->debug_context.OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr);
+    if (impl->debug_context) {
+        impl->debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr);
+    }
 
     if (screen_id == 0) {
         MicroProfileFlip();
@@ -382,7 +386,9 @@ void GPU::MemoryTransfer() {
     MICROPROFILE_SCOPE(GPU_DisplayTransfer);
 
     // Notify debugger about the display transfer.
-    impl->debug_context.OnEvent(Pica::DebugContext::Event::IncomingDisplayTransfer, nullptr);
+    if (impl->debug_context) {
+        impl->debug_context->OnEvent(Pica::DebugContext::Event::IncomingDisplayTransfer, nullptr);
+    }
 
     // Perform memory transfer
     if (config.is_texture_copy) {
diff --git a/src/video_core/pica/pica_core.cpp b/src/video_core/pica/pica_core.cpp
index 1d7594a2a..9c3fadde8 100644
--- a/src/video_core/pica/pica_core.cpp
+++ b/src/video_core/pica/pica_core.cpp
@@ -30,9 +30,10 @@ union CommandHeader {
 };
 static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!");
 
-PicaCore::PicaCore(Memory::MemorySystem& memory_, DebugContext& debug_context_)
-    : memory{memory_}, debug_context{debug_context_}, geometry_pipeline{regs.internal, gs_unit,
-                                                                        gs_setup},
+PicaCore::PicaCore(Memory::MemorySystem& memory_, std::shared_ptr<DebugContext> debug_context_)
+    : memory{memory_}, debug_context{std::move(debug_context_)}, geometry_pipeline{regs.internal,
+                                                                                   gs_unit,
+                                                                                   gs_setup},
       shader_engine{CreateEngine(Settings::values.use_shader_jit.GetValue())} {
     SetFramebufferDefaults();
 
@@ -138,8 +139,10 @@ void PicaCore::WriteInternalReg(u32 id, u32 value, u32 mask) {
     DebugUtils::OnPicaRegWrite(id, mask, regs.internal.reg_array[id]);
 
     // Track events.
-    debug_context.OnEvent(DebugContext::Event::PicaCommandLoaded, &id);
-    SCOPE_EXIT({ debug_context.OnEvent(DebugContext::Event::PicaCommandProcessed, &id); });
+    if (debug_context) {
+        debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded, &id);
+        SCOPE_EXIT({ debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, &id); });
+    }
 
     switch (id) {
     // Trigger IRQ
@@ -427,9 +430,12 @@ void PicaCore::DrawImmediate() {
     shader_engine->SetupBatch(vs_setup, regs.internal.vs.main_offset);
 
     // Track vertex in the debug recorder.
-    debug_context.OnEvent(DebugContext::Event::VertexShaderInvocation,
-                          std::addressof(immediate.input_vertex));
-    SCOPE_EXIT({ debug_context.OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); });
+    if (debug_context) {
+        debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation,
+                               std::addressof(immediate.input_vertex));
+        SCOPE_EXIT(
+            { debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); });
+    }
 
     ShaderUnit shader_unit;
     AttributeBuffer output{};
@@ -459,8 +465,11 @@ void PicaCore::DrawArrays(bool is_indexed) {
     MICROPROFILE_SCOPE(GPU_Drawing);
 
     // Track vertex in the debug recorder.
-    debug_context.OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr);
-    SCOPE_EXIT({ debug_context.OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); });
+    if (debug_context) {
+        debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr);
+        SCOPE_EXIT(
+            { debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); });
+    }
 
     const bool accelerate_draw = [this] {
         // Geometry shaders cannot be accelerated due to register preservation.
@@ -554,8 +563,10 @@ void PicaCore::LoadVertices(bool is_indexed) {
             loader.LoadVertex(base_address, index, vertex, input, input_default_attributes);
 
             // Record vertex processing to the debugger.
-            debug_context.OnEvent(DebugContext::Event::VertexShaderInvocation,
-                                  std::addressof(input));
+            if (debug_context) {
+                debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation,
+                                       std::addressof(input));
+            }
 
             // Invoke the vertex shader for this vertex.
             shader_unit.LoadInput(regs.internal.vs, input);
diff --git a/src/video_core/pica/pica_core.h b/src/video_core/pica/pica_core.h
index bb19a4f25..353945b53 100644
--- a/src/video_core/pica/pica_core.h
+++ b/src/video_core/pica/pica_core.h
@@ -29,7 +29,7 @@ class ShaderEngine;
 
 class PicaCore {
 public:
-    explicit PicaCore(Memory::MemorySystem& memory, DebugContext& debug_context_);
+    explicit PicaCore(Memory::MemorySystem& memory, std::shared_ptr<DebugContext> debug_context_);
     ~PicaCore();
 
     void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
@@ -274,7 +274,7 @@ private:
 private:
     Memory::MemorySystem& memory;
     VideoCore::RasterizerInterface* rasterizer;
-    DebugContext& debug_context;
+    std::shared_ptr<DebugContext> debug_context;
     Service::GSP::InterruptHandler signal_interrupt;
     GeometryPipeline geometry_pipeline;
     PrimitiveAssembler primitive_assembler;