Skip to content

Commit 591661a

Browse files
committed
Add GCA poll rate to controller settings
1 parent 283babe commit 591661a

File tree

6 files changed

+88
-3
lines changed

6 files changed

+88
-3
lines changed

Readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ This is a work-in-progress version of the Dolphin Emulator built for usage with
2020
* Discord Rich Presence support
2121
* Separate Minimum and Player buffers in netplay window
2222
* Client side music toggle in netplay window
23+
* Gamecube adapter polling rate in controller settings
2324

2425
* To-Do
25-
* Gamecube adapter polling rate in controller settings
2626
* Spectator button in netplay window
2727
* Overwrite Dolphin updater functions with our own
2828
* "On SI Read" polling method

Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <QCheckBox>
77
#include <QDialogButtonBox>
88
#include <QLabel>
9+
#include <QTimer>
910
#include <QVBoxLayout>
1011

1112
#include "Core/Config/MainSettings.h"
@@ -36,25 +37,32 @@ void GCPadWiiUConfigDialog::CreateLayout()
3637

3738
m_layout = new QVBoxLayout();
3839
m_status_label = new QLabel();
40+
m_poll_rate_label = new QLabel();
3941
m_rumble = new QCheckBox(tr("Enable Rumble"));
4042
m_simulate_bongos = new QCheckBox(tr("Simulate DK Bongos"));
4143
m_button_box = new QDialogButtonBox(QDialogButtonBox::Ok);
4244

4345
UpdateAdapterStatus();
46+
UpdatePollRate();
47+
48+
m_poll_rate_timer = new QTimer(this);
4449

4550
auto callback = [this] { QueueOnObject(this, &GCPadWiiUConfigDialog::UpdateAdapterStatus); };
4651
GCAdapter::SetAdapterCallback(callback);
4752

4853
m_layout->addWidget(m_status_label);
4954
m_layout->addWidget(m_rumble);
50-
m_layout->addWidget(m_simulate_bongos);
55+
m_layout->addWidget(m_poll_rate_label);
56+
// m_layout->addWidget(m_simulate_bongos); //we're not using bongos for this lol
5157
m_layout->addWidget(m_button_box);
5258

5359
setLayout(m_layout);
5460
}
5561

5662
void GCPadWiiUConfigDialog::ConnectWidgets()
5763
{
64+
connect(m_poll_rate_timer, &QTimer::timeout, this, &GCPadWiiUConfigDialog::UpdatePollRate);
65+
m_poll_rate_timer->start(1500);
5866
connect(m_rumble, &QCheckBox::toggled, this, &GCPadWiiUConfigDialog::SaveSettings);
5967
connect(m_simulate_bongos, &QCheckBox::toggled, this, &GCPadWiiUConfigDialog::SaveSettings);
6068
connect(m_button_box, &QDialogButtonBox::accepted, this, &GCPadWiiUConfigDialog::accept);
@@ -83,6 +91,13 @@ void GCPadWiiUConfigDialog::UpdateAdapterStatus()
8391

8492
m_rumble->setEnabled(detected);
8593
m_simulate_bongos->setEnabled(detected);
94+
m_poll_rate_label->setHidden(!detected);
95+
}
96+
97+
void GCPadWiiUConfigDialog::UpdatePollRate()
98+
{
99+
QString poll_rate_text = tr("Poll Rate: %1 hz").arg(1000.0 / GCAdapter::ReadRate());
100+
m_poll_rate_label->setText(poll_rate_text);
86101
}
87102

88103
void GCPadWiiUConfigDialog::LoadSettings()

Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class QCheckBox;
99
class QLabel;
1010
class QDialogButtonBox;
1111
class QVBoxLayout;
12+
class QTimer;
1213

1314
class GCPadWiiUConfigDialog final : public QDialog
1415
{
@@ -26,11 +27,14 @@ class GCPadWiiUConfigDialog final : public QDialog
2627

2728
private:
2829
void UpdateAdapterStatus();
30+
void UpdatePollRate();
2931

3032
int m_port;
3133

3234
QVBoxLayout* m_layout;
3335
QLabel* m_status_label;
36+
QLabel* m_poll_rate_label;
37+
QTimer* m_poll_rate_timer;
3438
QDialogButtonBox* m_button_box;
3539

3640
// Checkboxes

Source/Core/InputCommon/GCAdapter.cpp

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ static std::optional<Config::ConfigChangedCallbackID> s_config_callback_id = std
171171
static bool s_is_adapter_wanted = false;
172172
static std::array<bool, SerialInterface::MAX_SI_CHANNELS> s_config_rumble_enabled{};
173173

174+
// P+ change: for poll rate display
175+
static u64 s_consecutive_slow_transfers = 0;
176+
static double s_read_rate = 0.0;
177+
174178
static void ReadThreadFunc()
175179
{
176180
Common::SetCurrentThreadName("GCAdapter Read Thread");
@@ -206,16 +210,40 @@ static void ReadThreadFunc()
206210

207211
// Reset rumble once on initial reading
208212
ResetRumble();
213+
214+
// P+ change: for poll rate display
215+
s_read_rate = 0.0;
209216

210217
while (s_read_adapter_thread_running.IsSet())
211218
{
212219
#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION
213220
std::array<u8, CONTROLLER_INPUT_PAYLOAD_EXPECTED_SIZE> input_buffer;
214221

215222
int payload_size = 0;
223+
224+
// P+ change: for poll rate display
225+
std::chrono::high_resolution_clock::time_point start =
226+
std::chrono::high_resolution_clock::now();
216227
int error = libusb_interrupt_transfer(s_handle, s_endpoint_in, input_buffer.data(),
217228
int(input_buffer.size()), &payload_size, USB_TIMEOUT_MS);
218-
if (error != LIBUSB_SUCCESS)
229+
// P+ change: for poll rate display
230+
std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now();
231+
232+
double elapsed_ms =
233+
std::chrono::duration_cast<std::chrono::nanoseconds>(now - start).count() / 1000000.0;
234+
235+
if (elapsed_ms > 15.0)
236+
{
237+
s_consecutive_slow_transfers++;
238+
}
239+
else
240+
{
241+
s_consecutive_slow_transfers = 0;
242+
}
243+
244+
s_read_rate = elapsed_ms;
245+
246+
if (error != LIBUSB_SUCCESS)
219247
{
220248
ERROR_LOG_FMT(CONTROLLERINTERFACE, "Read: libusb_interrupt_transfer failed: {}",
221249
LibusbUtils::ErrorWrap(error));
@@ -491,6 +519,18 @@ void StopScanThread()
491519
}
492520
}
493521

522+
// P+ change: for poll rate display
523+
bool IsReadingAtReducedRate()
524+
{
525+
return s_consecutive_slow_transfers > 80;
526+
}
527+
528+
529+
double ReadRate()
530+
{
531+
return s_read_rate;
532+
}
533+
494534
static void Setup()
495535
{
496536
#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION

Source/Core/InputCommon/GCAdapter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ void SetAdapterCallback(std::function<void(void)> func);
1818
void StartScanThread();
1919
void StopScanThread();
2020

21+
// P+ change: for poll rate display
22+
bool IsReadingAtReducedRate();
23+
double ReadRate();
24+
2125
// Buttons have PAD_GET_ORIGIN set on new connection
2226
// Netplay and CSIDevice_GCAdapter make use of this.
2327
GCPadStatus Input(int chan);

Source/Core/VideoCommon/OnScreenUI.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "Core/Config/NetplaySettings.h"
1313
#include "Core/Movie.h"
1414
#include "Core/System.h"
15+
#include "InputCommon/GCAdapter.h"
1516

1617
#include "VideoCommon/AbstractGfx.h"
1718
#include "VideoCommon/AbstractPipeline.h"
@@ -329,8 +330,29 @@ void OnScreenUI::DrawDebugText()
329330
const std::string profile_output = Common::Profiler::ToString();
330331
if (!profile_output.empty())
331332
ImGui::TextUnformatted(profile_output.c_str());
333+
334+
// P+ change: warn if adapter is being read at reduced rate
335+
if (GCAdapter::IsReadingAtReducedRate())
336+
{
337+
ImGui::TextWrapped(
338+
"Your GameCube Controller Adapter is reading inputs at a reduced rate.\n"
339+
"You can still play normally but you will experience higher input lag.\n"
340+
"This indicates a potential hardware issue.\n"
341+
"\n"
342+
"Go to the Dolphin -> Controllers page, click 'Configure' next to your "
343+
"controller's port, then check what your pollrate is."
344+
"\n"
345+
"If it is considerably lower than 125 hz, keep trying different USB ports until it "
346+
"is around 125 hz."
347+
"\n"
348+
"For more help, please ask in the official P+ Discord server.");
349+
350+
}
332351
}
333352

353+
354+
355+
334356
void OnScreenUI::DrawChallengesAndLeaderboards()
335357
{
336358
if (!Config::Get(Config::MAIN_OSD_MESSAGES))

0 commit comments

Comments
 (0)