mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
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:
@ -1,5 +1,6 @@
|
|||||||
# GKBEAF - Baten Kaitos
|
# GKBEAF - Baten Kaitos
|
||||||
[Core] Values set here will override the main dolphin settings.
|
[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.
|
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||||
EmulationStateId = 4
|
EmulationStateId = 4
|
||||||
EmulationIssues =
|
EmulationIssues =
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# GKBPAF - Baten Kaitos
|
# GKBPAF - Baten Kaitos
|
||||||
[Core] Values set here will override the main dolphin settings.
|
[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.
|
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||||
EmulationStateId = 4
|
EmulationStateId = 4
|
||||||
EmulationIssues =
|
EmulationIssues =
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
# GLSE64 - LucasArts Gladius
|
# GLSE64 - LucasArts Gladius
|
||||||
[Core] Values set here will override the main dolphin settings.
|
[Core] Values set here will override the main dolphin settings.
|
||||||
TLBHack = 1
|
TLBHack = 1
|
||||||
|
SyncGPU = 1
|
||||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||||
EmulationStateId = 1
|
EmulationStateId = 4
|
||||||
EmulationIssues =
|
EmulationIssues =
|
||||||
[OnFrame] Add memory patches to be applied every frame here.
|
[OnFrame] Add memory patches to be applied every frame here.
|
||||||
[ActionReplay] Add action replay cheats here.
|
[ActionReplay] Add action replay cheats here.
|
||||||
|
@ -55,7 +55,7 @@ namespace BootManager
|
|||||||
struct ConfigCache
|
struct ConfigCache
|
||||||
{
|
{
|
||||||
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF,
|
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF,
|
||||||
bVBeam, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bHLE_BS2;
|
bVBeam, bSyncGPU, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bHLE_BS2;
|
||||||
int iTLBHack, iCPUCore;
|
int iTLBHack, iCPUCore;
|
||||||
std::string strBackend;
|
std::string strBackend;
|
||||||
};
|
};
|
||||||
@ -95,6 +95,7 @@ bool BootCore(const std::string& _rFilename)
|
|||||||
config_cache.bDCBZOFF = StartUp.bDCBZOFF;
|
config_cache.bDCBZOFF = StartUp.bDCBZOFF;
|
||||||
config_cache.iTLBHack = StartUp.iTLBHack;
|
config_cache.iTLBHack = StartUp.iTLBHack;
|
||||||
config_cache.bVBeam = StartUp.bVBeam;
|
config_cache.bVBeam = StartUp.bVBeam;
|
||||||
|
config_cache.bSyncGPU = StartUp.bSyncGPU;
|
||||||
config_cache.bFastDiscSpeed = StartUp.bFastDiscSpeed;
|
config_cache.bFastDiscSpeed = StartUp.bFastDiscSpeed;
|
||||||
config_cache.bMergeBlocks = StartUp.bMergeBlocks;
|
config_cache.bMergeBlocks = StartUp.bMergeBlocks;
|
||||||
config_cache.bDSPHLE = StartUp.bDSPHLE;
|
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", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack);
|
||||||
game_ini.Get("Core", "DCBZ", &StartUp.bDCBZOFF, StartUp.bDCBZOFF);
|
game_ini.Get("Core", "DCBZ", &StartUp.bDCBZOFF, StartUp.bDCBZOFF);
|
||||||
game_ini.Get("Core", "VBeam", &StartUp.bVBeam, StartUp.bVBeam);
|
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", "FastDiscSpeed", &StartUp.bFastDiscSpeed, StartUp.bFastDiscSpeed);
|
||||||
game_ini.Get("Core", "BlockMerging", &StartUp.bMergeBlocks, StartUp.bMergeBlocks);
|
game_ini.Get("Core", "BlockMerging", &StartUp.bMergeBlocks, StartUp.bMergeBlocks);
|
||||||
game_ini.Get("Core", "DSPHLE", &StartUp.bDSPHLE, StartUp.bDSPHLE);
|
game_ini.Get("Core", "DSPHLE", &StartUp.bDSPHLE, StartUp.bDSPHLE);
|
||||||
@ -168,6 +170,7 @@ void Stop()
|
|||||||
StartUp.bDCBZOFF = config_cache.bDCBZOFF;
|
StartUp.bDCBZOFF = config_cache.bDCBZOFF;
|
||||||
StartUp.iTLBHack = config_cache.iTLBHack;
|
StartUp.iTLBHack = config_cache.iTLBHack;
|
||||||
StartUp.bVBeam = config_cache.bVBeam;
|
StartUp.bVBeam = config_cache.bVBeam;
|
||||||
|
StartUp.bSyncGPU = config_cache.bSyncGPU;
|
||||||
StartUp.bFastDiscSpeed = config_cache.bFastDiscSpeed;
|
StartUp.bFastDiscSpeed = config_cache.bFastDiscSpeed;
|
||||||
StartUp.bMergeBlocks = config_cache.bMergeBlocks;
|
StartUp.bMergeBlocks = config_cache.bMergeBlocks;
|
||||||
StartUp.bDSPHLE = config_cache.bDSPHLE;
|
StartUp.bDSPHLE = config_cache.bDSPHLE;
|
||||||
|
@ -399,6 +399,7 @@ void SConfig::LoadSettings()
|
|||||||
ini.Get("Core", "MMU", &m_LocalCoreStartupParameter.bMMU, false);
|
ini.Get("Core", "MMU", &m_LocalCoreStartupParameter.bMMU, false);
|
||||||
ini.Get("Core", "TLBHack", &m_LocalCoreStartupParameter.iTLBHack, 0);
|
ini.Get("Core", "TLBHack", &m_LocalCoreStartupParameter.iTLBHack, 0);
|
||||||
ini.Get("Core", "VBeam", &m_LocalCoreStartupParameter.bVBeam, false);
|
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", "FastDiscSpeed", &m_LocalCoreStartupParameter.bFastDiscSpeed, false);
|
||||||
ini.Get("Core", "DCBZ", &m_LocalCoreStartupParameter.bDCBZOFF, false);
|
ini.Get("Core", "DCBZ", &m_LocalCoreStartupParameter.bDCBZOFF, false);
|
||||||
ini.Get("Core", "FrameLimit", &m_Framelimit, 1); // auto frame limit by default
|
ini.Get("Core", "FrameLimit", &m_Framelimit, 1); // auto frame limit by default
|
||||||
|
@ -50,7 +50,7 @@ SCoreStartupParameter::SCoreStartupParameter()
|
|||||||
bDPL2Decoder(false), iLatency(14),
|
bDPL2Decoder(false), iLatency(14),
|
||||||
bRunCompareServer(false), bRunCompareClient(false),
|
bRunCompareServer(false), bRunCompareClient(false),
|
||||||
bMMU(false), bDCBZOFF(false), iTLBHack(0), bVBeam(false),
|
bMMU(false), bDCBZOFF(false), iTLBHack(0), bVBeam(false),
|
||||||
bFastDiscSpeed(false),
|
bSyncGPU(false), bFastDiscSpeed(false),
|
||||||
SelectedLanguage(0), bWii(false),
|
SelectedLanguage(0), bWii(false),
|
||||||
bConfirmStop(false), bHideCursor(false),
|
bConfirmStop(false), bHideCursor(false),
|
||||||
bAutoHideCursor(false), bUsePanicHandlers(true), bOnScreenDisplayMessages(true),
|
bAutoHideCursor(false), bUsePanicHandlers(true), bOnScreenDisplayMessages(true),
|
||||||
@ -78,6 +78,7 @@ void SCoreStartupParameter::LoadDefaults()
|
|||||||
bDCBZOFF = false;
|
bDCBZOFF = false;
|
||||||
iTLBHack = 0;
|
iTLBHack = 0;
|
||||||
bVBeam = false;
|
bVBeam = false;
|
||||||
|
bSyncGPU = false;
|
||||||
bFastDiscSpeed = false;
|
bFastDiscSpeed = false;
|
||||||
bMergeBlocks = false;
|
bMergeBlocks = false;
|
||||||
SelectedLanguage = 0;
|
SelectedLanguage = 0;
|
||||||
|
@ -116,6 +116,7 @@ struct SCoreStartupParameter
|
|||||||
bool bDCBZOFF;
|
bool bDCBZOFF;
|
||||||
int iTLBHack;
|
int iTLBHack;
|
||||||
bool bVBeam;
|
bool bVBeam;
|
||||||
|
bool bSyncGPU;
|
||||||
bool bFastDiscSpeed;
|
bool bFastDiscSpeed;
|
||||||
|
|
||||||
int SelectedLanguage;
|
int SelectedLanguage;
|
||||||
|
@ -74,6 +74,7 @@ IPC_HLE_PERIOD: For the Wiimote this is the call schedule:
|
|||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "VideoBackendBase.h"
|
#include "VideoBackendBase.h"
|
||||||
|
#include "CommandProcessor.h"
|
||||||
|
|
||||||
|
|
||||||
namespace SystemTimers
|
namespace SystemTimers
|
||||||
@ -110,6 +111,7 @@ int et_Dec;
|
|||||||
int et_VI;
|
int et_VI;
|
||||||
int et_SI;
|
int et_SI;
|
||||||
int et_AI;
|
int et_AI;
|
||||||
|
int et_CP;
|
||||||
int et_AudioDMA;
|
int et_AudioDMA;
|
||||||
int et_DSP;
|
int et_DSP;
|
||||||
int et_IPC_HLE;
|
int et_IPC_HLE;
|
||||||
@ -127,6 +129,9 @@ int
|
|||||||
// This is a fixed value, don't change it
|
// This is a fixed value, don't change it
|
||||||
AUDIO_DMA_PERIOD,
|
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
|
// This is completely arbitrary. If we find that we need lower latency, we can just
|
||||||
// increase this number.
|
// increase this number.
|
||||||
IPC_HLE_PERIOD;
|
IPC_HLE_PERIOD;
|
||||||
@ -187,6 +192,12 @@ void SICallback(u64 userdata, int cyclesLate)
|
|||||||
CoreTiming::ScheduleEvent(SerialInterface::GetTicksToNextSIPoll() - cyclesLate, et_SI);
|
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)
|
void DecrementerCallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
|
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
|
// System internal sample rate is fixed at 32KHz * 4 (16bit Stereo) / 32 bytes DMA
|
||||||
AUDIO_DMA_PERIOD = CPU_CORE_CLOCK / (AudioInterface::GetAIDSampleRate() * 4 / 32);
|
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();
|
Common::Timer::IncreaseResolution();
|
||||||
// store and convert localtime at boot to timebase ticks
|
// store and convert localtime at boot to timebase ticks
|
||||||
CoreTiming::SetFakeTBStartValue((u64)(CPU_CORE_CLOCK / TIMER_RATIO) * (u64)CEXIIPL::GetGCTime());
|
CoreTiming::SetFakeTBStartValue((u64)(CPU_CORE_CLOCK / TIMER_RATIO) * (u64)CEXIIPL::GetGCTime());
|
||||||
@ -284,6 +298,8 @@ void Init()
|
|||||||
et_AI = CoreTiming::RegisterEvent("AICallback", AICallback);
|
et_AI = CoreTiming::RegisterEvent("AICallback", AICallback);
|
||||||
et_VI = CoreTiming::RegisterEvent("VICallback", VICallback);
|
et_VI = CoreTiming::RegisterEvent("VICallback", VICallback);
|
||||||
et_SI = CoreTiming::RegisterEvent("SICallback", SICallback);
|
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_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback);
|
||||||
et_AudioDMA = CoreTiming::RegisterEvent("AudioDMACallback", AudioDMACallback);
|
et_AudioDMA = CoreTiming::RegisterEvent("AudioDMACallback", AudioDMACallback);
|
||||||
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
|
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(DSP_PERIOD, et_DSP);
|
||||||
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_SI);
|
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_SI);
|
||||||
CoreTiming::ScheduleEvent(AUDIO_DMA_PERIOD, et_AudioDMA);
|
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);
|
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_PatchEngine);
|
||||||
|
|
||||||
|
@ -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."));
|
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 = 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)"));
|
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 = 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)"));
|
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);
|
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(CPUThread, 0, wxLEFT, 5);
|
||||||
sbCoreOverrides->Add(SkipIdle, 0, wxLEFT, 5);
|
sbCoreOverrides->Add(SkipIdle, 0, wxLEFT, 5);
|
||||||
sbCoreOverrides->Add(MMU, 0, wxLEFT, 5);
|
sbCoreOverrides->Add(MMU, 0, wxLEFT, 5);
|
||||||
sbCoreOverrides->Add(DCBZOFF, 0, wxLEFT, 5);
|
|
||||||
sbCoreOverrides->Add(TLBHack, 0, wxLEFT, 5);
|
sbCoreOverrides->Add(TLBHack, 0, wxLEFT, 5);
|
||||||
|
sbCoreOverrides->Add(DCBZOFF, 0, wxLEFT, 5);
|
||||||
sbCoreOverrides->Add(VBeam, 0, wxLEFT, 5);
|
sbCoreOverrides->Add(VBeam, 0, wxLEFT, 5);
|
||||||
|
sbCoreOverrides->Add(SyncGPU, 0, wxLEFT, 5);
|
||||||
sbCoreOverrides->Add(FastDiscSpeed, 0, wxLEFT, 5);
|
sbCoreOverrides->Add(FastDiscSpeed, 0, wxLEFT, 5);
|
||||||
sbCoreOverrides->Add(BlockMerging, 0, wxLEFT, 5);
|
sbCoreOverrides->Add(BlockMerging, 0, wxLEFT, 5);
|
||||||
sbCoreOverrides->Add(DSPHLE, 0, wxLEFT, 5);
|
sbCoreOverrides->Add(DSPHLE, 0, wxLEFT, 5);
|
||||||
@ -941,6 +944,11 @@ void CISOProperties::LoadGameConfig()
|
|||||||
else
|
else
|
||||||
VBeam->Set3StateValue(wxCHK_UNDETERMINED);
|
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))
|
if (GameIni.Get("Core", "FastDiscSpeed", &bTemp))
|
||||||
FastDiscSpeed->Set3StateValue((wxCheckBoxState)bTemp);
|
FastDiscSpeed->Set3StateValue((wxCheckBoxState)bTemp);
|
||||||
else
|
else
|
||||||
@ -1030,6 +1038,11 @@ bool CISOProperties::SaveGameConfig()
|
|||||||
else
|
else
|
||||||
GameIni.Set("Core", "VBeam", VBeam->Get3StateValue());
|
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)
|
if (FastDiscSpeed->Get3StateValue() == wxCHK_UNDETERMINED)
|
||||||
GameIni.DeleteKey("Core", "FastDiscSpeed");
|
GameIni.DeleteKey("Core", "FastDiscSpeed");
|
||||||
else
|
else
|
||||||
|
@ -70,7 +70,7 @@ private:
|
|||||||
|
|
||||||
// Core
|
// Core
|
||||||
wxCheckBox *CPUThread, *SkipIdle, *MMU, *DCBZOFF, *TLBHack;
|
wxCheckBox *CPUThread, *SkipIdle, *MMU, *DCBZOFF, *TLBHack;
|
||||||
wxCheckBox *VBeam, *FastDiscSpeed, *BlockMerging, *DSPHLE;
|
wxCheckBox *VBeam, *SyncGPU, *FastDiscSpeed, *BlockMerging, *DSPHLE;
|
||||||
// Wii
|
// Wii
|
||||||
wxCheckBox *EnableWideScreen;
|
wxCheckBox *EnableWideScreen;
|
||||||
// Video
|
// Video
|
||||||
@ -130,6 +130,7 @@ private:
|
|||||||
ID_DCBZOFF,
|
ID_DCBZOFF,
|
||||||
ID_TLBHACK,
|
ID_TLBHACK,
|
||||||
ID_VBEAM,
|
ID_VBEAM,
|
||||||
|
ID_SYNCGPU,
|
||||||
ID_DISCSPEED,
|
ID_DISCSPEED,
|
||||||
ID_MERGEBLOCKS,
|
ID_MERGEBLOCKS,
|
||||||
ID_AUDIO_DSP_HLE,
|
ID_AUDIO_DSP_HLE,
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
#include "HW/GPFifo.h"
|
#include "HW/GPFifo.h"
|
||||||
#include "HW/Memmap.h"
|
#include "HW/Memmap.h"
|
||||||
#include "DLCache.h"
|
#include "DLCache.h"
|
||||||
|
#include "HW/SystemTimers.h"
|
||||||
|
#include "Core.h"
|
||||||
|
|
||||||
namespace CommandProcessor
|
namespace CommandProcessor
|
||||||
{
|
{
|
||||||
@ -64,6 +66,8 @@ volatile bool interruptTokenWaiting = false;
|
|||||||
volatile bool interruptFinishWaiting = false;
|
volatile bool interruptFinishWaiting = false;
|
||||||
volatile bool waitingForPEInterruptDisable = false;
|
volatile bool waitingForPEInterruptDisable = false;
|
||||||
|
|
||||||
|
volatile u32 VITicks = CommandProcessor::m_cpClockOrigin;
|
||||||
|
|
||||||
bool IsOnThread()
|
bool IsOnThread()
|
||||||
{
|
{
|
||||||
return SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread;
|
return SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread;
|
||||||
@ -464,7 +468,7 @@ void STACKALIGN GatherPipeBursted()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (IsOnThread())
|
if (IsOnThread())
|
||||||
SetWatermarkFromGatherPipe();
|
SetCpStatus();
|
||||||
|
|
||||||
// update the fifo-pointer
|
// update the fifo-pointer
|
||||||
if (fifo.CPWritePointer >= fifo.CPEnd)
|
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()
|
void SetCpStatus()
|
||||||
{
|
{
|
||||||
// overflow & underflow check
|
// overflow & underflow check
|
||||||
@ -542,30 +525,33 @@ void SetCpStatus()
|
|||||||
fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark);
|
fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark);
|
||||||
|
|
||||||
// breakpoint
|
// breakpoint
|
||||||
if (fifo.bFF_BPEnable)
|
if (Core::IsGPUThread())
|
||||||
{
|
{
|
||||||
if (fifo.CPBreakpoint == fifo.CPReadPointer)
|
if (fifo.bFF_BPEnable)
|
||||||
{
|
{
|
||||||
if (!fifo.bFF_Breakpoint)
|
if (fifo.CPBreakpoint == fifo.CPReadPointer)
|
||||||
{
|
{
|
||||||
INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer);
|
if (!fifo.bFF_Breakpoint)
|
||||||
fifo.bFF_Breakpoint = true;
|
{
|
||||||
IncrementCheckContextId();
|
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
|
else
|
||||||
{
|
{
|
||||||
if (fifo.bFF_Breakpoint)
|
if (fifo.bFF_Breakpoint)
|
||||||
INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer);
|
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 bpInt = fifo.bFF_Breakpoint && fifo.bFF_BPInt;
|
||||||
bool ovfInt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt;
|
bool ovfInt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt;
|
||||||
@ -581,10 +567,19 @@ void SetCpStatus()
|
|||||||
u64 userdata = interrupt?1:0;
|
u64 userdata = interrupt?1:0;
|
||||||
if (IsOnThread())
|
if (IsOnThread())
|
||||||
{
|
{
|
||||||
if(!interrupt || bpInt || undfInt)
|
if(!interrupt || bpInt || undfInt || ovfInt)
|
||||||
{
|
{
|
||||||
interruptWaiting = true;
|
if (Core::IsGPUThread())
|
||||||
CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
|
{
|
||||||
|
interruptWaiting = true;
|
||||||
|
CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
|
||||||
|
}
|
||||||
|
else if (Core::IsCPUThread())
|
||||||
|
{
|
||||||
|
interruptSet = interrupt;
|
||||||
|
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
|
||||||
|
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, interrupt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -608,7 +603,7 @@ void ProcessFifoAllDistance()
|
|||||||
if (IsOnThread())
|
if (IsOnThread())
|
||||||
{
|
{
|
||||||
while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
|
while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
|
||||||
fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt())
|
fifo.CPReadWriteDistance && !AtBreakpoint())
|
||||||
Common::YieldCPU();
|
Common::YieldCPU();
|
||||||
}
|
}
|
||||||
bProcessFifoAllDistance = false;
|
bProcessFifoAllDistance = false;
|
||||||
@ -629,8 +624,8 @@ void SetCpStatusRegister()
|
|||||||
{
|
{
|
||||||
// Here always there is one fifo attached to the GPU
|
// Here always there is one fifo attached to the GPU
|
||||||
m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint;
|
m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint;
|
||||||
m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint) ;
|
m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || AtBreakpoint() || (fifo.CPReadPointer == fifo.CPWritePointer);
|
||||||
m_CPStatusReg.CommandIdle = !fifo.isGpuReadingData;
|
m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance || AtBreakpoint() || !fifo.bFF_GPReadEnable;
|
||||||
m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark;
|
m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark;
|
||||||
m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark;
|
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
|
} // end of namespace CommandProcessor
|
||||||
|
@ -141,6 +141,9 @@ union UCPClearReg
|
|||||||
UCPClearReg(u16 _hex) {Hex = _hex; }
|
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
|
// Init
|
||||||
void Init();
|
void Init();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
@ -162,11 +165,14 @@ bool AllowIdleSkipping();
|
|||||||
void SetCpClearRegister();
|
void SetCpClearRegister();
|
||||||
void SetCpControlRegister();
|
void SetCpControlRegister();
|
||||||
void SetCpStatusRegister();
|
void SetCpStatusRegister();
|
||||||
void SetWatermarkFromGatherPipe();
|
|
||||||
void ProcessFifoToLoWatermark();
|
void ProcessFifoToLoWatermark();
|
||||||
void ProcessFifoAllDistance();
|
void ProcessFifoAllDistance();
|
||||||
void ProcessFifoEvents();
|
void ProcessFifoEvents();
|
||||||
void AbortFrame();
|
void AbortFrame();
|
||||||
|
|
||||||
|
void Update();
|
||||||
|
extern volatile u32 VITicks;
|
||||||
|
|
||||||
} // namespace CommandProcessor
|
} // namespace CommandProcessor
|
||||||
|
|
||||||
#endif // _COMMANDPROCESSOR_H
|
#endif // _COMMANDPROCESSOR_H
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "Fifo.h"
|
#include "Fifo.h"
|
||||||
#include "HW/Memmap.h"
|
#include "HW/Memmap.h"
|
||||||
#include "Core.h"
|
#include "Core.h"
|
||||||
|
#include "CoreTiming.h"
|
||||||
|
|
||||||
volatile bool g_bSkipCurrentFrame = false;
|
volatile bool g_bSkipCurrentFrame = false;
|
||||||
extern u8* g_pVideoData;
|
extern u8* g_pVideoData;
|
||||||
@ -72,6 +73,7 @@ void Fifo_Init()
|
|||||||
videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE);
|
videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE);
|
||||||
size = 0;
|
size = 0;
|
||||||
GpuRunningState = false;
|
GpuRunningState = false;
|
||||||
|
Common::AtomicStore(CommandProcessor::VITicks, CommandProcessor::m_cpClockOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fifo_Shutdown()
|
void Fifo_Shutdown()
|
||||||
@ -123,7 +125,7 @@ void ReadDataFromFifo(u8* _uData, u32 len)
|
|||||||
size -= pos;
|
size -= pos;
|
||||||
if (size + len > FIFO_SIZE)
|
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);
|
memmove(&videoBuffer[0], &videoBuffer[pos], size);
|
||||||
g_pVideoData = videoBuffer;
|
g_pVideoData = videoBuffer;
|
||||||
@ -147,6 +149,7 @@ void RunGpuLoop()
|
|||||||
std::lock_guard<std::mutex> lk(m_csHWVidOccupied);
|
std::lock_guard<std::mutex> lk(m_csHWVidOccupied);
|
||||||
GpuRunningState = true;
|
GpuRunningState = true;
|
||||||
SCPFifoStruct &fifo = CommandProcessor::fifo;
|
SCPFifoStruct &fifo = CommandProcessor::fifo;
|
||||||
|
u32 cyclesExecuted = 0;
|
||||||
|
|
||||||
while (GpuRunningState)
|
while (GpuRunningState)
|
||||||
{
|
{
|
||||||
@ -156,6 +159,8 @@ void RunGpuLoop()
|
|||||||
|
|
||||||
CommandProcessor::SetCpStatus();
|
CommandProcessor::SetCpStatus();
|
||||||
|
|
||||||
|
Common::AtomicStore(CommandProcessor::VITicks, CommandProcessor::m_cpClockOrigin);
|
||||||
|
|
||||||
// check if we are able to run this buffer
|
// check if we are able to run this buffer
|
||||||
while (GpuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint())
|
while (GpuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint())
|
||||||
{
|
{
|
||||||
@ -163,24 +168,30 @@ void RunGpuLoop()
|
|||||||
|
|
||||||
fifo.isGpuReadingData = true;
|
fifo.isGpuReadingData = true;
|
||||||
CommandProcessor::isPossibleWaitingSetDrawDone = fifo.bFF_GPLinkEnable ? true : false;
|
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;
|
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);
|
_assert_msg_(COMMANDPROCESSOR, (s32)fifo.CPReadWriteDistance - 32 >= 0 ,
|
||||||
Common::AtomicAdd(fifo.CPReadWriteDistance, -32);
|
"Negative fifo.CPReadWriteDistance = %i in FIFO Loop !\nThat can produce instabilty in the game. Please report it.", fifo.CPReadWriteDistance - 32);
|
||||||
if((GetVideoBufferEndPtr() - g_pVideoData) == 0)
|
|
||||||
Common::AtomicStore(fifo.SafeCPReadPointer, fifo.CPReadPointer);
|
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();
|
CommandProcessor::SetCpStatus();
|
||||||
|
|
||||||
@ -190,7 +201,7 @@ void RunGpuLoop()
|
|||||||
VideoFifo_CheckAsyncRequest();
|
VideoFifo_CheckAsyncRequest();
|
||||||
CommandProcessor::isPossibleWaitingSetDrawDone = false;
|
CommandProcessor::isPossibleWaitingSetDrawDone = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fifo.isGpuReadingData = false;
|
fifo.isGpuReadingData = false;
|
||||||
|
|
||||||
|
|
||||||
@ -219,23 +230,23 @@ bool AtBreakpoint()
|
|||||||
|
|
||||||
void RunGpu()
|
void RunGpu()
|
||||||
{
|
{
|
||||||
SCPFifoStruct &fifo = CommandProcessor::fifo;
|
SCPFifoStruct &fifo = CommandProcessor::fifo;
|
||||||
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() )
|
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() )
|
||||||
{
|
{
|
||||||
u8 *uData = Memory::GetPointer(fifo.CPReadPointer);
|
u8 *uData = Memory::GetPointer(fifo.CPReadPointer);
|
||||||
|
|
||||||
SaveSSEState();
|
SaveSSEState();
|
||||||
LoadDefaultSSEState();
|
LoadDefaultSSEState();
|
||||||
ReadDataFromFifo(uData, 32);
|
ReadDataFromFifo(uData, 32);
|
||||||
OpcodeDecoder_Run(g_bSkipCurrentFrame);
|
u32 count = OpcodeDecoder_Run(g_bSkipCurrentFrame);
|
||||||
LoadSSEState();
|
LoadSSEState();
|
||||||
|
|
||||||
//DEBUG_LOG(COMMANDPROCESSOR, "Fifo wraps to base");
|
//DEBUG_LOG(COMMANDPROCESSOR, "Fifo wraps to base");
|
||||||
|
|
||||||
if (fifo.CPReadPointer == fifo.CPEnd) fifo.CPReadPointer = fifo.CPBase;
|
if (fifo.CPReadPointer == fifo.CPEnd) fifo.CPReadPointer = fifo.CPBase;
|
||||||
else fifo.CPReadPointer += 32;
|
else fifo.CPReadPointer += 32;
|
||||||
|
|
||||||
fifo.CPReadWriteDistance -= 32;
|
fifo.CPReadWriteDistance -= 32;
|
||||||
}
|
}
|
||||||
CommandProcessor::SetCpStatus();
|
CommandProcessor::SetCpStatus();
|
||||||
}
|
}
|
||||||
|
@ -136,29 +136,38 @@ void ExecuteDisplayList(u32 address, u32 size)
|
|||||||
InterpretDisplayList(address, size);
|
InterpretDisplayList(address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FifoCommandRunnable()
|
u32 FifoCommandRunnable(u32 &command_size)
|
||||||
{
|
{
|
||||||
|
u32 cycleTime = 0;
|
||||||
u32 buffer_size = (u32)(GetVideoBufferEndPtr() - g_pVideoData);
|
u32 buffer_size = (u32)(GetVideoBufferEndPtr() - g_pVideoData);
|
||||||
if (buffer_size == 0)
|
if (buffer_size == 0)
|
||||||
return false; // can't peek
|
return 0; // can't peek
|
||||||
|
|
||||||
u8 cmd_byte = DataPeek8(0);
|
u8 cmd_byte = DataPeek8(0);
|
||||||
u32 command_size = 0;
|
|
||||||
|
|
||||||
switch (cmd_byte)
|
switch (cmd_byte)
|
||||||
{
|
{
|
||||||
case GX_NOP: // Hm, this means that we scan over nop streams pretty slowly...
|
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
|
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
|
case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that
|
||||||
command_size = 1;
|
command_size = 1;
|
||||||
|
cycleTime = 6;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GX_LOAD_BP_REG:
|
case GX_LOAD_BP_REG:
|
||||||
command_size = 5;
|
command_size = 5;
|
||||||
|
cycleTime = 12;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GX_LOAD_CP_REG:
|
case GX_LOAD_CP_REG:
|
||||||
command_size = 6;
|
command_size = 6;
|
||||||
|
cycleTime = 12;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GX_LOAD_INDX_A:
|
case GX_LOAD_INDX_A:
|
||||||
@ -166,10 +175,39 @@ bool FifoCommandRunnable()
|
|||||||
case GX_LOAD_INDX_C:
|
case GX_LOAD_INDX_C:
|
||||||
case GX_LOAD_INDX_D:
|
case GX_LOAD_INDX_D:
|
||||||
command_size = 5;
|
command_size = 5;
|
||||||
|
cycleTime = 6; // TODO
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GX_CMD_CALL_DL:
|
case GX_CMD_CALL_DL:
|
||||||
command_size = 9;
|
{
|
||||||
|
// 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;
|
break;
|
||||||
|
|
||||||
case GX_LOAD_XF_REG:
|
case GX_LOAD_XF_REG:
|
||||||
@ -180,11 +218,12 @@ bool FifoCommandRunnable()
|
|||||||
command_size = 1 + 4;
|
command_size = 1 + 4;
|
||||||
u32 Cmd2 = DataPeek32(1);
|
u32 Cmd2 = DataPeek32(1);
|
||||||
int transfer_size = ((Cmd2 >> 16) & 15) + 1;
|
int transfer_size = ((Cmd2 >> 16) & 15) + 1;
|
||||||
command_size += transfer_size * 4;
|
command_size += transfer_size * 4;
|
||||||
|
cycleTime = 18 + 6 * transfer_size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -198,10 +237,11 @@ bool FifoCommandRunnable()
|
|||||||
command_size = 1 + 2;
|
command_size = 1 + 2;
|
||||||
u16 numVertices = DataPeek16(1);
|
u16 numVertices = DataPeek16(1);
|
||||||
command_size += numVertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK);
|
command_size += numVertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK);
|
||||||
|
cycleTime = 12 * numVertices; // This depends on the number of pixels rendered
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -248,11 +288,19 @@ bool FifoCommandRunnable()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (command_size > buffer_size)
|
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);
|
// 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()
|
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())
|
skipped_frame ? DecodeSemiNop() : Decode();
|
||||||
Decode();
|
totalCycles += cycles;
|
||||||
}
|
cycles = FifoCommandRunnable();
|
||||||
else
|
|
||||||
{
|
|
||||||
while (FifoCommandRunnable())
|
|
||||||
DecodeSemiNop();
|
|
||||||
}
|
}
|
||||||
|
return totalCycles;
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,6 @@ extern bool g_bRecordFifoData;
|
|||||||
|
|
||||||
void OpcodeDecoder_Init();
|
void OpcodeDecoder_Init();
|
||||||
void OpcodeDecoder_Shutdown();
|
void OpcodeDecoder_Shutdown();
|
||||||
void OpcodeDecoder_Run(bool skipped_frame);
|
u32 OpcodeDecoder_Run(bool skipped_frame);
|
||||||
void ExecuteDisplayList(u32 address, u32 size);
|
void ExecuteDisplayList(u32 address, u32 size);
|
||||||
#endif // _OPCODE_DECODING_H
|
#endif // _OPCODE_DECODING_H
|
||||||
|
@ -450,9 +450,4 @@ void ResetSetToken()
|
|||||||
}
|
}
|
||||||
CommandProcessor::interruptTokenWaiting = false;
|
CommandProcessor::interruptTokenWaiting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WaitingForPEInterrupt()
|
|
||||||
{
|
|
||||||
return !CommandProcessor::waitingForPEInterruptDisable && (CommandProcessor::interruptFinishWaiting || CommandProcessor::interruptTokenWaiting || Common::AtomicLoad(interruptSetFinish) || Common::AtomicLoad(interruptSetToken));
|
|
||||||
}
|
|
||||||
} // end of namespace PixelEngine
|
} // end of namespace PixelEngine
|
||||||
|
@ -80,7 +80,6 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge);
|
|||||||
void SetFinish(void);
|
void SetFinish(void);
|
||||||
void ResetSetFinish(void);
|
void ResetSetFinish(void);
|
||||||
void ResetSetToken(void);
|
void ResetSetToken(void);
|
||||||
bool WaitingForPEInterrupt();
|
|
||||||
|
|
||||||
// Bounding box functionality. Paper Mario (both) are a couple of the few games that use it.
|
// Bounding box functionality. Paper Mario (both) are a couple of the few games that use it.
|
||||||
extern u16 bbox[4];
|
extern u16 bbox[4];
|
||||||
|
Reference in New Issue
Block a user