From b7fe08519f75c6e1aa3081db804bea9edfe6fcec Mon Sep 17 00:00:00 2001
From: "Daniel R." <47796739+polybiusproxy@users.noreply.github.com>
Date: Thu, 31 Oct 2024 16:53:03 +0100
Subject: [PATCH] core/gnmdriver: Proper interrupt registering (#1218)

---
 .gitignore                                 | 16 ++++----
 src/core/libraries/gnmdriver/gnmdriver.cpp | 10 ++---
 src/core/platform.h                        | 44 ++++++++++++----------
 3 files changed, 38 insertions(+), 32 deletions(-)

diff --git a/.gitignore b/.gitignore
index 9abc4aae..61d9e32e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -382,13 +382,13 @@ FodyWeavers.xsd
 
 # VS Code files for those working on multiple tools
 .vscode/*
-!.vscode/settings.json
-!.vscode/tasks.json
-!.vscode/launch.json
-!.vscode/extensions.json
+.vscode/settings.json
+.vscode/tasks.json
+.vscode/launch.json
+.vscode/extensions.json
 *.code-workspace
-/CMakeUserPresets.json
-/compile_commands.json
+/CMakeUserPresets.json
+/compile_commands.json
 
 # Local History for Visual Studio Code
 .history/
@@ -411,6 +411,6 @@ FodyWeavers.xsd
 /out/*
 /third-party/out/*
 /src/common/scm_rev.cpp
-
+
 # for macOS
-**/.DS_Store
+**/.DS_Store
diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp
index 4d8aa881..08f534c7 100644
--- a/src/core/libraries/gnmdriver/gnmdriver.cpp
+++ b/src/core/libraries/gnmdriver/gnmdriver.cpp
@@ -359,12 +359,13 @@ s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) {
     eq->AddEvent(kernel_event);
 
     Platform::IrqC::Instance()->Register(
-        Platform::InterruptId::GfxEop,
+        static_cast<Platform::InterruptId>(id),
         [=](Platform::InterruptId irq) {
-            ASSERT_MSG(irq == Platform::InterruptId::GfxEop,
+            ASSERT_MSG(irq == static_cast<Platform::InterruptId>(id),
                        "An unexpected IRQ occured"); // We need to convert IRQ# to event id and do
                                                      // proper filtering in trigger function
-            eq->TriggerEvent(GnmEventIdents::GfxEop, SceKernelEvent::Filter::GraphicsCore, nullptr);
+            eq->TriggerEvent(static_cast<GnmEventIdents>(id), SceKernelEvent::Filter::GraphicsCore,
+                             nullptr);
         },
         eq);
     return ORBIS_OK;
@@ -468,7 +469,6 @@ int PS4_SYSV_ABI sceGnmDebugHardwareStatus() {
 
 s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(SceKernelEqueue eq, u64 id) {
     LOG_TRACE(Lib_GnmDriver, "called");
-    ASSERT_MSG(id == GnmEventIdents::GfxEop);
 
     if (!eq) {
         return ORBIS_KERNEL_ERROR_EBADF;
@@ -476,7 +476,7 @@ s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(SceKernelEqueue eq, u64 id) {
 
     eq->RemoveEvent(id);
 
-    Platform::IrqC::Instance()->Unregister(Platform::InterruptId::GfxEop, eq);
+    Platform::IrqC::Instance()->Unregister(static_cast<Platform::InterruptId>(id), eq);
     return ORBIS_OK;
 }
 
diff --git a/src/core/platform.h b/src/core/platform.h
index 2c38dfd3..03bd79e8 100644
--- a/src/core/platform.h
+++ b/src/core/platform.h
@@ -17,31 +17,35 @@
 namespace Platform {
 
 enum class InterruptId : u32 {
-    Compute0RelMem = 0u,
-    Compute1RelMem = 1u,
-    Compute2RelMem = 2u,
-    Compute3RelMem = 3u,
-    Compute4RelMem = 4u,
-    Compute5RelMem = 5u,
-    Compute6RelMem = 6u,
-    GfxEop = 7u,
-    GfxFlip = 8u,
-    GpuIdle = 9u,
+    Compute0RelMem = 0x00,
+    Compute1RelMem = 0x01,
+    Compute2RelMem = 0x02,
+    Compute3RelMem = 0x03,
+    Compute4RelMem = 0x04,
+    Compute5RelMem = 0x05,
+    Compute6RelMem = 0x06,
+    GfxEop = 0x40,
+    GfxFlip = 0x08,
+    GpuIdle = 0x09,
+
+    InterruptIdMax = 0x40, ///< Max possible value (GfxEop)
 };
 
 using IrqHandler = std::function<void(InterruptId)>;
 
 struct IrqController {
     void RegisterOnce(InterruptId irq, IrqHandler handler) {
-        ASSERT_MSG(static_cast<u32>(irq) < irq_contexts.size(), "Invalid IRQ number");
-        auto& ctx = irq_contexts[static_cast<u32>(irq)];
+        ASSERT_MSG(static_cast<u32>(irq) <= static_cast<u32>(InterruptId::InterruptIdMax),
+                   "Invalid IRQ number");
+        auto& ctx = irq_contexts.try_emplace(irq).first->second;
         std::unique_lock lock{ctx.m_lock};
         ctx.one_time_subscribers.emplace(handler);
     }
 
     void Register(InterruptId irq, IrqHandler handler, void* uid) {
-        ASSERT_MSG(static_cast<u32>(irq) < irq_contexts.size(), "Invalid IRQ number");
-        auto& ctx = irq_contexts[static_cast<u32>(irq)];
+        ASSERT_MSG(static_cast<u32>(irq) <= static_cast<u32>(InterruptId::InterruptIdMax),
+                   "Invalid IRQ number");
+        auto& ctx = irq_contexts.try_emplace(irq).first->second;
 
         std::unique_lock lock{ctx.m_lock};
         ASSERT_MSG(ctx.persistent_handlers.find(uid) == ctx.persistent_handlers.cend(),
@@ -50,15 +54,17 @@ struct IrqController {
     }
 
     void Unregister(InterruptId irq, void* uid) {
-        ASSERT_MSG(static_cast<u32>(irq) < irq_contexts.size(), "Invalid IRQ number");
-        auto& ctx = irq_contexts[static_cast<u32>(irq)];
+        ASSERT_MSG(static_cast<u32>(irq) <= static_cast<u32>(InterruptId::InterruptIdMax),
+                   "Invalid IRQ number");
+        auto& ctx = irq_contexts.try_emplace(irq).first->second;
         std::unique_lock lock{ctx.m_lock};
         ctx.persistent_handlers.erase(uid);
     }
 
     void Signal(InterruptId irq) {
-        ASSERT_MSG(static_cast<u32>(irq) < irq_contexts.size(), "Unexpected IRQ signaled");
-        auto& ctx = irq_contexts[static_cast<u32>(irq)];
+        ASSERT_MSG(static_cast<u32>(irq) <= static_cast<u32>(InterruptId::InterruptIdMax),
+                   "Unexpected IRQ signaled");
+        auto& ctx = irq_contexts.try_emplace(irq).first->second;
         std::unique_lock lock{ctx.m_lock};
 
         LOG_TRACE(Core, "IRQ signaled: {}", magic_enum::enum_name(irq));
@@ -81,7 +87,7 @@ private:
         std::queue<IrqHandler> one_time_subscribers{};
         std::mutex m_lock{};
     };
-    std::array<IrqContext, magic_enum::enum_count<InterruptId>()> irq_contexts{};
+    std::unordered_map<InterruptId, IrqContext> irq_contexts{};
 };
 
 using IrqC = Common::Singleton<IrqController>;