Merge pull request #2533 from degasus/syncgpu

Fifo: Rewrite SyncGPU
This commit is contained in:
Jules Blok
2015-06-09 09:43:26 +02:00
12 changed files with 126 additions and 110 deletions

View File

@ -16,7 +16,6 @@
#include "Core/HW/Memmap.h"
#include "Core/HW/MMIO.h"
#include "Core/HW/ProcessorInterface.h"
#include "Core/HW/SystemTimers.h"
#include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/PixelEngine.h"
@ -47,8 +46,6 @@ static std::atomic<bool> s_interrupt_waiting;
static std::atomic<bool> s_interrupt_token_waiting;
static std::atomic<bool> s_interrupt_finish_waiting;
static std::atomic<u32> s_vi_ticks(CommandProcessor::m_cpClockOrigin);
static bool IsOnThread()
{
return SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread;
@ -546,30 +543,4 @@ void SetCpClearRegister()
{
}
void Update()
{
while (s_vi_ticks.load() > m_cpClockOrigin && fifo.isGpuReadingData && IsOnThread())
Common::YieldCPU();
if (fifo.isGpuReadingData)
s_vi_ticks.fetch_add(SystemTimers::GetTicksPerSecond() / 10000);
RunGpu();
}
u32 GetVITicks()
{
return s_vi_ticks.load();
}
void SetVITicks(u32 ticks)
{
s_vi_ticks.store(ticks);
}
void DecrementVITicks(u32 ticks)
{
s_vi_ticks.fetch_sub(ticks);
}
} // end of namespace CommandProcessor

View File

@ -121,9 +121,6 @@ union UCPClearReg
UCPClearReg(u16 _hex) {Hex = _hex; }
};
// Can be any number, low enough to not be below the number of clocks executed by the GPU per CP_PERIOD
const static u32 m_cpClockOrigin = 200000;
// Init
void Init();
void Shutdown();
@ -146,10 +143,4 @@ void SetCpControlRegister();
void SetCpStatusRegister();
void ProcessFifoEvents();
void Update();
u32 GetVITicks();
void SetVITicks(u32 ticks);
void DecrementVITicks(u32 ticks);
} // namespace CommandProcessor

View File

@ -61,6 +61,9 @@ static u8* s_video_buffer_pp_read_ptr;
// polls, it's just atomic.
// - The pp_read_ptr is the CPU preprocessing version of the read_ptr.
static std::atomic<int> s_sync_ticks;
static Common::Event s_sync_wakeup_event;
void Fifo_DoState(PointerWrap &p)
{
p.DoArray(s_video_buffer, FIFO_SIZE);
@ -99,7 +102,7 @@ void Fifo_Init()
ResetVideoBuffer();
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread)
s_gpu_mainloop.Prepare();
CommandProcessor::SetVITicks(CommandProcessor::m_cpClockOrigin);
s_sync_ticks.store(0);
}
void Fifo_Shutdown()
@ -282,6 +285,8 @@ void RunGpuLoop()
s_gpu_mainloop.Run(
[] {
const SCoreStartupParameter& param = SConfig::GetInstance().m_LocalCoreStartupParameter;
g_video_backend->PeekMessages();
// Do nothing while paused
@ -310,63 +315,59 @@ void RunGpuLoop()
CommandProcessor::SetCPStatusFromGPU();
if (!fifo.isGpuReadingData)
{
CommandProcessor::SetVITicks(CommandProcessor::m_cpClockOrigin);
}
bool run_loop = true;
// check if we are able to run this buffer
while (run_loop && !CommandProcessor::IsInterruptWaiting() && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint())
while (!CommandProcessor::IsInterruptWaiting() && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint())
{
fifo.isGpuReadingData = true;
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU && s_sync_ticks.load() < param.iSyncGpuMinDistance)
break;
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU || CommandProcessor::GetVITicks() > CommandProcessor::m_cpClockOrigin)
{
u32 cyclesExecuted = 0;
u32 readPtr = fifo.CPReadPointer;
ReadDataFromFifo(readPtr);
u32 cyclesExecuted = 0;
u32 readPtr = fifo.CPReadPointer;
ReadDataFromFifo(readPtr);
if (readPtr == fifo.CPEnd)
readPtr = fifo.CPBase;
else
readPtr += 32;
_assert_msg_(COMMANDPROCESSOR, (s32)fifo.CPReadWriteDistance - 32 >= 0 ,
"Negative fifo.CPReadWriteDistance = %i in FIFO Loop !\nThat can produce instability in the game. Please report it.", fifo.CPReadWriteDistance - 32);
u8* write_ptr = s_video_buffer_write_ptr;
s_video_buffer_read_ptr = OpcodeDecoder_Run(DataReader(s_video_buffer_read_ptr, write_ptr), &cyclesExecuted, false);
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU && CommandProcessor::GetVITicks() >= cyclesExecuted)
CommandProcessor::DecrementVITicks(cyclesExecuted);
Common::AtomicStore(fifo.CPReadPointer, readPtr);
Common::AtomicAdd(fifo.CPReadWriteDistance, -32);
if ((write_ptr - s_video_buffer_read_ptr) == 0)
Common::AtomicStore(fifo.SafeCPReadPointer, fifo.CPReadPointer);
}
if (readPtr == fifo.CPEnd)
readPtr = fifo.CPBase;
else
{
run_loop = false;
}
readPtr += 32;
_assert_msg_(COMMANDPROCESSOR, (s32)fifo.CPReadWriteDistance - 32 >= 0 ,
"Negative fifo.CPReadWriteDistance = %i in FIFO Loop !\nThat can produce instability in the game. Please report it.", fifo.CPReadWriteDistance - 32);
u8* write_ptr = s_video_buffer_write_ptr;
s_video_buffer_read_ptr = OpcodeDecoder_Run(DataReader(s_video_buffer_read_ptr, write_ptr), &cyclesExecuted, false);
Common::AtomicStore(fifo.CPReadPointer, readPtr);
Common::AtomicAdd(fifo.CPReadWriteDistance, -32);
if ((write_ptr - s_video_buffer_read_ptr) == 0)
Common::AtomicStore(fifo.SafeCPReadPointer, fifo.CPReadPointer);
CommandProcessor::SetCPStatusFromGPU();
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU)
{
cyclesExecuted = (int)(cyclesExecuted / param.fSyncGpuOverclock);
int old = s_sync_ticks.fetch_sub(cyclesExecuted);
if (old > 0 && old - (int)cyclesExecuted <= 0)
s_sync_wakeup_event.Set();
}
// This call is pretty important in DualCore mode and must be called in the FIFO Loop.
// If we don't, s_swapRequested or s_efbAccessRequested won't be set to false
// leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing things down.
AsyncRequests::GetInstance()->PullEvents();
}
// fast skip remaining GPU time if fifo is empty
if (s_sync_ticks.load() > 0)
{
int old = s_sync_ticks.exchange(0);
if (old > 0)
s_sync_wakeup_event.Set();
}
// The fifo is empty and it's unlikely we will get any more work in the near future.
// Make sure VertexManager finishes drawing any primitives it has stored in it's buffer.
VertexManager::Flush();
// don't release the GPU running state on sync GPU waits
fifo.isGpuReadingData = !run_loop;
}
}, 100);
@ -376,7 +377,9 @@ void RunGpuLoop()
void FlushGpu()
{
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread || g_use_deterministic_gpu_thread)
const SCoreStartupParameter& param = SConfig::GetInstance().m_LocalCoreStartupParameter;
if (!param.bCPUThread || g_use_deterministic_gpu_thread)
return;
s_gpu_mainloop.Wait();
@ -396,9 +399,10 @@ bool AtBreakpoint()
void RunGpu()
{
SCPFifoStruct &fifo = CommandProcessor::fifo;
const SCoreStartupParameter& param = SConfig::GetInstance().m_LocalCoreStartupParameter;
// execute GPU
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread || g_use_deterministic_gpu_thread)
if (!param.bCPUThread || g_use_deterministic_gpu_thread)
{
bool reset_simd_state = false;
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() )
@ -438,7 +442,7 @@ void RunGpu()
}
// wake up GPU thread
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread)
if (param.bCPUThread)
{
s_gpu_mainloop.Wakeup();
}
@ -471,7 +475,7 @@ void Fifo_UpdateWantDeterminism(bool want)
break;
}
gpu_thread = gpu_thread && SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread;
gpu_thread = gpu_thread && param.bCPUThread;
if (g_use_deterministic_gpu_thread != gpu_thread)
{
@ -485,3 +489,40 @@ void Fifo_UpdateWantDeterminism(bool want)
}
}
}
int Fifo_Update(int ticks)
{
const SCoreStartupParameter& param = SConfig::GetInstance().m_LocalCoreStartupParameter;
if (ticks == 0)
{
FlushGpu();
return param.iSyncGpuMaxDistance;
}
// GPU is sleeping, so no need for synchronization
if (s_gpu_mainloop.IsDone() || g_use_deterministic_gpu_thread)
{
if (s_sync_ticks.load() < 0)
{
int old = s_sync_ticks.fetch_add(ticks);
if (old < param.iSyncGpuMinDistance && old + ticks >= param.iSyncGpuMinDistance)
RunGpu();
}
return param.iSyncGpuMaxDistance;
}
int old = s_sync_ticks.fetch_add(ticks);
if (old < param.iSyncGpuMinDistance && old + ticks >= param.iSyncGpuMinDistance)
RunGpu();
if (s_sync_ticks.load() >= param.iSyncGpuMaxDistance)
{
while (s_sync_ticks.load() > 0)
{
s_sync_wakeup_event.Wait();
}
}
return param.iSyncGpuMaxDistance - s_sync_ticks.load();
}

View File

@ -50,3 +50,4 @@ void EmulatorState(bool running);
bool AtBreakpoint();
void ResetVideoBuffer();
void Fifo_SetRendering(bool bEnabled);
int Fifo_Update(int ticks);

View File

@ -245,9 +245,9 @@ void VideoBackendHardware::Video_GatherPipeBursted()
CommandProcessor::GatherPipeBursted();
}
void VideoBackendHardware::Video_Sync()
int VideoBackendHardware::Video_Sync(int ticks)
{
FlushGpu();
return Fifo_Update(ticks);
}
void VideoBackendHardware::RegisterCPMMIO(MMIO::Mapping* mmio, u32 base)

View File

@ -56,9 +56,6 @@ struct SCPFifoStruct
volatile u32 bFF_LoWatermark;
volatile u32 bFF_HiWatermark;
// for GP watchdog hack
volatile u32 isGpuReadingData;
};
class VideoBackend
@ -99,7 +96,7 @@ public:
virtual void Video_GatherPipeBursted() = 0;
virtual void Video_Sync() = 0;
virtual int Video_Sync(int ticks) = 0;
// Registers MMIO handlers for the CommandProcessor registers.
virtual void RegisterCPMMIO(MMIO::Mapping* mmio, u32 base) = 0;
@ -148,7 +145,7 @@ class VideoBackendHardware : public VideoBackend
void Video_GatherPipeBursted() override;
void Video_Sync() override;
int Video_Sync(int ticks) override;
void RegisterCPMMIO(MMIO::Mapping* mmio, u32 base) override;