mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-14 16:29:21 +01:00
Merge pull request #2465 from lioncash/commandproc
CommandProcessor: Replace volatile usages with atomics
This commit is contained in:
commit
255a8dfdd2
@ -2,6 +2,8 @@
|
|||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include "Common/Atomic.h"
|
#include "Common/Atomic.h"
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
@ -40,15 +42,15 @@ static u16 m_bboxright;
|
|||||||
static u16 m_bboxbottom;
|
static u16 m_bboxbottom;
|
||||||
static u16 m_tokenReg;
|
static u16 m_tokenReg;
|
||||||
|
|
||||||
volatile bool interruptSet= false;
|
static std::atomic<bool> s_interrupt_set;
|
||||||
volatile bool interruptWaiting= false;
|
static std::atomic<bool> s_interrupt_waiting;
|
||||||
volatile bool interruptTokenWaiting = false;
|
static std::atomic<bool> s_interrupt_token_waiting;
|
||||||
volatile bool interruptFinishWaiting = false;
|
static std::atomic<bool> s_interrupt_finish_waiting;
|
||||||
|
|
||||||
|
static std::atomic<u32> s_vi_ticks(CommandProcessor::m_cpClockOrigin);
|
||||||
|
|
||||||
Common::Flag s_gpuMaySleep;
|
Common::Flag s_gpuMaySleep;
|
||||||
|
|
||||||
volatile u32 VITicks = CommandProcessor::m_cpClockOrigin;
|
|
||||||
|
|
||||||
static bool IsOnThread()
|
static bool IsOnThread()
|
||||||
{
|
{
|
||||||
return SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread;
|
return SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread;
|
||||||
@ -71,10 +73,10 @@ void DoState(PointerWrap &p)
|
|||||||
p.Do(m_tokenReg);
|
p.Do(m_tokenReg);
|
||||||
p.Do(fifo);
|
p.Do(fifo);
|
||||||
|
|
||||||
p.Do(interruptSet);
|
p.Do(s_interrupt_set);
|
||||||
p.Do(interruptWaiting);
|
p.Do(s_interrupt_waiting);
|
||||||
p.Do(interruptTokenWaiting);
|
p.Do(s_interrupt_token_waiting);
|
||||||
p.Do(interruptFinishWaiting);
|
p.Do(s_interrupt_finish_waiting);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void WriteLow(volatile u32& _reg, u16 lowbits)
|
static inline void WriteLow(volatile u32& _reg, u16 lowbits)
|
||||||
@ -118,10 +120,10 @@ void Init()
|
|||||||
fifo.bFF_LoWatermark = 0;
|
fifo.bFF_LoWatermark = 0;
|
||||||
fifo.bFF_LoWatermarkInt = 0;
|
fifo.bFF_LoWatermarkInt = 0;
|
||||||
|
|
||||||
interruptSet = false;
|
s_interrupt_set.store(false);
|
||||||
interruptWaiting = false;
|
s_interrupt_waiting.store(false);
|
||||||
interruptFinishWaiting = false;
|
s_interrupt_finish_waiting.store(false);
|
||||||
interruptTokenWaiting = false;
|
s_interrupt_token_waiting.store(false);
|
||||||
|
|
||||||
et_UpdateInterrupts = CoreTiming::RegisterEvent("CPInterrupt", UpdateInterrupts_Wrapper);
|
et_UpdateInterrupts = CoreTiming::RegisterEvent("CPInterrupt", UpdateInterrupts_Wrapper);
|
||||||
}
|
}
|
||||||
@ -358,18 +360,18 @@ void UpdateInterrupts(u64 userdata)
|
|||||||
{
|
{
|
||||||
if (userdata)
|
if (userdata)
|
||||||
{
|
{
|
||||||
interruptSet = true;
|
s_interrupt_set.store(true);
|
||||||
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
|
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
|
||||||
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true);
|
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
interruptSet = false;
|
s_interrupt_set.store(false);
|
||||||
INFO_LOG(COMMANDPROCESSOR,"Interrupt cleared");
|
INFO_LOG(COMMANDPROCESSOR,"Interrupt cleared");
|
||||||
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false);
|
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false);
|
||||||
}
|
}
|
||||||
CoreTiming::ForceExceptionCheck(0);
|
CoreTiming::ForceExceptionCheck(0);
|
||||||
interruptWaiting = false;
|
s_interrupt_waiting.store(false);
|
||||||
RunGpu();
|
RunGpu();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,6 +381,21 @@ void UpdateInterruptsFromVideoBackend(u64 userdata)
|
|||||||
CoreTiming::ScheduleEvent_Threadsafe(0, et_UpdateInterrupts, userdata);
|
CoreTiming::ScheduleEvent_Threadsafe(0, et_UpdateInterrupts, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsInterruptWaiting()
|
||||||
|
{
|
||||||
|
return s_interrupt_waiting.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetInterruptTokenWaiting(bool waiting)
|
||||||
|
{
|
||||||
|
s_interrupt_token_waiting.store(waiting);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetInterruptFinishWaiting(bool waiting)
|
||||||
|
{
|
||||||
|
s_interrupt_finish_waiting.store(waiting);
|
||||||
|
}
|
||||||
|
|
||||||
void SetCPStatusFromGPU()
|
void SetCPStatusFromGPU()
|
||||||
{
|
{
|
||||||
// breakpoint
|
// breakpoint
|
||||||
@ -416,7 +433,7 @@ void SetCPStatusFromGPU()
|
|||||||
|
|
||||||
bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable;
|
bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable;
|
||||||
|
|
||||||
if (interrupt != interruptSet && !interruptWaiting)
|
if (interrupt != s_interrupt_set.load() && !s_interrupt_waiting.load())
|
||||||
{
|
{
|
||||||
u64 userdata = interrupt ? 1 : 0;
|
u64 userdata = interrupt ? 1 : 0;
|
||||||
if (IsOnThread())
|
if (IsOnThread())
|
||||||
@ -424,7 +441,7 @@ void SetCPStatusFromGPU()
|
|||||||
if (!interrupt || bpInt || undfInt || ovfInt)
|
if (!interrupt || bpInt || undfInt || ovfInt)
|
||||||
{
|
{
|
||||||
// Schedule the interrupt asynchronously
|
// Schedule the interrupt asynchronously
|
||||||
interruptWaiting = true;
|
s_interrupt_waiting.store(true);
|
||||||
CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
|
CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -447,14 +464,14 @@ void SetCPStatusFromCPU()
|
|||||||
|
|
||||||
bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable;
|
bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable;
|
||||||
|
|
||||||
if (interrupt != interruptSet && !interruptWaiting)
|
if (interrupt != s_interrupt_set.load() && !s_interrupt_waiting.load())
|
||||||
{
|
{
|
||||||
u64 userdata = interrupt ? 1 : 0;
|
u64 userdata = interrupt ? 1 : 0;
|
||||||
if (IsOnThread())
|
if (IsOnThread())
|
||||||
{
|
{
|
||||||
if (!interrupt || bpInt || undfInt || ovfInt)
|
if (!interrupt || bpInt || undfInt || ovfInt)
|
||||||
{
|
{
|
||||||
interruptSet = interrupt;
|
s_interrupt_set.store(interrupt);
|
||||||
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
|
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
|
||||||
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, interrupt);
|
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, interrupt);
|
||||||
}
|
}
|
||||||
@ -468,7 +485,7 @@ void SetCPStatusFromCPU()
|
|||||||
|
|
||||||
void ProcessFifoEvents()
|
void ProcessFifoEvents()
|
||||||
{
|
{
|
||||||
if (IsOnThread() && (interruptWaiting || interruptFinishWaiting || interruptTokenWaiting))
|
if (IsOnThread() && (s_interrupt_waiting.load() || s_interrupt_finish_waiting.load() || s_interrupt_token_waiting.load()))
|
||||||
CoreTiming::ProcessFifoWaitEvents();
|
CoreTiming::ProcessFifoWaitEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,12 +550,28 @@ void SetCpClearRegister()
|
|||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
while (VITicks > m_cpClockOrigin && fifo.isGpuReadingData && IsOnThread())
|
while (s_vi_ticks.load() > m_cpClockOrigin && fifo.isGpuReadingData && IsOnThread())
|
||||||
Common::YieldCPU();
|
Common::YieldCPU();
|
||||||
|
|
||||||
if (fifo.isGpuReadingData)
|
if (fifo.isGpuReadingData)
|
||||||
Common::AtomicAdd(VITicks, SystemTimers::GetTicksPerSecond() / 10000);
|
s_vi_ticks.fetch_add(SystemTimers::GetTicksPerSecond() / 10000);
|
||||||
|
|
||||||
RunGpu();
|
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
|
} // end of namespace CommandProcessor
|
||||||
|
@ -17,11 +17,6 @@ namespace CommandProcessor
|
|||||||
{
|
{
|
||||||
|
|
||||||
extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread.
|
extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread.
|
||||||
|
|
||||||
extern volatile bool interruptSet;
|
|
||||||
extern volatile bool interruptWaiting;
|
|
||||||
extern volatile bool interruptTokenWaiting;
|
|
||||||
extern volatile bool interruptFinishWaiting;
|
|
||||||
extern Common::Flag s_gpuMaySleep;
|
extern Common::Flag s_gpuMaySleep;
|
||||||
|
|
||||||
// internal hardware addresses
|
// internal hardware addresses
|
||||||
@ -143,12 +138,19 @@ void GatherPipeBursted();
|
|||||||
void UpdateInterrupts(u64 userdata);
|
void UpdateInterrupts(u64 userdata);
|
||||||
void UpdateInterruptsFromVideoBackend(u64 userdata);
|
void UpdateInterruptsFromVideoBackend(u64 userdata);
|
||||||
|
|
||||||
|
bool IsInterruptWaiting();
|
||||||
|
void SetInterruptTokenWaiting(bool waiting);
|
||||||
|
void SetInterruptFinishWaiting(bool waiting);
|
||||||
|
|
||||||
void SetCpClearRegister();
|
void SetCpClearRegister();
|
||||||
void SetCpControlRegister();
|
void SetCpControlRegister();
|
||||||
void SetCpStatusRegister();
|
void SetCpStatusRegister();
|
||||||
void ProcessFifoEvents();
|
void ProcessFifoEvents();
|
||||||
|
|
||||||
void Update();
|
void Update();
|
||||||
extern volatile u32 VITicks;
|
|
||||||
|
u32 GetVITicks();
|
||||||
|
void SetVITicks(u32 ticks);
|
||||||
|
void DecrementVITicks(u32 ticks);
|
||||||
|
|
||||||
} // namespace CommandProcessor
|
} // namespace CommandProcessor
|
||||||
|
@ -103,7 +103,7 @@ void Fifo_Init()
|
|||||||
s_video_buffer = (u8*)AllocateMemoryPages(FIFO_SIZE + 4);
|
s_video_buffer = (u8*)AllocateMemoryPages(FIFO_SIZE + 4);
|
||||||
ResetVideoBuffer();
|
ResetVideoBuffer();
|
||||||
s_gpu_running_state.store(false);
|
s_gpu_running_state.store(false);
|
||||||
Common::AtomicStore(CommandProcessor::VITicks, CommandProcessor::m_cpClockOrigin);
|
CommandProcessor::SetVITicks(CommandProcessor::m_cpClockOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fifo_Shutdown()
|
void Fifo_Shutdown()
|
||||||
@ -321,17 +321,17 @@ void RunGpuLoop()
|
|||||||
|
|
||||||
if (!fifo.isGpuReadingData)
|
if (!fifo.isGpuReadingData)
|
||||||
{
|
{
|
||||||
Common::AtomicStore(CommandProcessor::VITicks, CommandProcessor::m_cpClockOrigin);
|
CommandProcessor::SetVITicks(CommandProcessor::m_cpClockOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool run_loop = true;
|
bool run_loop = true;
|
||||||
|
|
||||||
// check if we are able to run this buffer
|
// check if we are able to run this buffer
|
||||||
while (run_loop && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint())
|
while (run_loop && !CommandProcessor::IsInterruptWaiting() && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint())
|
||||||
{
|
{
|
||||||
fifo.isGpuReadingData = true;
|
fifo.isGpuReadingData = true;
|
||||||
|
|
||||||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU || Common::AtomicLoad(CommandProcessor::VITicks) > CommandProcessor::m_cpClockOrigin)
|
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU || CommandProcessor::GetVITicks() > CommandProcessor::m_cpClockOrigin)
|
||||||
{
|
{
|
||||||
u32 readPtr = fifo.CPReadPointer;
|
u32 readPtr = fifo.CPReadPointer;
|
||||||
ReadDataFromFifo(readPtr);
|
ReadDataFromFifo(readPtr);
|
||||||
@ -349,8 +349,8 @@ void RunGpuLoop()
|
|||||||
s_video_buffer_read_ptr = OpcodeDecoder_Run(DataReader(s_video_buffer_read_ptr, write_ptr), &cyclesExecuted, false);
|
s_video_buffer_read_ptr = OpcodeDecoder_Run(DataReader(s_video_buffer_read_ptr, write_ptr), &cyclesExecuted, false);
|
||||||
|
|
||||||
|
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU && Common::AtomicLoad(CommandProcessor::VITicks) >= cyclesExecuted)
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU && CommandProcessor::GetVITicks() >= cyclesExecuted)
|
||||||
Common::AtomicAdd(CommandProcessor::VITicks, -(s32)cyclesExecuted);
|
CommandProcessor::DecrementVITicks(cyclesExecuted);
|
||||||
|
|
||||||
Common::AtomicStore(fifo.CPReadPointer, readPtr);
|
Common::AtomicStore(fifo.CPReadPointer, readPtr);
|
||||||
Common::AtomicAdd(fifo.CPReadWriteDistance, -32);
|
Common::AtomicAdd(fifo.CPReadWriteDistance, -32);
|
||||||
|
@ -274,14 +274,14 @@ void SetToken_OnMainThread(u64 userdata, int cyclesLate)
|
|||||||
s_signal_token_interrupt.store(1);
|
s_signal_token_interrupt.store(1);
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
CommandProcessor::interruptTokenWaiting = false;
|
CommandProcessor::SetInterruptTokenWaiting(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
|
void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
s_signal_finish_interrupt.store(1);
|
s_signal_finish_interrupt.store(1);
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
CommandProcessor::interruptFinishWaiting = false;
|
CommandProcessor::SetInterruptFinishWaiting(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetToken
|
// SetToken
|
||||||
@ -293,7 +293,8 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge)
|
|||||||
s_signal_token_interrupt.store(1);
|
s_signal_token_interrupt.store(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandProcessor::interruptTokenWaiting = true;
|
CommandProcessor::SetInterruptTokenWaiting(true);
|
||||||
|
|
||||||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread || g_use_deterministic_gpu_thread)
|
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread || g_use_deterministic_gpu_thread)
|
||||||
CoreTiming::ScheduleEvent(0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16));
|
CoreTiming::ScheduleEvent(0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16));
|
||||||
else
|
else
|
||||||
@ -304,11 +305,13 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge)
|
|||||||
// THIS IS EXECUTED FROM VIDEO THREAD (BPStructs.cpp) when a new frame has been drawn
|
// THIS IS EXECUTED FROM VIDEO THREAD (BPStructs.cpp) when a new frame has been drawn
|
||||||
void SetFinish()
|
void SetFinish()
|
||||||
{
|
{
|
||||||
CommandProcessor::interruptFinishWaiting = true;
|
CommandProcessor::SetInterruptFinishWaiting(true);
|
||||||
|
|
||||||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread || g_use_deterministic_gpu_thread)
|
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread || g_use_deterministic_gpu_thread)
|
||||||
CoreTiming::ScheduleEvent(0, et_SetFinishOnMainThread, 0);
|
CoreTiming::ScheduleEvent(0, et_SetFinishOnMainThread, 0);
|
||||||
else
|
else
|
||||||
CoreTiming::ScheduleEvent_Threadsafe(0, et_SetFinishOnMainThread, 0);
|
CoreTiming::ScheduleEvent_Threadsafe(0, et_SetFinishOnMainThread, 0);
|
||||||
|
|
||||||
INFO_LOG(PIXELENGINE, "VIDEO Set Finish");
|
INFO_LOG(PIXELENGINE, "VIDEO Set Finish");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user