Merge pull request #3490 from degasus/singlecore

Fifo: Use SyncGPU timings for single core.
This commit is contained in:
Markus Wick 2016-09-27 10:33:47 +02:00 committed by GitHub
commit 9525a9e048
3 changed files with 100 additions and 68 deletions

View File

@ -70,7 +70,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // Don't forget to increase this after doing changes on the savestate system
static const u32 STATE_VERSION = 58; static const u32 STATE_VERSION = 59; // Last changed in PR 3490
// Maps savestate versions to Dolphin versions. // Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list, // Versions after 42 don't need to be added to this list,

View File

@ -268,7 +268,6 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
void GatherPipeBursted() void GatherPipeBursted()
{ {
if (IsOnThread())
SetCPStatusFromCPU(); SetCPStatusFromCPU();
// if we aren't linked, we don't care about gather pipe data // if we aren't linked, we don't care about gather pipe data

View File

@ -17,6 +17,7 @@
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/CoreTiming.h" #include "Core/CoreTiming.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "Core/HW/SystemTimers.h"
#include "Core/NetPlayProto.h" #include "Core/NetPlayProto.h"
#include "VideoCommon/AsyncRequests.h" #include "VideoCommon/AsyncRequests.h"
@ -31,6 +32,7 @@
namespace Fifo namespace Fifo
{ {
static constexpr u32 FIFO_SIZE = 2 * 1024 * 1024; static constexpr u32 FIFO_SIZE = 2 * 1024 * 1024;
static constexpr int GPU_TIME_SLOT_SIZE = 1000;
static bool s_skip_current_frame = false; static bool s_skip_current_frame = false;
@ -47,7 +49,6 @@ static u8* s_fifo_aux_read_ptr;
// and can change at runtime. // and can change at runtime.
static bool s_use_deterministic_gpu_thread; static bool s_use_deterministic_gpu_thread;
static u64 s_last_sync_gpu_tick;
static CoreTiming::EventType* s_event_sync_gpu; static CoreTiming::EventType* s_event_sync_gpu;
// STATE_TO_SAVE // STATE_TO_SAVE
@ -69,6 +70,7 @@ static u8* s_video_buffer_pp_read_ptr;
// - The pp_read_ptr is the CPU preprocessing version of the read_ptr. // - The pp_read_ptr is the CPU preprocessing version of the read_ptr.
static std::atomic<int> s_sync_ticks; static std::atomic<int> s_sync_ticks;
static bool s_syncing_suspended;
static Common::Event s_sync_wakeup_event; static Common::Event s_sync_wakeup_event;
void DoState(PointerWrap& p) void DoState(PointerWrap& p)
@ -85,7 +87,7 @@ void DoState(PointerWrap& p)
} }
p.Do(s_skip_current_frame); p.Do(s_skip_current_frame);
p.Do(s_last_sync_gpu_tick); p.Do(s_sync_ticks);
} }
void PauseAndLock(bool doLock, bool unpauseOnUnlock) void PauseAndLock(bool doLock, bool unpauseOnUnlock)
@ -422,14 +424,33 @@ bool AtBreakpoint()
void RunGpu() void RunGpu()
{ {
SCPFifoStruct& fifo = CommandProcessor::fifo;
const SConfig& param = SConfig::GetInstance(); const SConfig& param = SConfig::GetInstance();
// execute GPU // wake up GPU thread
if (!param.bCPUThread || s_use_deterministic_gpu_thread) if (param.bCPUThread && !s_use_deterministic_gpu_thread)
{ {
s_gpu_mainloop.Wakeup();
}
// if the sync GPU callback is suspended, wake it up.
if (!SConfig::GetInstance().bCPUThread || s_use_deterministic_gpu_thread ||
SConfig::GetInstance().bSyncGPU)
{
if (s_syncing_suspended)
{
s_syncing_suspended = false;
CoreTiming::ScheduleEvent(GPU_TIME_SLOT_SIZE, s_event_sync_gpu, GPU_TIME_SLOT_SIZE);
}
}
}
static int RunGpuOnCpu(int ticks)
{
SCPFifoStruct& fifo = CommandProcessor::fifo;
bool reset_simd_state = false; bool reset_simd_state = false;
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint()) int available_ticks = int(ticks * SConfig::GetInstance().fSyncGpuOverclock) + s_sync_ticks.load();
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() &&
available_ticks >= 0)
{ {
if (s_use_deterministic_gpu_thread) if (s_use_deterministic_gpu_thread)
{ {
@ -445,12 +466,12 @@ void RunGpu()
reset_simd_state = true; reset_simd_state = true;
} }
ReadDataFromFifo(fifo.CPReadPointer); ReadDataFromFifo(fifo.CPReadPointer);
u32 cycles = 0;
s_video_buffer_read_ptr = OpcodeDecoder::Run( s_video_buffer_read_ptr = OpcodeDecoder::Run(
DataReader(s_video_buffer_read_ptr, s_video_buffer_write_ptr), nullptr, false); DataReader(s_video_buffer_read_ptr, s_video_buffer_write_ptr), &cycles, false);
available_ticks -= cycles;
} }
// DEBUG_LOG(COMMANDPROCESSOR, "Fifo wraps to base");
if (fifo.CPReadPointer == fifo.CPEnd) if (fifo.CPReadPointer == fifo.CPEnd)
fifo.CPReadPointer = fifo.CPBase; fifo.CPReadPointer = fifo.CPBase;
else else
@ -458,19 +479,23 @@ void RunGpu()
fifo.CPReadWriteDistance -= 32; fifo.CPReadWriteDistance -= 32;
} }
CommandProcessor::SetCPStatusFromGPU(); CommandProcessor::SetCPStatusFromGPU();
if (reset_simd_state) if (reset_simd_state)
{ {
FPURoundMode::LoadSIMDState(); FPURoundMode::LoadSIMDState();
} }
}
// wake up GPU thread // Discard all available ticks as there is nothing to do any more.
if (param.bCPUThread) s_sync_ticks.store(std::min(available_ticks, 0));
{
s_gpu_mainloop.Wakeup(); // If the GPU is idle, drop the handler.
} if (available_ticks >= 0)
return -1;
// Always wait at least for GPU_TIME_SLOT_SIZE cycles.
return -available_ticks + GPU_TIME_SLOT_SIZE;
} }
void UpdateWantDeterminism(bool want) void UpdateWantDeterminism(bool want)
@ -521,24 +546,27 @@ bool UseDeterministicGPUThread()
} }
/* This function checks the emulated CPU - GPU distance and may wake up the GPU, /* This function checks the emulated CPU - GPU distance and may wake up the GPU,
* or block the CPU if required. It should be called by the CPU thread regulary. * or block the CPU if required. It should be called by the CPU thread regularly.
* @ticks The gone emulated CPU time. * @ticks The gone emulated CPU time.
* @return A good time to call Update() next. * @return A good time to call WaitForGpuThread() next.
*/ */
static int Update(int ticks) static int WaitForGpuThread(int ticks)
{ {
const SConfig& param = SConfig::GetInstance(); const SConfig& param = SConfig::GetInstance();
// GPU is sleeping, so no need for synchronization // GPU is sleeping, so no need for synchronization
if (s_gpu_mainloop.IsDone() || s_use_deterministic_gpu_thread) if (s_gpu_mainloop.IsDone() || s_use_deterministic_gpu_thread)
{ {
if (s_sync_ticks.load() < 0) if ((s_sync_ticks.load() + ticks) < 0)
{ {
int old = s_sync_ticks.fetch_add(ticks); s_sync_ticks.store(s_sync_ticks.load() + ticks);
if (old < param.iSyncGpuMinDistance && old + ticks >= param.iSyncGpuMinDistance) return 0 - s_sync_ticks.load();
RunGpu(); }
else
{
s_sync_ticks.store(0);
return -1;
} }
return param.iSyncGpuMaxDistance;
} }
// Wakeup GPU // Wakeup GPU
@ -558,24 +586,29 @@ static int Update(int ticks)
return param.iSyncGpuMaxDistance - s_sync_ticks.load(); return param.iSyncGpuMaxDistance - s_sync_ticks.load();
} }
static void SyncGPUCallback(u64 userdata, s64 cyclesLate) static void SyncGPUCallback(u64 ticks, s64 cyclesLate)
{ {
u64 now = CoreTiming::GetTicks(); ticks += cyclesLate;
int next = Fifo::Update((int)(now - s_last_sync_gpu_tick)); int next = -1;
s_last_sync_gpu_tick = now;
if (next > 0) if (!SConfig::GetInstance().bCPUThread || s_use_deterministic_gpu_thread)
CoreTiming::ScheduleEvent(next, s_event_sync_gpu); {
next = RunGpuOnCpu((int)ticks);
}
else if (SConfig::GetInstance().bSyncGPU)
{
next = WaitForGpuThread((int)ticks);
}
s_syncing_suspended = next < 0;
if (!s_syncing_suspended)
CoreTiming::ScheduleEvent(next, s_event_sync_gpu, next);
} }
// Initialize GPU - CPU thread syncing, this gives us a deterministic way to start the GPU thread. // Initialize GPU - CPU thread syncing, this gives us a deterministic way to start the GPU thread.
void Prepare() void Prepare()
{ {
if (SConfig::GetInstance().bCPUThread && SConfig::GetInstance().bSyncGPU)
{
s_event_sync_gpu = CoreTiming::RegisterEvent("SyncGPUCallback", SyncGPUCallback); s_event_sync_gpu = CoreTiming::RegisterEvent("SyncGPUCallback", SyncGPUCallback);
CoreTiming::ScheduleEvent(0, s_event_sync_gpu); s_syncing_suspended = true;
s_last_sync_gpu_tick = CoreTiming::GetTicks();
}
} }
} }