diff --git a/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.cpp b/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.cpp index af9231abd188..ca74a4f8f5e0 100644 --- a/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "Core/Config/MainSettings.h" @@ -36,16 +37,22 @@ void GCPadWiiUConfigDialog::CreateLayout() m_layout = new QVBoxLayout(); m_status_label = new QLabel(); + m_poll_rate_label = new QLabel(); m_rumble = new QCheckBox(tr("Enable Rumble")); m_simulate_bongos = new QCheckBox(tr("Simulate DK Bongos")); + m_simulate_bongos->setDisabled(true); m_button_box = new QDialogButtonBox(QDialogButtonBox::Ok); UpdateAdapterStatus(); + UpdatePollRate(); + + m_poll_rate_timer = new QTimer(this); auto callback = [this] { QueueOnObject(this, &GCPadWiiUConfigDialog::UpdateAdapterStatus); }; GCAdapter::SetAdapterCallback(callback); m_layout->addWidget(m_status_label); + m_layout->addWidget(m_poll_rate_label); m_layout->addWidget(m_rumble); m_layout->addWidget(m_simulate_bongos); m_layout->addWidget(m_button_box); @@ -55,6 +62,8 @@ void GCPadWiiUConfigDialog::CreateLayout() void GCPadWiiUConfigDialog::ConnectWidgets() { + connect(m_poll_rate_timer, &QTimer::timeout, this, &GCPadWiiUConfigDialog::UpdatePollRate); + m_poll_rate_timer->start(1500); connect(m_rumble, &QCheckBox::toggled, this, &GCPadWiiUConfigDialog::SaveSettings); connect(m_simulate_bongos, &QCheckBox::toggled, this, &GCPadWiiUConfigDialog::SaveSettings); connect(m_button_box, &QDialogButtonBox::accepted, this, &GCPadWiiUConfigDialog::accept); @@ -85,6 +94,12 @@ void GCPadWiiUConfigDialog::UpdateAdapterStatus() m_simulate_bongos->setEnabled(detected); } +void GCPadWiiUConfigDialog::UpdatePollRate() +{ + QString poll_rate_text = tr("Poll Rate: %1 hz").arg(1000.0 / GCAdapter::ReadRate()); + m_poll_rate_label->setText(poll_rate_text); +} + void GCPadWiiUConfigDialog::LoadSettings() { m_rumble->setChecked(Config::Get(Config::GetInfoForAdapterRumble(m_port))); diff --git a/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h b/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h index 0bcfb8f966fa..969142b29c63 100644 --- a/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h +++ b/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h @@ -9,6 +9,7 @@ class QCheckBox; class QLabel; class QDialogButtonBox; class QVBoxLayout; +class QTimer; class GCPadWiiUConfigDialog final : public QDialog { @@ -26,11 +27,14 @@ class GCPadWiiUConfigDialog final : public QDialog private: void UpdateAdapterStatus(); + void UpdatePollRate(); int m_port; QVBoxLayout* m_layout; QLabel* m_status_label; + QLabel* m_poll_rate_label; + QTimer* m_poll_rate_timer; QDialogButtonBox* m_button_box; // Checkboxes diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index a3853e9e6cf3..0b0275ab8705 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -161,6 +161,11 @@ static std::optional s_config_callback_id = std::nullopt; static bool s_is_adapter_wanted = false; static std::array s_config_rumble_enabled{}; +// slippi change: poll rate stuff +static u64 s_consecutive_slow_transfers = 0; +static double s_read_rate = 0.0; +// slippi change: poll rate stuff + static void ReadThreadFunc() { Common::SetCurrentThreadName("GCAdapter Read Thread"); @@ -197,15 +202,37 @@ static void ReadThreadFunc() // Reset rumble once on initial reading ResetRumble(); + s_read_rate = 0.0; + while (s_read_adapter_thread_running.IsSet()) { #if GCADAPTER_USE_LIBUSB_IMPLEMENTATION std::array input_buffer; int payload_size = 0; + + std::chrono::high_resolution_clock::time_point start = + std::chrono::high_resolution_clock::now(); const int error = libusb_interrupt_transfer(s_handle, s_endpoint_in, input_buffer.data(), int(input_buffer.size()), &payload_size, USB_TIMEOUT_MS); + + std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now(); + + double elapsed_ms = + std::chrono::duration_cast(now - start).count() / 1000000.0; + + if (elapsed_ms > 15.0) + { + s_consecutive_slow_transfers++; + } + else + { + s_consecutive_slow_transfers = 0; + } + + s_read_rate = elapsed_ms; + if (error != LIBUSB_SUCCESS) { ERROR_LOG_FMT(CONTROLLERINTERFACE, "Read: libusb_interrupt_transfer failed: {}", @@ -469,6 +496,18 @@ void StopScanThread() } } +// slippi change: for poll rate display +bool IsReadingAtReducedRate() +{ + return s_consecutive_slow_transfers > 80; +} + +double ReadRate() +{ + return s_read_rate; +} +// slippi change: for poll rate display + static void Setup() { #if GCADAPTER_USE_LIBUSB_IMPLEMENTATION diff --git a/Source/Core/InputCommon/GCAdapter.h b/Source/Core/InputCommon/GCAdapter.h index e6f62e035b40..20aee9776e6a 100644 --- a/Source/Core/InputCommon/GCAdapter.h +++ b/Source/Core/InputCommon/GCAdapter.h @@ -18,6 +18,12 @@ void SetAdapterCallback(std::function func); void StartScanThread(); void StopScanThread(); +// slippi change: for poll rate display +void ResetAdapterIfNecessary(); +bool IsReadingAtReducedRate(); +double ReadRate(); +// slippi change: for poll rate display + // Buttons have PAD_GET_ORIGIN set on new connection // Netplay and CSIDevice_GCAdapter make use of this. GCPadStatus Input(int chan);