diff --git a/Source/Core/Core/Src/HW/SystemTimers.cpp b/Source/Core/Core/Src/HW/SystemTimers.cpp index 815fdde2a2..d7bbfc331b 100644 --- a/Source/Core/Core/Src/HW/SystemTimers.cpp +++ b/Source/Core/Core/Src/HW/SystemTimers.cpp @@ -113,7 +113,6 @@ int et_AI; int et_AudioDMA; int et_DSP; int et_IPC_HLE; -int et_FakeGPWD; // DC watchdog hack int et_PatchEngine; // PatchEngine updates every 1/60th of a second by default // These are badly educated guesses @@ -244,11 +243,12 @@ void Init() // AyuanX: TO BE TWEAKED // Now the 1500 is a pure assumption // We need to figure out the real frequency though - // PS: When this period is tweaked, the interval - // in WII_IPC_HLE_Device_usb.cpp should also be tweaked accordingly - // to guarantee WiiMote updates at a fixed 100Hz - int interval = SConfig::GetInstance().m_LocalCoreStartupParameter.bDisableWiimoteSpeaker?1250:1500; - int fields = SConfig::GetInstance().m_LocalCoreStartupParameter.bVBeam?2:1; + + // FIXME: does Wiimote Speaker support really require a different interval? (issue 4608) + const int interval = SConfig::GetInstance().m_LocalCoreStartupParameter. + bDisableWiimoteSpeaker ? 1250 : 1500; + const int fields = SConfig::GetInstance().m_LocalCoreStartupParameter. + bVBeam ? 2 : 1; IPC_HLE_PERIOD = GetTicksPerSecond() / (interval * fields); } else diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp index 61bb376a51..d4491f8972 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp @@ -18,6 +18,7 @@ #include "../Core.h" #include "../Debugger/Debugger_SymbolMap.h" #include "../Host.h" +#include "../HW/SystemTimers.h" #include "../HW/Wiimote.h" #include "../HW/WII_IPC.h" #include "WII_IPC_HLE.h" @@ -495,17 +496,24 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update() } } - // The Real Wiimote sends report every ~6.66ms. + // The Real Wiimote sends report every ~6.66ms (150 Hz). // However, we don't actually reach here at dependable intervals, so we // instead just timeslice in such a way that makes the stack think we have // perfect "radio quality" (WPADGetRadioSensitivity) and yet still have some // idle time. - static int wiimote_to_update = 0; - const u64 interval = 729000000u / 200; // 5ms behaves well - u64 each_wiimote_interval = interval / m_WiiMotes.size(); - u64 now = CoreTiming::GetTicks(); + // Somehow, Dolphin's Wiimote Speaker support requires using an update interval + // of 5ms (200 Hz) for its output to work. This increased frequency tends to + // fill the ACL queue (even) quicker than it can be processed by Dolphin, + // especially during simultaneous requests involving many (emulated) Wiimotes... + // Thus, we only use that interval when the option is enabled. See issue 4608. + const u64 interval = SystemTimers::GetTicksPerSecond() / (SConfig::GetInstance(). + m_LocalCoreStartupParameter.bDisableWiimoteSpeaker ? 150 : 200); + const u64 each_wiimote_interval = interval / m_WiiMotes.size(); + const u64 now = CoreTiming::GetTicks(); + if (now - m_last_ticks > each_wiimote_interval) { + static int wiimote_to_update = 0; if (m_WiiMotes[wiimote_to_update].IsConnected()) { NetPlay_WiimoteUpdate(wiimote_to_update); diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.h index 897f3a9e86..6bb381ed6f 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.h @@ -182,10 +182,24 @@ private: { _dbg_assert_msg_(WII_IPC_WIIMOTE, size < m_acl_pkt_size, "acl packet too large for pool"); + + const int next_write_ptr = (m_write_ptr + 1) % m_acl_pkts_num; + if (next_write_ptr == m_read_ptr) + { + // Many simultaneous exchanges of ACL packets tend to cause the + // 10-packet limit to be exceeded. Typically, this occurs when + // many emulated Wiimotes are requesting connections at once. + // See issue 4608 for more info. + ERROR_LOG(WII_IPC_WIIMOTE, "ACL queue is full - current packet will be " + "dropped! (m_write_ptr(%d) was about to overlap m_read_ptr(%d))", + m_write_ptr, m_read_ptr); + return; + } + memcpy(m_pool + m_acl_pkt_size * m_write_ptr, data, size); m_info[m_write_ptr].size = size; m_info[m_write_ptr].conn_handle = conn_handle; - m_write_ptr = (m_write_ptr + 1) % m_acl_pkts_num; + m_write_ptr = next_write_ptr; } void WriteToEndpoint(CtrlBuffer& endpoint);