From 8d774e7415fac1153d8944baa2cc250cc4831107 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Mon, 18 Apr 2022 21:07:21 +0200
Subject: [PATCH] NvDec: Fix regressions.

---
 .../hle/service/nvdrv/core/syncpoint_manager.cpp |  6 ++++++
 .../hle/service/nvdrv/core/syncpoint_manager.h   |  5 +++++
 .../hle/service/nvdrv/devices/nvhost_gpu.cpp     |  1 +
 .../nvdrv/devices/nvhost_nvdec_common.cpp        | 16 ++++++++++++----
 .../service/nvdrv/devices/nvhost_nvdec_common.h  |  3 +++
 src/core/hle/service/nvdrv/nvdrv.cpp             |  5 ++++-
 6 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp
index b34481b486..fc4ff3c2fa 100644
--- a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp
+++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp
@@ -55,6 +55,12 @@ u32 SyncpointManager::AllocateSyncpoint(bool clientManaged) {
     return ReserveSyncpoint(FindFreeSyncpoint(), clientManaged);
 }
 
+void SyncpointManager::FreeSyncpoint(u32 id) {
+    std::lock_guard lock(reservation_lock);
+    ASSERT(syncpoints.at(id).reserved);
+    syncpoints.at(id).reserved = false;
+}
+
 bool SyncpointManager::IsSyncpointAllocated(u32 id) {
     return (id <= SyncpointCount) && syncpoints[id].reserved;
 }
diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.h b/src/core/hle/service/nvdrv/core/syncpoint_manager.h
index bfc8ba84b0..da456f2062 100644
--- a/src/core/hle/service/nvdrv/core/syncpoint_manager.h
+++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.h
@@ -84,6 +84,11 @@ public:
      */
     u32 UpdateMin(u32 id);
 
+    /**
+     * @brief Frees the usage of a syncpoint.
+     */
+    void FreeSyncpoint(u32 id);
+
     /**
      * @return A fence that will be signalled once this syncpoint hits its maximum value
      */
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index c2cc09993f..908e60191d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -43,6 +43,7 @@ nvhost_gpu::~nvhost_gpu() {
     events_interface.FreeEvent(sm_exception_breakpoint_int_report_event);
     events_interface.FreeEvent(sm_exception_breakpoint_pause_report_event);
     events_interface.FreeEvent(error_notifier_event);
+    syncpoint_manager.FreeSyncpoint(channel_syncpoint);
 }
 
 NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
index 008092dbb3..fe83423d53 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -51,8 +51,12 @@ std::unordered_map<DeviceFD, u32> nvhost_nvdec_common::fd_to_id{};
 nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_,
                                          NvCore::ChannelType channel_type_)
     : nvdevice{system_}, core{core_}, syncpoint_manager{core.GetSyncpointManager()},
-      nvmap{core.GetNvMapFile()}, channel_type{channel_type_} {}
-nvhost_nvdec_common::~nvhost_nvdec_common() = default;
+      nvmap{core.GetNvMapFile()}, channel_type{channel_type_} {
+    channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false);
+}
+nvhost_nvdec_common::~nvhost_nvdec_common() {
+    syncpoint_manager.FreeSyncpoint(channel_syncpoint);
+}
 
 NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
     IoctlSetNvmapFD params{};
@@ -117,8 +121,8 @@ NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::ve
     std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
     LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
 
-    const u32 id{NvCore::SyncpointManager::channel_syncpoints[static_cast<u32>(channel_type)]};
-    params.value = id;
+    // const u32 id{NvCore::SyncpointManager::channel_syncpoints[static_cast<u32>(channel_type)]};
+    params.value = channel_syncpoint;
     std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
 
     return NvResult::Success;
@@ -176,4 +180,8 @@ Kernel::KEvent* nvhost_nvdec_common::QueryEvent(u32 event_id) {
     return nullptr;
 }
 
+void nvhost_nvdec_common::Reset() {
+    fd_to_id.clear();
+}
+
 } // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
index 51bb7c2cb6..4046b0e13f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -24,6 +24,8 @@ public:
                                  NvCore::ChannelType channel_type);
     ~nvhost_nvdec_common() override;
 
+    static void Reset();
+
 protected:
     struct IoctlSetNvmapFD {
         s32_le nvmap_fd{};
@@ -117,6 +119,7 @@ protected:
     Kernel::KEvent* QueryEvent(u32 event_id) override;
 
     static std::unordered_map<DeviceFD, u32> fd_to_id;
+    u32 channel_syncpoint;
     s32_le nvmap_fd{};
     u32_le submit_timeout{};
     NvCore::Container& core;
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 1be51e4018..20bf24ec8c 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -18,6 +18,7 @@
 #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
 #include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
 #include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
+#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
 #include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h"
 #include "core/hle/service/nvdrv/devices/nvhost_vic.h"
 #include "core/hle/service/nvdrv/devices/nvmap.h"
@@ -101,7 +102,9 @@ Module::Module(Core::System& system)
     };
 }
 
-Module::~Module() = default;
+Module::~Module() {
+    Devices::nvhost_nvdec_common::Reset();
+}
 
 NvResult Module::VerifyFD(DeviceFD fd) const {
     if (fd < 0) {