diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/core.cpp | 31 | ||||
| -rw-r--r-- | src/core/core.h | 4 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 14 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/nvdrv.h | 2 |
4 files changed, 51 insertions, 0 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 3532839df..3042d611b 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -140,25 +140,45 @@ struct System::Impl { | |||
| 140 | cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {} | 140 | cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {} |
| 141 | 141 | ||
| 142 | SystemResultStatus Run() { | 142 | SystemResultStatus Run() { |
| 143 | std::unique_lock<std::mutex> lk(suspend_guard); | ||
| 143 | status = SystemResultStatus::Success; | 144 | status = SystemResultStatus::Success; |
| 144 | 145 | ||
| 145 | kernel.Suspend(false); | 146 | kernel.Suspend(false); |
| 146 | core_timing.SyncPause(false); | 147 | core_timing.SyncPause(false); |
| 147 | cpu_manager.Pause(false); | 148 | cpu_manager.Pause(false); |
| 149 | is_paused = false; | ||
| 148 | 150 | ||
| 149 | return status; | 151 | return status; |
| 150 | } | 152 | } |
| 151 | 153 | ||
| 152 | SystemResultStatus Pause() { | 154 | SystemResultStatus Pause() { |
| 155 | std::unique_lock<std::mutex> lk(suspend_guard); | ||
| 153 | status = SystemResultStatus::Success; | 156 | status = SystemResultStatus::Success; |
| 154 | 157 | ||
| 155 | core_timing.SyncPause(true); | 158 | core_timing.SyncPause(true); |
| 156 | kernel.Suspend(true); | 159 | kernel.Suspend(true); |
| 157 | cpu_manager.Pause(true); | 160 | cpu_manager.Pause(true); |
| 161 | is_paused = true; | ||
| 158 | 162 | ||
| 159 | return status; | 163 | return status; |
| 160 | } | 164 | } |
| 161 | 165 | ||
| 166 | std::unique_lock<std::mutex> StallCPU() { | ||
| 167 | std::unique_lock<std::mutex> lk(suspend_guard); | ||
| 168 | kernel.Suspend(true); | ||
| 169 | core_timing.SyncPause(true); | ||
| 170 | cpu_manager.Pause(true); | ||
| 171 | return lk; | ||
| 172 | } | ||
| 173 | |||
| 174 | void UnstallCPU() { | ||
| 175 | if (!is_paused) { | ||
| 176 | core_timing.SyncPause(false); | ||
| 177 | kernel.Suspend(false); | ||
| 178 | cpu_manager.Pause(false); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 162 | SystemResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { | 182 | SystemResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { |
| 163 | LOG_DEBUG(Core, "initialized OK"); | 183 | LOG_DEBUG(Core, "initialized OK"); |
| 164 | 184 | ||
| @@ -367,6 +387,9 @@ struct System::Impl { | |||
| 367 | return perf_stats->GetAndResetStats(core_timing.GetGlobalTimeUs()); | 387 | return perf_stats->GetAndResetStats(core_timing.GetGlobalTimeUs()); |
| 368 | } | 388 | } |
| 369 | 389 | ||
| 390 | std::mutex suspend_guard; | ||
| 391 | bool is_paused{}; | ||
| 392 | |||
| 370 | Timing::CoreTiming core_timing; | 393 | Timing::CoreTiming core_timing; |
| 371 | Kernel::KernelCore kernel; | 394 | Kernel::KernelCore kernel; |
| 372 | /// RealVfsFilesystem instance | 395 | /// RealVfsFilesystem instance |
| @@ -464,6 +487,14 @@ void System::Shutdown() { | |||
| 464 | impl->Shutdown(); | 487 | impl->Shutdown(); |
| 465 | } | 488 | } |
| 466 | 489 | ||
| 490 | std::unique_lock<std::mutex> System::StallCPU() { | ||
| 491 | return impl->StallCPU(); | ||
| 492 | } | ||
| 493 | |||
| 494 | void System::UnstallCPU() { | ||
| 495 | impl->UnstallCPU(); | ||
| 496 | } | ||
| 497 | |||
| 467 | SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, | 498 | SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, |
| 468 | u64 program_id, std::size_t program_index) { | 499 | u64 program_id, std::size_t program_index) { |
| 469 | return impl->Load(*this, emu_window, filepath, program_id, program_index); | 500 | return impl->Load(*this, emu_window, filepath, program_id, program_index); |
diff --git a/src/core/core.h b/src/core/core.h index c1234ef77..1cfe1bba6 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include <functional> | 8 | #include <functional> |
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | #include <mutex> | ||
| 10 | #include <string> | 11 | #include <string> |
| 11 | #include <vector> | 12 | #include <vector> |
| 12 | 13 | ||
| @@ -160,6 +161,9 @@ public: | |||
| 160 | /// Shutdown the emulated system. | 161 | /// Shutdown the emulated system. |
| 161 | void Shutdown(); | 162 | void Shutdown(); |
| 162 | 163 | ||
| 164 | std::unique_lock<std::mutex> StallCPU(); | ||
| 165 | void UnstallCPU(); | ||
| 166 | |||
| 163 | /** | 167 | /** |
| 164 | * Load an executable application. | 168 | * Load an executable application. |
| 165 | * @param emu_window Reference to the host-system window used for video output and keyboard | 169 | * @param emu_window Reference to the host-system window used for video output and keyboard |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 8b4867ca7..f9b82b504 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -92,6 +92,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector | |||
| 92 | if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { | 92 | if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { |
| 93 | params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id); | 93 | params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id); |
| 94 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 94 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 95 | events_interface.failed[event_id] = false; | ||
| 95 | return NvResult::Success; | 96 | return NvResult::Success; |
| 96 | } | 97 | } |
| 97 | 98 | ||
| @@ -99,6 +100,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector | |||
| 99 | syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { | 100 | syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { |
| 100 | params.value = new_value; | 101 | params.value = new_value; |
| 101 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 102 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 103 | events_interface.failed[event_id] = false; | ||
| 102 | return NvResult::Success; | 104 | return NvResult::Success; |
| 103 | } | 105 | } |
| 104 | 106 | ||
| @@ -117,6 +119,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector | |||
| 117 | event.event->GetWritableEvent().Signal(); | 119 | event.event->GetWritableEvent().Signal(); |
| 118 | params.value = current_syncpoint_value; | 120 | params.value = current_syncpoint_value; |
| 119 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 121 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 122 | events_interface.failed[event_id] = false; | ||
| 120 | return NvResult::Success; | 123 | return NvResult::Success; |
| 121 | } | 124 | } |
| 122 | const u32 target_value = current_syncpoint_value - diff; | 125 | const u32 target_value = current_syncpoint_value - diff; |
| @@ -146,6 +149,16 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector | |||
| 146 | } | 149 | } |
| 147 | params.value |= event_id; | 150 | params.value |= event_id; |
| 148 | event.event->GetWritableEvent().Clear(); | 151 | event.event->GetWritableEvent().Clear(); |
| 152 | if (events_interface.failed[event_id]) { | ||
| 153 | { | ||
| 154 | auto lk = system.StallCPU(); | ||
| 155 | gpu.WaitFence(params.syncpt_id, target_value); | ||
| 156 | system.UnstallCPU(); | ||
| 157 | } | ||
| 158 | std::memcpy(output.data(), ¶ms, sizeof(params)); | ||
| 159 | events_interface.failed[event_id] = false; | ||
| 160 | return NvResult::Success; | ||
| 161 | } | ||
| 149 | gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); | 162 | gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); |
| 150 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 163 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 151 | return NvResult::Timeout; | 164 | return NvResult::Timeout; |
| @@ -201,6 +214,7 @@ NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::v | |||
| 201 | if (events_interface.status[event_id] == EventState::Waiting) { | 214 | if (events_interface.status[event_id] == EventState::Waiting) { |
| 202 | events_interface.LiberateEvent(event_id); | 215 | events_interface.LiberateEvent(event_id); |
| 203 | } | 216 | } |
| 217 | events_interface.failed[event_id] = true; | ||
| 204 | 218 | ||
| 205 | syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id); | 219 | syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id); |
| 206 | 220 | ||
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index e2a1dde5b..a5af5b785 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -49,6 +49,8 @@ struct EventInterface { | |||
| 49 | std::array<EventState, MaxNvEvents> status{}; | 49 | std::array<EventState, MaxNvEvents> status{}; |
| 50 | // Tells if an NVEvent is registered or not | 50 | // Tells if an NVEvent is registered or not |
| 51 | std::array<bool, MaxNvEvents> registered{}; | 51 | std::array<bool, MaxNvEvents> registered{}; |
| 52 | // Tells the NVEvent that it has failed. | ||
| 53 | std::array<bool, MaxNvEvents> failed{}; | ||
| 52 | // When an NVEvent is waiting on GPU interrupt, this is the sync_point | 54 | // When an NVEvent is waiting on GPU interrupt, this is the sync_point |
| 53 | // associated with it. | 55 | // associated with it. |
| 54 | std::array<u32, MaxNvEvents> assigned_syncpt{}; | 56 | std::array<u32, MaxNvEvents> assigned_syncpt{}; |