From 43c09c63d83377f59391c199837369fadf0cdc7b Mon Sep 17 00:00:00 2001 From: Michael Maltese Date: Mon, 8 May 2017 17:16:47 -0700 Subject: [PATCH 1/3] AX-HLE: delay sending interrupt when done processing command list Fixes https://bugs.dolphin-emu.org/issues/10265 (Star Wars: The Clone Wars hangs on loading screen with DSP-HLE and JIT Recompiler). The Clone Wars hangs upon initial boot if this interrupt happens too quickly after submitting a command list. When played in DSP-LLE, the interrupt lags by about 160,000 cycles, though any value greater than or equal to 814 will work. In other games, the lag can be as small as 50,000 cycles (in Metroid Prime) and as large as 718,092 cycles (in Tales of Symphonia!). All credit to @hthh, who put in a heroic(!) amount of detective work and discovered that The Clone Wars tracks a "AXCommandListCycles" variable which matches the aforementioned 160,000 cycles. It's initialized to ~2500 cycles for a minimal, empty command list, so that should be a safe number for pretty much anything a game does (*crosses fingers*). --- Source/Core/Core/HW/DSP.cpp | 7 +++---- Source/Core/Core/HW/DSP.h | 3 ++- Source/Core/Core/HW/DSPHLE/MailHandler.cpp | 4 ++-- Source/Core/Core/HW/DSPHLE/MailHandler.h | 3 ++- Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp | 17 ++++++++++++++++- 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Source/Core/Core/HW/DSP.cpp b/Source/Core/Core/HW/DSP.cpp index aae25d8298..4795eb6b87 100644 --- a/Source/Core/Core/HW/DSP.cpp +++ b/Source/Core/Core/HW/DSP.cpp @@ -408,15 +408,14 @@ static void GenerateDSPInterrupt(u64 DSPIntType, s64 cyclesLate) // DSP_CONTROL - we mask by (INT_DSP | INT_ARAM | INT_AID) just to ensure people // don't call this with bogus values. s_dspState.Hex |= (DSPIntType & (INT_DSP | INT_ARAM | INT_AID)); - UpdateInterrupts(); } // CALLED FROM DSP EMULATOR, POSSIBLY THREADED -void GenerateDSPInterruptFromDSPEmu(DSPInterruptType type) +void GenerateDSPInterruptFromDSPEmu(DSPInterruptType type, int cycles_into_future) { - // TODO: Maybe rethink this? The timing is unpredictable. - CoreTiming::ScheduleEvent(0, s_et_GenerateDSPInterrupt, type, CoreTiming::FromThread::ANY); + CoreTiming::ScheduleEvent(cycles_into_future, s_et_GenerateDSPInterrupt, type, + CoreTiming::FromThread::ANY); } // called whenever SystemTimers thinks the DSP deserves a few more cycles diff --git a/Source/Core/Core/HW/DSP.h b/Source/Core/Core/HW/DSP.h index 05bbffa86a..2447685a2e 100644 --- a/Source/Core/Core/HW/DSP.h +++ b/Source/Core/Core/HW/DSP.h @@ -69,7 +69,8 @@ DSPEmulator* GetDSPEmulator(); void DoState(PointerWrap& p); -void GenerateDSPInterruptFromDSPEmu(DSPInterruptType type); +// TODO: Maybe rethink this? The timing is unpredictable. +void GenerateDSPInterruptFromDSPEmu(DSPInterruptType type, int cycles_into_future = 0); // Audio/DSP Helper u8 ReadARAM(u32 address); diff --git a/Source/Core/Core/HW/DSPHLE/MailHandler.cpp b/Source/Core/Core/HW/DSPHLE/MailHandler.cpp index fc5cb8bf87..be56af8e86 100644 --- a/Source/Core/Core/HW/DSPHLE/MailHandler.cpp +++ b/Source/Core/Core/HW/DSPHLE/MailHandler.cpp @@ -22,13 +22,13 @@ CMailHandler::~CMailHandler() Clear(); } -void CMailHandler::PushMail(u32 _Mail, bool interrupt) +void CMailHandler::PushMail(u32 _Mail, bool interrupt, int cycles_into_future) { if (interrupt) { if (m_Mails.empty()) { - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP, cycles_into_future); } else { diff --git a/Source/Core/Core/HW/DSPHLE/MailHandler.h b/Source/Core/Core/HW/DSPHLE/MailHandler.h index d02ec9ffbe..ba2191276c 100644 --- a/Source/Core/Core/HW/DSPHLE/MailHandler.h +++ b/Source/Core/Core/HW/DSPHLE/MailHandler.h @@ -21,7 +21,8 @@ public: CMailHandler(); ~CMailHandler(); - void PushMail(u32 _Mail, bool interrupt = false); + // TODO: figure out correct timing for interrupts rather than defaulting to "immediately." + void PushMail(u32 _Mail, bool interrupt = false, int cycles_into_future = 0); void Clear(); void Halt(bool _Halt); void DoState(PointerWrap& p); diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp index 7c9e745fd1..8cf4c33507 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp @@ -77,7 +77,22 @@ void AXUCode::LoadResamplingCoefficients() void AXUCode::SignalWorkEnd() { // Signal end of processing - m_mail_handler.PushMail(DSP_YIELD, true); + // TODO: figure out how many cycles this is actually supposed to take + + // The Clone Wars hangs upon initial boot if this interrupt happens too quickly after submitting a + // command list. When played in DSP-LLE, the interrupt lags by about 160,000 cycles, though any + // value greater than or equal to 814 will work here. In other games, the lag can be as small as + // 50,000 cycles (in Metroid Prime) and as large as 718,092 cycles (in Tales of Symphonia!). + + // On the PowerPC side, hthh_ discovered that The Clone Wars tracks a "AXCommandListCycles" + // variable which matches the aforementioned 160,000 cycles. It's initialized to ~2500 cycles for + // a minimal, empty command list, so that should be a safe number for pretty much anything a game + // does. + + // For more information, see https://bugs.dolphin-emu.org/issues/10265. + constexpr int AX_EMPTY_COMMAND_LIST_CYCLES = 2500; + + m_mail_handler.PushMail(DSP_YIELD, true, AX_EMPTY_COMMAND_LIST_CYCLES); } void AXUCode::HandleCommandList() From 2fad33cafebfaa2b385c988f7d8c2e2f227d9426 Mon Sep 17 00:00:00 2001 From: Michael Maltese Date: Fri, 19 May 2017 18:39:42 -0700 Subject: [PATCH 2/3] DSP-HLE: cleanup PushMail argument names --- Source/Core/Core/HW/DSPHLE/MailHandler.cpp | 6 +++--- Source/Core/Core/HW/DSPHLE/MailHandler.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/HW/DSPHLE/MailHandler.cpp b/Source/Core/Core/HW/DSPHLE/MailHandler.cpp index be56af8e86..da1ccfd29b 100644 --- a/Source/Core/Core/HW/DSPHLE/MailHandler.cpp +++ b/Source/Core/Core/HW/DSPHLE/MailHandler.cpp @@ -22,7 +22,7 @@ CMailHandler::~CMailHandler() Clear(); } -void CMailHandler::PushMail(u32 _Mail, bool interrupt, int cycles_into_future) +void CMailHandler::PushMail(u32 mail, bool interrupt, int cycles_into_future) { if (interrupt) { @@ -35,8 +35,8 @@ void CMailHandler::PushMail(u32 _Mail, bool interrupt, int cycles_into_future) m_Mails.front().second = true; } } - m_Mails.emplace(_Mail, false); - DEBUG_LOG(DSP_MAIL, "DSP writes 0x%08x", _Mail); + m_Mails.emplace(mail, false); + DEBUG_LOG(DSP_MAIL, "DSP writes 0x%08x", mail); } u16 CMailHandler::ReadDSPMailboxHigh() diff --git a/Source/Core/Core/HW/DSPHLE/MailHandler.h b/Source/Core/Core/HW/DSPHLE/MailHandler.h index ba2191276c..a3503cefb7 100644 --- a/Source/Core/Core/HW/DSPHLE/MailHandler.h +++ b/Source/Core/Core/HW/DSPHLE/MailHandler.h @@ -22,7 +22,7 @@ public: ~CMailHandler(); // TODO: figure out correct timing for interrupts rather than defaulting to "immediately." - void PushMail(u32 _Mail, bool interrupt = false, int cycles_into_future = 0); + void PushMail(u32 mail, bool interrupt = false, int cycles_into_future = 0); void Clear(); void Halt(bool _Halt); void DoState(PointerWrap& p); From b25babfbf30bed7d405ca66c53e195ec29fddbe0 Mon Sep 17 00:00:00 2001 From: Michael Maltese Date: Mon, 8 May 2017 17:37:10 -0700 Subject: [PATCH 3/3] GameSettings: Star Wars: The Clone Wars no longer requires DSP-LLE --- Data/Sys/GameSettings/GSX.ini | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Data/Sys/GameSettings/GSX.ini b/Data/Sys/GameSettings/GSX.ini index beba2cda9e..d64006e60e 100644 --- a/Data/Sys/GameSettings/GSX.ini +++ b/Data/Sys/GameSettings/GSX.ini @@ -3,16 +3,9 @@ [Core] # Values set here will override the main Dolphin settings. MMU = 1 -# LLE audio enabled by default for a listenable output -DSPHLE = False - -[DSP] -# Ensure the LLE recompiler gets selected and not interpreter. -EnableJIT = True [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationIssues = Needs LLE audio for proper sound. EmulationStateId = 4 [OnLoad]