Merge pull request #7187 from FernandoS27/boy-i-say-boy

NVHost_Ctrl: Force wait if the gpu falls behind too long.
This commit is contained in:
bunnei 2021-10-15 16:14:32 -07:00 committed by GitHub
commit aef3ae1cb9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 0 deletions

View file

@ -140,25 +140,45 @@ struct System::Impl {
cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {} cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {}
SystemResultStatus Run() { SystemResultStatus Run() {
std::unique_lock<std::mutex> lk(suspend_guard);
status = SystemResultStatus::Success; status = SystemResultStatus::Success;
kernel.Suspend(false); kernel.Suspend(false);
core_timing.SyncPause(false); core_timing.SyncPause(false);
cpu_manager.Pause(false); cpu_manager.Pause(false);
is_paused = false;
return status; return status;
} }
SystemResultStatus Pause() { SystemResultStatus Pause() {
std::unique_lock<std::mutex> lk(suspend_guard);
status = SystemResultStatus::Success; status = SystemResultStatus::Success;
core_timing.SyncPause(true); core_timing.SyncPause(true);
kernel.Suspend(true); kernel.Suspend(true);
cpu_manager.Pause(true); cpu_manager.Pause(true);
is_paused = true;
return status; return status;
} }
std::unique_lock<std::mutex> StallCPU() {
std::unique_lock<std::mutex> lk(suspend_guard);
kernel.Suspend(true);
core_timing.SyncPause(true);
cpu_manager.Pause(true);
return lk;
}
void UnstallCPU() {
if (!is_paused) {
core_timing.SyncPause(false);
kernel.Suspend(false);
cpu_manager.Pause(false);
}
}
SystemResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { SystemResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
LOG_DEBUG(Core, "initialized OK"); LOG_DEBUG(Core, "initialized OK");
@ -367,6 +387,9 @@ struct System::Impl {
return perf_stats->GetAndResetStats(core_timing.GetGlobalTimeUs()); return perf_stats->GetAndResetStats(core_timing.GetGlobalTimeUs());
} }
std::mutex suspend_guard;
bool is_paused{};
Timing::CoreTiming core_timing; Timing::CoreTiming core_timing;
Kernel::KernelCore kernel; Kernel::KernelCore kernel;
/// RealVfsFilesystem instance /// RealVfsFilesystem instance
@ -464,6 +487,14 @@ void System::Shutdown() {
impl->Shutdown(); impl->Shutdown();
} }
std::unique_lock<std::mutex> System::StallCPU() {
return impl->StallCPU();
}
void System::UnstallCPU() {
impl->UnstallCPU();
}
SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
u64 program_id, std::size_t program_index) { u64 program_id, std::size_t program_index) {
return impl->Load(*this, emu_window, filepath, program_id, program_index); return impl->Load(*this, emu_window, filepath, program_id, program_index);

View file

@ -7,6 +7,7 @@
#include <cstddef> #include <cstddef>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <mutex>
#include <string> #include <string>
#include <vector> #include <vector>
@ -160,6 +161,9 @@ public:
/// Shutdown the emulated system. /// Shutdown the emulated system.
void Shutdown(); void Shutdown();
std::unique_lock<std::mutex> StallCPU();
void UnstallCPU();
/** /**
* Load an executable application. * Load an executable application.
* @param emu_window Reference to the host-system window used for video output and keyboard * @param emu_window Reference to the host-system window used for video output and keyboard

View file

@ -92,6 +92,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) {
params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id); params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id);
std::memcpy(output.data(), &params, sizeof(params)); std::memcpy(output.data(), &params, sizeof(params));
events_interface.failed[event_id] = false;
return NvResult::Success; return NvResult::Success;
} }
@ -99,6 +100,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) {
params.value = new_value; params.value = new_value;
std::memcpy(output.data(), &params, sizeof(params)); std::memcpy(output.data(), &params, sizeof(params));
events_interface.failed[event_id] = false;
return NvResult::Success; return NvResult::Success;
} }
@ -117,6 +119,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
event.event->GetWritableEvent().Signal(); event.event->GetWritableEvent().Signal();
params.value = current_syncpoint_value; params.value = current_syncpoint_value;
std::memcpy(output.data(), &params, sizeof(params)); std::memcpy(output.data(), &params, sizeof(params));
events_interface.failed[event_id] = false;
return NvResult::Success; return NvResult::Success;
} }
const u32 target_value = current_syncpoint_value - diff; const u32 target_value = current_syncpoint_value - diff;
@ -146,6 +149,16 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
} }
params.value |= event_id; params.value |= event_id;
event.event->GetWritableEvent().Clear(); event.event->GetWritableEvent().Clear();
if (events_interface.failed[event_id]) {
{
auto lk = system.StallCPU();
gpu.WaitFence(params.syncpt_id, target_value);
system.UnstallCPU();
}
std::memcpy(output.data(), &params, sizeof(params));
events_interface.failed[event_id] = false;
return NvResult::Success;
}
gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
std::memcpy(output.data(), &params, sizeof(params)); std::memcpy(output.data(), &params, sizeof(params));
return NvResult::Timeout; return NvResult::Timeout;
@ -201,6 +214,7 @@ NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::v
if (events_interface.status[event_id] == EventState::Waiting) { if (events_interface.status[event_id] == EventState::Waiting) {
events_interface.LiberateEvent(event_id); events_interface.LiberateEvent(event_id);
} }
events_interface.failed[event_id] = true;
syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id); syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id);

View file

@ -49,6 +49,8 @@ struct EventInterface {
std::array<EventState, MaxNvEvents> status{}; std::array<EventState, MaxNvEvents> status{};
// Tells if an NVEvent is registered or not // Tells if an NVEvent is registered or not
std::array<bool, MaxNvEvents> registered{}; std::array<bool, MaxNvEvents> registered{};
// Tells the NVEvent that it has failed.
std::array<bool, MaxNvEvents> failed{};
// When an NVEvent is waiting on GPU interrupt, this is the sync_point // When an NVEvent is waiting on GPU interrupt, this is the sync_point
// associated with it. // associated with it.
std::array<u32, MaxNvEvents> assigned_syncpt{}; std::array<u32, MaxNvEvents> assigned_syncpt{};