From e9650f1c6197baa7e532559964f42578bdde42d5 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Mon, 5 Jan 2015 00:19:28 -0500
Subject: [PATCH] DSP: Signal (faked) interrupt on every frame.

- Hack to work around games checking that the DSP event has been signaled by a real DSP interrupt.
---
 src/core/hle/service/dsp_dsp.cpp | 22 ++++++++++++++++++----
 src/core/hle/service/dsp_dsp.h   |  3 +++
 src/core/hw/gpu.cpp              |  8 +++++++-
 3 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index 2cf4d118f9..d4affdfbf5 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -12,9 +12,23 @@
 
 namespace DSP_DSP {
 
-static u32 read_pipe_count;
-static Handle semaphore_event;
-static Handle interrupt_event;
+static u32 read_pipe_count    = 0;
+static Handle semaphore_event = 0;
+static Handle interrupt_event = 0;
+
+void SignalInterrupt() {
+    // TODO(bunnei): This is just a stub, it does not do anything other than signal to the emulated
+    // application that a DSP interrupt occurred, without specifying which one. Since we do not
+    // emulate the DSP yet (and how it works is largely unknown), this is a work around to get games
+    // that check the DSP interrupt signal event to run. We should figure out the different types of
+    // DSP interrupts, and trigger them at the appropriate times.
+
+    if (interrupt_event == 0) {
+        LOG_WARNING(Service_DSP, "cannot signal interrupt until DSP event has been created!");
+        return;
+    }
+    Kernel::SignalEvent(interrupt_event);
+}
 
 /**
  * DSP_DSP::ConvertProcessAddressFromDspDram service function
@@ -102,7 +116,7 @@ void RegisterInterruptEvents(Service::Interface* self) {
 void WriteReg0x10(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
 
-    Kernel::SignalEvent(interrupt_event);
+    SignalInterrupt();
 
     cmd_buff[1] = 0; // No error
 
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
index 0b8b64600a..fa13bfb7c9 100644
--- a/src/core/hle/service/dsp_dsp.h
+++ b/src/core/hle/service/dsp_dsp.h
@@ -20,4 +20,7 @@ public:
     }
 };
 
+/// Signals that a DSP interrupt has occurred to userland code
+void SignalInterrupt();
+
 } // namespace
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 0ff6c6cde1..e346e0ad6f 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -10,6 +10,7 @@
 
 #include "core/hle/hle.h"
 #include "core/hle/service/gsp_gpu.h"
+#include "core/hle/service/dsp_dsp.h"
 
 #include "core/hw/gpu.h"
 
@@ -214,13 +215,18 @@ void Update() {
             //  - If frameskip == 0 (disabled), always swap buffers
             //  - If frameskip == 1, swap buffers every other frame (starting from the first frame)
             //  - If frameskip > 1, swap buffers every frameskip^n frames (starting from the second frame)
-
             if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) || 
                    Settings::values.frame_skip == 0) {
                 VideoCore::g_renderer->SwapBuffers();
             }
 
+            // Signal to GSP that GPU interrupt has occurred
             GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1);
+
+            // TODO(bunnei): Fake a DSP interrupt on each frame. This does not belong here, but
+            // until we can emulate DSP interrupts, this is probably the only reasonable place to do
+            // this. Certain games expect this to be periodically signaled.
+            DSP_DSP::SignalInterrupt();
         }
     }
 }