summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/core.cpp31
-rw-r--r--src/core/core.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp14
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h2
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
490std::unique_lock<std::mutex> System::StallCPU() {
491 return impl->StallCPU();
492}
493
494void System::UnstallCPU() {
495 impl->UnstallCPU();
496}
497
467SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, 498SystemResultStatus 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(), &params, sizeof(params)); 94 std::memcpy(output.data(), &params, 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(), &params, sizeof(params)); 102 std::memcpy(output.data(), &params, 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(), &params, sizeof(params)); 121 std::memcpy(output.data(), &params, 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(), &params, 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(), &params, sizeof(params)); 163 std::memcpy(output.data(), &params, 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{};