Added preliminary support to synchronise the timing of the CPU and GPU threads. A new option has been added to the game properties for this purpose. This option may help with random freezes in Dual Core mode.

Fixes Gladius and Baten Kaitos: Eternal Wings and the Lost Ocean

Fixes issue 5150.
This commit is contained in:
skidau 2013-02-16 12:51:09 +11:00
parent 51795d8811
commit 9bff8e00c8
17 changed files with 211 additions and 109 deletions

View File

@ -1,5 +1,6 @@
# GKBEAF - Baten Kaitos
[Core] Values set here will override the main dolphin settings.
SyncGPU = 1
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId = 4
EmulationIssues =

View File

@ -1,5 +1,6 @@
# GKBPAF - Baten Kaitos
[Core] Values set here will override the main dolphin settings.
SyncGPU = 1
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId = 4
EmulationIssues =

View File

@ -1,8 +1,9 @@
# GLSE64 - LucasArts Gladius
[Core] Values set here will override the main dolphin settings.
TLBHack = 1
SyncGPU = 1
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId = 1
EmulationStateId = 4
EmulationIssues =
[OnFrame] Add memory patches to be applied every frame here.
[ActionReplay] Add action replay cheats here.

View File

@ -55,7 +55,7 @@ namespace BootManager
struct ConfigCache
{
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF,
bVBeam, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bHLE_BS2;
bVBeam, bSyncGPU, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bHLE_BS2;
int iTLBHack, iCPUCore;
std::string strBackend;
};
@ -95,6 +95,7 @@ bool BootCore(const std::string& _rFilename)
config_cache.bDCBZOFF = StartUp.bDCBZOFF;
config_cache.iTLBHack = StartUp.iTLBHack;
config_cache.bVBeam = StartUp.bVBeam;
config_cache.bSyncGPU = StartUp.bSyncGPU;
config_cache.bFastDiscSpeed = StartUp.bFastDiscSpeed;
config_cache.bMergeBlocks = StartUp.bMergeBlocks;
config_cache.bDSPHLE = StartUp.bDSPHLE;
@ -109,6 +110,7 @@ bool BootCore(const std::string& _rFilename)
game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack);
game_ini.Get("Core", "DCBZ", &StartUp.bDCBZOFF, StartUp.bDCBZOFF);
game_ini.Get("Core", "VBeam", &StartUp.bVBeam, StartUp.bVBeam);
game_ini.Get("Core", "SyncGPU", &StartUp.bSyncGPU, StartUp.bSyncGPU);
game_ini.Get("Core", "FastDiscSpeed", &StartUp.bFastDiscSpeed, StartUp.bFastDiscSpeed);
game_ini.Get("Core", "BlockMerging", &StartUp.bMergeBlocks, StartUp.bMergeBlocks);
game_ini.Get("Core", "DSPHLE", &StartUp.bDSPHLE, StartUp.bDSPHLE);
@ -168,6 +170,7 @@ void Stop()
StartUp.bDCBZOFF = config_cache.bDCBZOFF;
StartUp.iTLBHack = config_cache.iTLBHack;
StartUp.bVBeam = config_cache.bVBeam;
StartUp.bSyncGPU = config_cache.bSyncGPU;
StartUp.bFastDiscSpeed = config_cache.bFastDiscSpeed;
StartUp.bMergeBlocks = config_cache.bMergeBlocks;
StartUp.bDSPHLE = config_cache.bDSPHLE;

View File

@ -399,6 +399,7 @@ void SConfig::LoadSettings()
ini.Get("Core", "MMU", &m_LocalCoreStartupParameter.bMMU, false);
ini.Get("Core", "TLBHack", &m_LocalCoreStartupParameter.iTLBHack, 0);
ini.Get("Core", "VBeam", &m_LocalCoreStartupParameter.bVBeam, false);
ini.Get("Core", "SyncGPU", &m_LocalCoreStartupParameter.bSyncGPU, false);
ini.Get("Core", "FastDiscSpeed", &m_LocalCoreStartupParameter.bFastDiscSpeed, false);
ini.Get("Core", "DCBZ", &m_LocalCoreStartupParameter.bDCBZOFF, false);
ini.Get("Core", "FrameLimit", &m_Framelimit, 1); // auto frame limit by default

View File

@ -50,7 +50,7 @@ SCoreStartupParameter::SCoreStartupParameter()
bDPL2Decoder(false), iLatency(14),
bRunCompareServer(false), bRunCompareClient(false),
bMMU(false), bDCBZOFF(false), iTLBHack(0), bVBeam(false),
bFastDiscSpeed(false),
bSyncGPU(false), bFastDiscSpeed(false),
SelectedLanguage(0), bWii(false),
bConfirmStop(false), bHideCursor(false),
bAutoHideCursor(false), bUsePanicHandlers(true), bOnScreenDisplayMessages(true),
@ -78,6 +78,7 @@ void SCoreStartupParameter::LoadDefaults()
bDCBZOFF = false;
iTLBHack = 0;
bVBeam = false;
bSyncGPU = false;
bFastDiscSpeed = false;
bMergeBlocks = false;
SelectedLanguage = 0;

View File

@ -116,6 +116,7 @@ struct SCoreStartupParameter
bool bDCBZOFF;
int iTLBHack;
bool bVBeam;
bool bSyncGPU;
bool bFastDiscSpeed;
int SelectedLanguage;

View File

@ -74,6 +74,7 @@ IPC_HLE_PERIOD: For the Wiimote this is the call schedule:
#include "Thread.h"
#include "Timer.h"
#include "VideoBackendBase.h"
#include "CommandProcessor.h"
namespace SystemTimers
@ -110,6 +111,7 @@ int et_Dec;
int et_VI;
int et_SI;
int et_AI;
int et_CP;
int et_AudioDMA;
int et_DSP;
int et_IPC_HLE;
@ -127,6 +129,9 @@ int
// This is a fixed value, don't change it
AUDIO_DMA_PERIOD,
// Regulates the speed of the Command Processor
CP_PERIOD,
// This is completely arbitrary. If we find that we need lower latency, we can just
// increase this number.
IPC_HLE_PERIOD;
@ -187,6 +192,12 @@ void SICallback(u64 userdata, int cyclesLate)
CoreTiming::ScheduleEvent(SerialInterface::GetTicksToNextSIPoll() - cyclesLate, et_SI);
}
void CPCallback(u64 userdata, int cyclesLate)
{
CommandProcessor::Update();
CoreTiming::ScheduleEvent(CP_PERIOD - cyclesLate, et_CP);
}
void DecrementerCallback(u64 userdata, int cyclesLate)
{
PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
@ -272,6 +283,9 @@ void Init()
// System internal sample rate is fixed at 32KHz * 4 (16bit Stereo) / 32 bytes DMA
AUDIO_DMA_PERIOD = CPU_CORE_CLOCK / (AudioInterface::GetAIDSampleRate() * 4 / 32);
// Emulated gekko <-> flipper bus speed ratio (cpu clock / flipper clock)
CP_PERIOD = GetTicksPerSecond() / 10000;
Common::Timer::IncreaseResolution();
// store and convert localtime at boot to timebase ticks
CoreTiming::SetFakeTBStartValue((u64)(CPU_CORE_CLOCK / TIMER_RATIO) * (u64)CEXIIPL::GetGCTime());
@ -284,6 +298,8 @@ void Init()
et_AI = CoreTiming::RegisterEvent("AICallback", AICallback);
et_VI = CoreTiming::RegisterEvent("VICallback", VICallback);
et_SI = CoreTiming::RegisterEvent("SICallback", SICallback);
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU)
et_CP = CoreTiming::RegisterEvent("CPCallback", CPCallback);
et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback);
et_AudioDMA = CoreTiming::RegisterEvent("AudioDMACallback", AudioDMACallback);
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
@ -294,6 +310,8 @@ void Init()
CoreTiming::ScheduleEvent(DSP_PERIOD, et_DSP);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_SI);
CoreTiming::ScheduleEvent(AUDIO_DMA_PERIOD, et_AudioDMA);
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU)
CoreTiming::ScheduleEvent(CP_PERIOD, et_CP);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_PatchEngine);

View File

@ -321,6 +321,8 @@ void CISOProperties::CreateGUIControls(bool IsWad)
DCBZOFF->SetToolTip(_("Bypass the clearing of the data cache by the DCBZ instruction. Usually leave this option disabled."));
VBeam = new wxCheckBox(m_GameConfig, ID_VBEAM, _("Accurate VBeam emulation"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
VBeam->SetToolTip(_("If the FPS is erratic, this option may help. (ON = Compatible, OFF = Fast)"));
SyncGPU = new wxCheckBox(m_GameConfig, ID_SYNCGPU, _("Sychronise GPU thread"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
SyncGPU->SetToolTip(_("Synchonises the GPU and CPU threads to help prevent random freezes in Dual Core mode. (ON = Compatible, OFF = Fast)"));
FastDiscSpeed = new wxCheckBox(m_GameConfig, ID_DISCSPEED, _("Speed up Disc Transfer Rate"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
FastDiscSpeed->SetToolTip(_("Enable fast disc access. Needed for a few games. (ON = Fast, OFF = Compatible)"));
BlockMerging = new wxCheckBox(m_GameConfig, ID_MERGEBLOCKS, _("Enable Block Merging"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
@ -362,9 +364,10 @@ void CISOProperties::CreateGUIControls(bool IsWad)
sbCoreOverrides->Add(CPUThread, 0, wxLEFT, 5);
sbCoreOverrides->Add(SkipIdle, 0, wxLEFT, 5);
sbCoreOverrides->Add(MMU, 0, wxLEFT, 5);
sbCoreOverrides->Add(DCBZOFF, 0, wxLEFT, 5);
sbCoreOverrides->Add(TLBHack, 0, wxLEFT, 5);
sbCoreOverrides->Add(DCBZOFF, 0, wxLEFT, 5);
sbCoreOverrides->Add(VBeam, 0, wxLEFT, 5);
sbCoreOverrides->Add(SyncGPU, 0, wxLEFT, 5);
sbCoreOverrides->Add(FastDiscSpeed, 0, wxLEFT, 5);
sbCoreOverrides->Add(BlockMerging, 0, wxLEFT, 5);
sbCoreOverrides->Add(DSPHLE, 0, wxLEFT, 5);
@ -941,6 +944,11 @@ void CISOProperties::LoadGameConfig()
else
VBeam->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "SyncGPU", &bTemp))
SyncGPU->Set3StateValue((wxCheckBoxState)bTemp);
else
SyncGPU->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "FastDiscSpeed", &bTemp))
FastDiscSpeed->Set3StateValue((wxCheckBoxState)bTemp);
else
@ -1030,6 +1038,11 @@ bool CISOProperties::SaveGameConfig()
else
GameIni.Set("Core", "VBeam", VBeam->Get3StateValue());
if (SyncGPU->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "SyncGPU");
else
GameIni.Set("Core", "SyncGPU", SyncGPU->Get3StateValue());
if (FastDiscSpeed->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "FastDiscSpeed");
else

View File

@ -70,7 +70,7 @@ private:
// Core
wxCheckBox *CPUThread, *SkipIdle, *MMU, *DCBZOFF, *TLBHack;
wxCheckBox *VBeam, *FastDiscSpeed, *BlockMerging, *DSPHLE;
wxCheckBox *VBeam, *SyncGPU, *FastDiscSpeed, *BlockMerging, *DSPHLE;
// Wii
wxCheckBox *EnableWideScreen;
// Video
@ -130,6 +130,7 @@ private:
ID_DCBZOFF,
ID_TLBHACK,
ID_VBEAM,
ID_SYNCGPU,
ID_DISCSPEED,
ID_MERGEBLOCKS,
ID_AUDIO_DSP_HLE,

View File

@ -32,6 +32,8 @@
#include "HW/GPFifo.h"
#include "HW/Memmap.h"
#include "DLCache.h"
#include "HW/SystemTimers.h"
#include "Core.h"
namespace CommandProcessor
{
@ -64,6 +66,8 @@ volatile bool interruptTokenWaiting = false;
volatile bool interruptFinishWaiting = false;
volatile bool waitingForPEInterruptDisable = false;
volatile u32 VITicks = CommandProcessor::m_cpClockOrigin;
bool IsOnThread()
{
return SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread;
@ -464,7 +468,7 @@ void STACKALIGN GatherPipeBursted()
}
if (IsOnThread())
SetWatermarkFromGatherPipe();
SetCpStatus();
// update the fifo-pointer
if (fifo.CPWritePointer >= fifo.CPEnd)
@ -514,27 +518,6 @@ void AbortFrame()
}
void SetWatermarkFromGatherPipe()
{
fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark);
fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark);
isHiWatermarkActive = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt && m_CPCtrlReg.GPReadEnable;
isLoWatermarkActive = fifo.bFF_LoWatermark && fifo.bFF_LoWatermarkInt && m_CPCtrlReg.GPReadEnable;
if (isHiWatermarkActive)
{
interruptSet = true;
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true);
}
else if (isLoWatermarkActive)
{
interruptSet = true;
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true);
}
}
void SetCpStatus()
{
// overflow & underflow check
@ -542,30 +525,33 @@ void SetCpStatus()
fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark);
// breakpoint
if (fifo.bFF_BPEnable)
{
if (fifo.CPBreakpoint == fifo.CPReadPointer)
{
if (!fifo.bFF_Breakpoint)
if (Core::IsGPUThread())
{
if (fifo.bFF_BPEnable)
{
if (fifo.CPBreakpoint == fifo.CPReadPointer)
{
INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer);
fifo.bFF_Breakpoint = true;
IncrementCheckContextId();
if (!fifo.bFF_Breakpoint)
{
INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer);
fifo.bFF_Breakpoint = true;
IncrementCheckContextId();
}
}
}
else
{
if (fifo.bFF_Breakpoint)
INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer);
fifo.bFF_Breakpoint = false;
}
}
else
{
if (fifo.bFF_Breakpoint)
INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer);
fifo.bFF_Breakpoint = false;
fifo.bFF_Breakpoint = false;
}
}
else
{
if (fifo.bFF_Breakpoint)
INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer);
fifo.bFF_Breakpoint = false;
}
}
bool bpInt = fifo.bFF_Breakpoint && fifo.bFF_BPInt;
bool ovfInt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt;
@ -581,10 +567,19 @@ void SetCpStatus()
u64 userdata = interrupt?1:0;
if (IsOnThread())
{
if(!interrupt || bpInt || undfInt)
if(!interrupt || bpInt || undfInt || ovfInt)
{
interruptWaiting = true;
CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
if (Core::IsGPUThread())
{
interruptWaiting = true;
CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
}
else if (Core::IsCPUThread())
{
interruptSet = interrupt;
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, interrupt);
}
}
}
else
@ -608,7 +603,7 @@ void ProcessFifoAllDistance()
if (IsOnThread())
{
while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt())
fifo.CPReadWriteDistance && !AtBreakpoint())
Common::YieldCPU();
}
bProcessFifoAllDistance = false;
@ -629,8 +624,8 @@ void SetCpStatusRegister()
{
// Here always there is one fifo attached to the GPU
m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint;
m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint) ;
m_CPStatusReg.CommandIdle = !fifo.isGpuReadingData;
m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || AtBreakpoint() || (fifo.CPReadPointer == fifo.CPWritePointer);
m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance || AtBreakpoint() || !fifo.bFF_GPReadEnable;
m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark;
m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark;
@ -701,4 +696,12 @@ void SetCpClearRegister()
// }
}
void Update()
{
while (VITicks > m_cpClockOrigin && fifo.isGpuReadingData && IsOnThread())
Common::YieldCPU();
if (fifo.isGpuReadingData)
Common::AtomicAdd(VITicks, SystemTimers::GetTicksPerSecond() / 10000);
}
} // end of namespace CommandProcessor

View File

@ -141,6 +141,9 @@ 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();
@ -162,11 +165,14 @@ bool AllowIdleSkipping();
void SetCpClearRegister();
void SetCpControlRegister();
void SetCpStatusRegister();
void SetWatermarkFromGatherPipe();
void ProcessFifoToLoWatermark();
void ProcessFifoAllDistance();
void ProcessFifoEvents();
void AbortFrame();
void Update();
extern volatile u32 VITicks;
} // namespace CommandProcessor
#endif // _COMMANDPROCESSOR_H

View File

@ -26,6 +26,7 @@
#include "Fifo.h"
#include "HW/Memmap.h"
#include "Core.h"
#include "CoreTiming.h"
volatile bool g_bSkipCurrentFrame = false;
extern u8* g_pVideoData;
@ -72,6 +73,7 @@ void Fifo_Init()
videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE);
size = 0;
GpuRunningState = false;
Common::AtomicStore(CommandProcessor::VITicks, CommandProcessor::m_cpClockOrigin);
}
void Fifo_Shutdown()
@ -123,7 +125,7 @@ void ReadDataFromFifo(u8* _uData, u32 len)
size -= pos;
if (size + len > FIFO_SIZE)
{
PanicAlert("FIFO out of bounds (sz = %i, at %08x)", size, pos);
PanicAlert("FIFO out of bounds (sz = %i, len = %i at %08x)", size, len, pos);
}
memmove(&videoBuffer[0], &videoBuffer[pos], size);
g_pVideoData = videoBuffer;
@ -147,6 +149,7 @@ void RunGpuLoop()
std::lock_guard<std::mutex> lk(m_csHWVidOccupied);
GpuRunningState = true;
SCPFifoStruct &fifo = CommandProcessor::fifo;
u32 cyclesExecuted = 0;
while (GpuRunningState)
{
@ -156,6 +159,8 @@ void RunGpuLoop()
CommandProcessor::SetCpStatus();
Common::AtomicStore(CommandProcessor::VITicks, CommandProcessor::m_cpClockOrigin);
// check if we are able to run this buffer
while (GpuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint())
{
@ -163,24 +168,30 @@ void RunGpuLoop()
fifo.isGpuReadingData = true;
CommandProcessor::isPossibleWaitingSetDrawDone = fifo.bFF_GPLinkEnable ? true : false;
u32 readPtr = fifo.CPReadPointer;
u8 *uData = Memory::GetPointer(readPtr);
if (readPtr == fifo.CPEnd) readPtr = fifo.CPBase;
if (Common::AtomicLoad(CommandProcessor::VITicks) > CommandProcessor::m_cpClockOrigin || !Core::g_CoreStartupParameter.bSyncGPU)
{
u32 readPtr = fifo.CPReadPointer;
u8 *uData = Memory::GetPointer(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 inestabilty in the game. Please report it.", fifo.CPReadWriteDistance - 32);
ReadDataFromFifo(uData, 32);
OpcodeDecoder_Run(g_bSkipCurrentFrame);
Common::AtomicStore(fifo.CPReadPointer, readPtr);
Common::AtomicAdd(fifo.CPReadWriteDistance, -32);
if((GetVideoBufferEndPtr() - g_pVideoData) == 0)
Common::AtomicStore(fifo.SafeCPReadPointer, fifo.CPReadPointer);
_assert_msg_(COMMANDPROCESSOR, (s32)fifo.CPReadWriteDistance - 32 >= 0 ,
"Negative fifo.CPReadWriteDistance = %i in FIFO Loop !\nThat can produce instabilty in the game. Please report it.", fifo.CPReadWriteDistance - 32);
ReadDataFromFifo(uData, 32);
cyclesExecuted = OpcodeDecoder_Run(g_bSkipCurrentFrame);
if (Common::AtomicLoad(CommandProcessor::VITicks) > cyclesExecuted && Core::g_CoreStartupParameter.bSyncGPU)
Common::AtomicAdd(CommandProcessor::VITicks, -(s32)cyclesExecuted);
Common::AtomicStore(fifo.CPReadPointer, readPtr);
Common::AtomicAdd(fifo.CPReadWriteDistance, -32);
if((GetVideoBufferEndPtr() - g_pVideoData) == 0)
Common::AtomicStore(fifo.SafeCPReadPointer, fifo.CPReadPointer);
}
CommandProcessor::SetCpStatus();
@ -190,7 +201,7 @@ void RunGpuLoop()
VideoFifo_CheckAsyncRequest();
CommandProcessor::isPossibleWaitingSetDrawDone = false;
}
fifo.isGpuReadingData = false;
@ -219,23 +230,23 @@ bool AtBreakpoint()
void RunGpu()
{
SCPFifoStruct &fifo = CommandProcessor::fifo;
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() )
{
u8 *uData = Memory::GetPointer(fifo.CPReadPointer);
SCPFifoStruct &fifo = CommandProcessor::fifo;
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() )
{
u8 *uData = Memory::GetPointer(fifo.CPReadPointer);
SaveSSEState();
LoadDefaultSSEState();
ReadDataFromFifo(uData, 32);
OpcodeDecoder_Run(g_bSkipCurrentFrame);
LoadSSEState();
SaveSSEState();
LoadDefaultSSEState();
ReadDataFromFifo(uData, 32);
u32 count = OpcodeDecoder_Run(g_bSkipCurrentFrame);
LoadSSEState();
//DEBUG_LOG(COMMANDPROCESSOR, "Fifo wraps to base");
//DEBUG_LOG(COMMANDPROCESSOR, "Fifo wraps to base");
if (fifo.CPReadPointer == fifo.CPEnd) fifo.CPReadPointer = fifo.CPBase;
else fifo.CPReadPointer += 32;
if (fifo.CPReadPointer == fifo.CPEnd) fifo.CPReadPointer = fifo.CPBase;
else fifo.CPReadPointer += 32;
fifo.CPReadWriteDistance -= 32;
}
CommandProcessor::SetCpStatus();
fifo.CPReadWriteDistance -= 32;
}
CommandProcessor::SetCpStatus();
}

View File

@ -136,29 +136,38 @@ void ExecuteDisplayList(u32 address, u32 size)
InterpretDisplayList(address, size);
}
bool FifoCommandRunnable()
u32 FifoCommandRunnable(u32 &command_size)
{
u32 cycleTime = 0;
u32 buffer_size = (u32)(GetVideoBufferEndPtr() - g_pVideoData);
if (buffer_size == 0)
return false; // can't peek
return 0; // can't peek
u8 cmd_byte = DataPeek8(0);
u32 command_size = 0;
switch (cmd_byte)
{
case GX_NOP: // Hm, this means that we scan over nop streams pretty slowly...
command_size = 1;
cycleTime = 6;
break;
case GX_CMD_INVL_VC: // Invalidate Vertex Cache - no parameters
command_size = 1;
cycleTime = 6;
break;
case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that
command_size = 1;
cycleTime = 6;
break;
case GX_LOAD_BP_REG:
command_size = 5;
cycleTime = 12;
break;
case GX_LOAD_CP_REG:
command_size = 6;
cycleTime = 12;
break;
case GX_LOAD_INDX_A:
@ -166,10 +175,39 @@ bool FifoCommandRunnable()
case GX_LOAD_INDX_C:
case GX_LOAD_INDX_D:
command_size = 5;
cycleTime = 6; // TODO
break;
case GX_CMD_CALL_DL:
command_size = 9;
case GX_CMD_CALL_DL:
{
// FIXME: Calculate the cycle time of the display list.
//u32 address = DataPeek32(1);
//u32 size = DataPeek32(5);
//u8* old_pVideoData = g_pVideoData;
//u8* startAddress = Memory::GetPointer(address);
//// Avoid the crash if Memory::GetPointer failed ..
//if (startAddress != 0)
//{
// g_pVideoData = startAddress;
// u8 *end = g_pVideoData + size;
// u32 step = 0;
// while (g_pVideoData < end)
// {
// cycleTime += FifoCommandRunnable(step);
// g_pVideoData += step;
// }
//}
//else
//{
// cycleTime = 45;
//}
//// reset to the old pointer
//g_pVideoData = old_pVideoData;
command_size = 9;
cycleTime = 45; // This is unverified
}
break;
case GX_LOAD_XF_REG:
@ -180,11 +218,12 @@ bool FifoCommandRunnable()
command_size = 1 + 4;
u32 Cmd2 = DataPeek32(1);
int transfer_size = ((Cmd2 >> 16) & 15) + 1;
command_size += transfer_size * 4;
command_size += transfer_size * 4;
cycleTime = 18 + 6 * transfer_size;
}
else
{
return false;
return 0;
}
}
break;
@ -198,10 +237,11 @@ bool FifoCommandRunnable()
command_size = 1 + 2;
u16 numVertices = DataPeek16(1);
command_size += numVertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK);
cycleTime = 12 * numVertices; // This depends on the number of pixels rendered
}
else
{
return false;
return 0;
}
}
else
@ -248,11 +288,19 @@ bool FifoCommandRunnable()
}
if (command_size > buffer_size)
return false;
return 0;
// INFO_LOG("OP detected: cmd_byte 0x%x size %i buffer %i",cmd_byte, command_size, buffer_size);
if (cycleTime == 0)
cycleTime = 6;
return true;
return cycleTime;
}
u32 FifoCommandRunnable()
{
u32 command_size = 0;
return FifoCommandRunnable(command_size);
}
static void Decode()
@ -461,16 +509,15 @@ void OpcodeDecoder_Shutdown()
}
}
void OpcodeDecoder_Run(bool skipped_frame)
u32 OpcodeDecoder_Run(bool skipped_frame)
{
if (!skipped_frame)
u32 totalCycles = 0;
u32 cycles = FifoCommandRunnable();
while (cycles > 0)
{
while (FifoCommandRunnable())
Decode();
}
else
{
while (FifoCommandRunnable())
DecodeSemiNop();
skipped_frame ? DecodeSemiNop() : Decode();
totalCycles += cycles;
cycles = FifoCommandRunnable();
}
return totalCycles;
}

View File

@ -50,6 +50,6 @@ extern bool g_bRecordFifoData;
void OpcodeDecoder_Init();
void OpcodeDecoder_Shutdown();
void OpcodeDecoder_Run(bool skipped_frame);
u32 OpcodeDecoder_Run(bool skipped_frame);
void ExecuteDisplayList(u32 address, u32 size);
#endif // _OPCODE_DECODING_H

View File

@ -450,9 +450,4 @@ void ResetSetToken()
}
CommandProcessor::interruptTokenWaiting = false;
}
bool WaitingForPEInterrupt()
{
return !CommandProcessor::waitingForPEInterruptDisable && (CommandProcessor::interruptFinishWaiting || CommandProcessor::interruptTokenWaiting || Common::AtomicLoad(interruptSetFinish) || Common::AtomicLoad(interruptSetToken));
}
} // end of namespace PixelEngine

View File

@ -80,7 +80,6 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge);
void SetFinish(void);
void ResetSetFinish(void);
void ResetSetToken(void);
bool WaitingForPEInterrupt();
// Bounding box functionality. Paper Mario (both) are a couple of the few games that use it.
extern u16 bbox[4];