Skip to content

Commit

Permalink
VideoCommon: rewrite sync on idle skipping hack
Browse files Browse the repository at this point in the history
Now it's done without a busy loop
  • Loading branch information
degasus committed Mar 11, 2015
1 parent 3e17e61 commit 1fe7067
Show file tree
Hide file tree
Showing 10 changed files with 29 additions and 39 deletions.
6 changes: 1 addition & 5 deletions Source/Core/Core/CoreTiming.cpp
Expand Up @@ -480,11 +480,7 @@ void Idle()
//When the FIFO is processing data we must not advance because in this way
//the VI will be desynchronized. So, We are waiting until the FIFO finish and
//while we process only the events required by the FIFO.
while (g_video_backend->Video_IsPossibleWaitingSetDrawDone())
{
ProcessFifoWaitEvents();
Common::YieldCPU();
}
g_video_backend->Video_Sync();
}

idledCycles += DowncountToCycles(PowerPC::ppcState.downcount);
Expand Down
5 changes: 0 additions & 5 deletions Source/Core/VideoBackends/Software/SWmain.cpp
Expand Up @@ -360,11 +360,6 @@ void VideoSoftware::Video_GatherPipeBursted()
SWCommandProcessor::GatherPipeBursted();
}

bool VideoSoftware::Video_IsPossibleWaitingSetDrawDone()
{
return false;
}

void VideoSoftware::RegisterCPMMIO(MMIO::Mapping* mmio, u32 base)
{
SWCommandProcessor::RegisterMMIO(mmio, base);
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/VideoBackends/Software/VideoBackend.h
Expand Up @@ -45,7 +45,7 @@ class VideoSoftware : public VideoBackend
void Video_SetRendering(bool bEnabled) override;

void Video_GatherPipeBursted() override;
bool Video_IsPossibleWaitingSetDrawDone() override;
void Video_Sync() override {}

void RegisterCPMMIO(MMIO::Mapping* mmio, u32 base) override;

Expand Down
17 changes: 2 additions & 15 deletions Source/Core/VideoCommon/CommandProcessor.cpp
Expand Up @@ -40,7 +40,6 @@ static u16 m_bboxright;
static u16 m_bboxbottom;
static u16 m_tokenReg;

volatile bool isPossibleWaitingSetDrawDone = false;
volatile bool interruptSet= false;
volatile bool interruptWaiting= false;
volatile bool interruptTokenWaiting = false;
Expand Down Expand Up @@ -70,7 +69,6 @@ void DoState(PointerWrap &p)
p.Do(m_tokenReg);
p.Do(fifo);

p.Do(isPossibleWaitingSetDrawDone);
p.Do(interruptSet);
p.Do(interruptWaiting);
p.Do(interruptTokenWaiting);
Expand Down Expand Up @@ -123,8 +121,6 @@ void Init()
interruptFinishWaiting = false;
interruptTokenWaiting = false;

isPossibleWaitingSetDrawDone = false;

et_UpdateInterrupts = CoreTiming::RegisterEvent("CPInterrupt", UpdateInterrupts_Wrapper);
}

Expand Down Expand Up @@ -319,7 +315,7 @@ void GatherPipeBursted()
(ProcessorInterface::Fifo_CPUBase == fifo.CPBase) &&
fifo.CPReadWriteDistance > 0)
{
ProcessFifoAllDistance();
FlushGpu();
}
}
RunGpu();
Expand Down Expand Up @@ -468,15 +464,6 @@ void SetCPStatusFromCPU()
}
}

void ProcessFifoAllDistance()
{
if (IsOnThread())
{
while (!interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint())
Common::YieldCPU();
}
}

void ProcessFifoEvents()
{
if (IsOnThread() && (interruptWaiting || interruptFinishWaiting || interruptTokenWaiting))
Expand Down Expand Up @@ -518,7 +505,7 @@ void SetCpControlRegister()
if (fifo.bFF_GPReadEnable && !m_CPCtrlReg.GPReadEnable)
{
fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable;
while (fifo.isGpuReadingData) Common::YieldCPU();
FlushGpu();
}
else
{
Expand Down
2 changes: 0 additions & 2 deletions Source/Core/VideoCommon/CommandProcessor.h
Expand Up @@ -17,7 +17,6 @@ namespace CommandProcessor

extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread.

extern volatile bool isPossibleWaitingSetDrawDone; //This one is used for sync gfx thread and emulator thread.
extern volatile bool interruptSet;
extern volatile bool interruptWaiting;
extern volatile bool interruptTokenWaiting;
Expand Down Expand Up @@ -145,7 +144,6 @@ void UpdateInterruptsFromVideoBackend(u64 userdata);
void SetCpClearRegister();
void SetCpControlRegister();
void SetCpStatusRegister();
void ProcessFifoAllDistance();
void ProcessFifoEvents();

void Update();
Expand Down
26 changes: 20 additions & 6 deletions Source/Core/VideoCommon/Fifo.cpp
Expand Up @@ -72,6 +72,14 @@ static std::atomic<bool> s_gpu_is_running;
static std::mutex s_fifo_mutex;
static std::condition_variable s_fifo_cond_var;

// The next two variables and "isGpuReadingData" are used to block the CPU thread until the GPU is idlying
// The setup is similiar to the one above but without the fast path. Shuting down the GPU is rare so there is no need for it.
// So the condition variable is always triggered after the flag is cleared.
// Both need to be made safe by a mutex.
// Also on calling RunGpu, this flag is set. Else it may happen that the CPU calls FlushGpu very soon and the GPU thread didn't start already.
static std::mutex s_gpu_flush_mutex;
static std::condition_variable s_gpu_flush_cond_var;

void Fifo_DoState(PointerWrap &p)
{
p.DoArray(s_video_buffer, FIFO_SIZE);
Expand Down Expand Up @@ -141,9 +149,8 @@ void ExitGpuLoop()
{
// This should break the wait loop in CPU thread
CommandProcessor::fifo.bFF_GPReadEnable = false;
SCPFifoStruct &fifo = CommandProcessor::fifo;
while (fifo.isGpuReadingData)
Common::YieldCPU();
FlushGpu();

// Terminate GPU thread loop
GpuRunningState = false;
EmuRunningState = true;
Expand Down Expand Up @@ -322,7 +329,6 @@ void RunGpuLoop()
while (GpuRunningState && EmuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint())
{
fifo.isGpuReadingData = true;
CommandProcessor::isPossibleWaitingSetDrawDone = fifo.bFF_GPLinkEnable ? true : false;

if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU || Common::AtomicLoad(CommandProcessor::VITicks) > CommandProcessor::m_cpClockOrigin)
{
Expand Down Expand Up @@ -357,10 +363,10 @@ void RunGpuLoop()
// 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();
CommandProcessor::isPossibleWaitingSetDrawDone = false;
}

std::unique_lock<std::mutex> lock(s_gpu_flush_mutex);
fifo.isGpuReadingData = false;
s_gpu_flush_cond_var.notify_all();
}

if (EmuRunningState)
Expand Down Expand Up @@ -397,6 +403,14 @@ void RunGpuLoop()
AsyncRequests::GetInstance()->SetPassthrough(true);
}

void FlushGpu()
{
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread || g_use_deterministic_gpu_thread || !CommandProcessor::fifo.isGpuReadingData)
return;

std::unique_lock<std::mutex> lock(s_gpu_flush_mutex);
s_gpu_flush_cond_var.wait(lock, []() { return !CommandProcessor::fifo.isGpuReadingData; });
}

bool AtBreakpoint()
{
Expand Down
1 change: 1 addition & 0 deletions Source/Core/VideoCommon/Fifo.h
Expand Up @@ -41,6 +41,7 @@ void SyncGPU(SyncGPUReason reason, bool may_move_read_ptr = true);
void PushFifoAuxBuffer(void* ptr, size_t size);
void* PopFifoAuxBuffer(size_t size);

void FlushGpu();
void RunGpu();
void RunGpuLoop();
void ExitGpuLoop();
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/VideoCommon/MainBase.cpp
Expand Up @@ -233,9 +233,9 @@ void VideoBackendHardware::Video_GatherPipeBursted()
CommandProcessor::GatherPipeBursted();
}

bool VideoBackendHardware::Video_IsPossibleWaitingSetDrawDone()
void VideoBackendHardware::Video_Sync()
{
return CommandProcessor::isPossibleWaitingSetDrawDone;
FlushGpu();
}

void VideoBackendHardware::RegisterCPMMIO(MMIO::Mapping* mmio, u32 base)
Expand Down
1 change: 0 additions & 1 deletion Source/Core/VideoCommon/PixelEngine.cpp
Expand Up @@ -287,7 +287,6 @@ void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
Common::AtomicStore(*(volatile u32*)&g_bSignalFinishInterrupt, 1);
UpdateInterrupts();
CommandProcessor::interruptFinishWaiting = false;
CommandProcessor::isPossibleWaitingSetDrawDone = false;
}

// SetToken
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/VideoCommon/VideoBackendBase.h
Expand Up @@ -99,7 +99,7 @@ class VideoBackend

virtual void Video_GatherPipeBursted() = 0;

virtual bool Video_IsPossibleWaitingSetDrawDone() = 0;
virtual void Video_Sync() = 0;

// Registers MMIO handlers for the CommandProcessor registers.
virtual void RegisterCPMMIO(MMIO::Mapping* mmio, u32 base) = 0;
Expand Down Expand Up @@ -148,7 +148,7 @@ class VideoBackendHardware : public VideoBackend

void Video_GatherPipeBursted() override;

bool Video_IsPossibleWaitingSetDrawDone() override;
void Video_Sync() override;

void RegisterCPMMIO(MMIO::Mapping* mmio, u32 base) override;

Expand Down

0 comments on commit 1fe7067

Please sign in to comment.