From 9eca21b273da2957511323d4b5f4f93bf776ba6e Mon Sep 17 00:00:00 2001 From: Nikhil Narayana Date: Fri, 13 Oct 2023 09:41:26 -0700 Subject: [PATCH] feat: add poll rate display in GC Adapter config (#7) for some reason i'm seeing 250hz readings every now and then instead of 500hz also adds reduced rate warning, i'm not in love with the implentation, but it works well enough --- .../Config/Mapping/GCPadWiiUConfigDialog.cpp | 18 +++++++- .../Config/Mapping/GCPadWiiUConfigDialog.h | 4 ++ Source/Core/InputCommon/GCAdapter.cpp | 43 +++++++++++++++++++ Source/Core/InputCommon/GCAdapter.h | 5 +++ Source/Core/VideoCommon/OnScreenUI.cpp | 19 ++++++++ 5 files changed, 88 insertions(+), 1 deletion(-) diff --git a/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.cpp b/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.cpp index af9231abd1..7aa17a92ff 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,18 +37,24 @@ 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_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); + // slippi change: no need to let users turn on bongos + // m_layout->addWidget(m_simulate_bongos); m_layout->addWidget(m_button_box); setLayout(m_layout); @@ -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); @@ -83,6 +92,13 @@ void GCPadWiiUConfigDialog::UpdateAdapterStatus() m_rumble->setEnabled(detected); m_simulate_bongos->setEnabled(detected); + m_poll_rate_label->setHidden(!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() diff --git a/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h b/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h index 0bcfb8f966..969142b29c 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 @@ private: 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 a3853e9e6c..505f91978d 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: for poll rate display +static u64 s_consecutive_slow_transfers = 0; +static double s_read_rate = 0.0; +// slippi change: for poll rate display + static void ReadThreadFunc() { Common::SetCurrentThreadName("GCAdapter Read Thread"); @@ -197,15 +202,41 @@ static void ReadThreadFunc() // Reset rumble once on initial reading ResetRumble(); + // slippi change: for poll rate display + 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; + + // slippi change: for poll rate display + 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); + + // slippi change: for poll rate display + 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; + // slippi change: for poll rate display + if (error != LIBUSB_SUCCESS) { ERROR_LOG_FMT(CONTROLLERINTERFACE, "Read: libusb_interrupt_transfer failed: {}", @@ -469,6 +500,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 e6f62e035b..0601bf56b6 100644 --- a/Source/Core/InputCommon/GCAdapter.h +++ b/Source/Core/InputCommon/GCAdapter.h @@ -18,6 +18,11 @@ void SetAdapterCallback(std::function func); void StartScanThread(); void StopScanThread(); +// slippi change: for poll rate display +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); diff --git a/Source/Core/VideoCommon/OnScreenUI.cpp b/Source/Core/VideoCommon/OnScreenUI.cpp index e2fa2593a7..ba44880af6 100644 --- a/Source/Core/VideoCommon/OnScreenUI.cpp +++ b/Source/Core/VideoCommon/OnScreenUI.cpp @@ -11,6 +11,8 @@ #include "Core/Config/NetplaySettings.h" #include "Core/Movie.h" +#include "InputCommon/GCAdapter.h" + #include "VideoCommon/AbstractGfx.h" #include "VideoCommon/AbstractPipeline.h" #include "VideoCommon/AbstractShader.h" @@ -321,6 +323,23 @@ void OnScreenUI::DrawDebugText() const std::string profile_output = Common::Profiler::ToString(); if (!profile_output.empty()) ImGui::TextUnformatted(profile_output.c_str()); + + // SLIPPITODO: make this cleaner + if (GCAdapter::IsReadingAtReducedRate()) + { + ImGui::TextWrapped( + "Your GameCube Controller Adapter is reading inputs at a reduced rate.\n" + "You can still play normally but you will experience higher input lag.\n" + "This indicates a potential hardware issue.\n" + "\n" + "Go to the Dolphin -> Controllers page, click 'Configure' next to your " + "controller's port, then check what your pollrate is." + "\n" + "If it is considerably lower than 125 hz, keep trying different USB ports until it " + "is around 125 hz." + "\n" + "For more help, please ask in the official Slippi Discord server."); + } } void OnScreenUI::Finalize()