mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 22:29:39 -06:00
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -50,3 +50,4 @@ void EmulatorState(bool running);
|
||||
bool AtBreakpoint();
|
||||
void ResetVideoBuffer();
|
||||
void Fifo_SetRendering(bool bEnabled);
|
||||
int Fifo_Update(int ticks);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
Reference in New Issue
Block a user