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] 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..da1ccfd29b 100644 --- a/Source/Core/Core/HW/DSPHLE/MailHandler.cpp +++ b/Source/Core/Core/HW/DSPHLE/MailHandler.cpp @@ -22,21 +22,21 @@ 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 { 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 d02ec9ffbe..a3503cefb7 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()