From d3d0de62a66e4c34f329ca60a4d7254a923ab4cf Mon Sep 17 00:00:00 2001 From: patchzyy <64382339+patchzyy@users.noreply.github.com> Date: Thu, 3 Sep 2026 23:29:49 +0200 Subject: [PATCH] Throttle SDL logs and gate Wii rescans (#129) * Throttle SDL logs and gate Wii rescans * Clarify Wii remote scan state in overlay --- runtime/include/wii_remote_input.h | 4 ++- runtime/src/settings_overlay.cpp | 4 ++- runtime/src/wii_remote_input.cpp | 53 +++++++++++++++++++++++++++--- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/runtime/include/wii_remote_input.h b/runtime/include/wii_remote_input.h index d7c1c9f..986ec64 100644 --- a/runtime/include/wii_remote_input.h +++ b/runtime/include/wii_remote_input.h @@ -102,8 +102,10 @@ void HideRemotesFromPad(PADStatus* statuses, uint32_t count); void Poll(); // Forces one re-enumeration right now (settings overlay "Rescan now"). void RescanNow(); -// True while Poll() is actively rescanning (no Wii controller connected). +// True while Poll() is looking for a remote (no Wii controller connected). bool IsScanning(); +// True where looking means periodic rescans; elsewhere Poll() waits for hotplug. +bool PeriodicRescanEnabled(); // Rescans issued since a Wii controller was last seen. uint32_t ScanCount(); diff --git a/runtime/src/settings_overlay.cpp b/runtime/src/settings_overlay.cpp index 282f7a4..6561ef8 100644 --- a/runtime/src/settings_overlay.cpp +++ b/runtime/src/settings_overlay.cpp @@ -393,8 +393,10 @@ void DrawWiiRemoteSettings(uint32_t selectedGamePort) { } ImGui::EndDisabled(); ImGui::SameLine(); - if (WiiRemoteInput::IsScanning()) { + if (WiiRemoteInput::IsScanning() && WiiRemoteInput::PeriodicRescanEnabled()) { ImGui::TextDisabled("Scanning... (%u so far) - press 1+2 on the remote", WiiRemoteInput::ScanCount()); + } else if (WiiRemoteInput::IsScanning()) { + ImGui::TextDisabled("Waiting for a remote - press 1+2 on the remote"); } else { ImGui::TextDisabled("Not scanning"); } diff --git a/runtime/src/wii_remote_input.cpp b/runtime/src/wii_remote_input.cpp index 6c0cf6f..09dc97d 100644 --- a/runtime/src/wii_remote_input.cpp +++ b/runtime/src/wii_remote_input.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include namespace WiiRemoteInput { namespace { @@ -346,6 +348,10 @@ bool AnyWiiControllerConnected() { // Route SDL's input diagnostics (HIDAPI open failures, the Wii driver's // extension/status messages) into console.log, minus the periodic chatter. +// A sub-warning message is written once: SDL repeats the same line on every +// enumeration (one "couldn't open /dev/hidraw7: Permission denied" per HID +// device per pass), and console.log is unbuffered, so the repeats were a +// per-pass burst of writes on the main thread for no new information. void SDLCALL LogSdlMessage(void*, int category, SDL_LogPriority priority, const char* message) { if (message == nullptr) { return; @@ -354,11 +360,42 @@ void SDLCALL LogSdlMessage(void*, int category, SDL_LogPriority priority, const (std::strstr(message, "Motion Plus") != nullptr || std::strstr(message, "Resetting report mode") != nullptr)) { return; } - if (category == SDL_LOG_CATEGORY_INPUT || priority >= SDL_LOG_PRIORITY_WARN) { - RT_LOG("sdl") << message << std::endl; + if (category != SDL_LOG_CATEGORY_INPUT && priority < SDL_LOG_PRIORITY_WARN) { + return; } + if (priority < SDL_LOG_PRIORITY_WARN) { + // Device paths in these messages keep changing (/dev/hidrawN climbs with + // hotplug churn), so cap the set instead of holding one string per line + // for the whole session. + static std::unordered_set s_seen; + if (s_seen.size() >= 256) { + s_seen.clear(); + } + if (!s_seen.insert(message).second) { + return; + } + RT_LOG("sdl") << message << " (further identical messages suppressed)" << std::endl; + return; + } + RT_LOG("sdl") << message << std::endl; } +// Whether Poll() drives its own periodic re-enumeration. The 1->0->1 hint +// flip below makes SDL close and re-open every HIDAPI device on the main +// thread, and on Linux that means an open() attempt on every /dev/hidraw node +// (each failing with EACCES until a udev rule grants access), which showed up +// as a frame hitch every scan interval even on an empty menu. It exists for +// Windows Bluetooth stacks, where a remote that drops or is switched on after +// launch is not seen again until the driver re-enumerates. Linux and macOS +// already get hotplug from udev / IOKit: SDL re-enumerates when a device +// appears, so nothing periodic is needed there. The overlay's "Rescan now" +// still works everywhere. +#if defined(_WIN32) +constexpr bool kPeriodicRescan = true; +#else +constexpr bool kPeriodicRescan = false; +#endif + // Second half of a rescan: re-enables the Wii driver once SDL has seen it off. void FinishRescan(uint64_t now) { if (g_driverOffSinceMs == 0 || now - g_driverOffSinceMs < kRescanDriverOffMs) { @@ -450,12 +487,13 @@ void Poll() { } const uint64_t now = SDL_GetTicks(); if (!g_scanning) { - RT_LOG(RT_TAG_CONFIG) << "No Wii Remote connected; scanning for one (press 1+2 on the remote)" - << std::endl; + RT_LOG(RT_TAG_CONFIG) << "No Wii Remote connected; " + << (kPeriodicRescan ? "scanning for one" : "waiting for one to be paired") + << " (press 1+2 on the remote)" << std::endl; g_scanning = true; g_lostAtMs = now; } - if (now - g_lostAtMs < kScanStartDelayMs) { + if (!kPeriodicRescan || now - g_lostAtMs < kScanStartDelayMs) { return; } const uint64_t interval = now - g_lostAtMs < kFastScanWindowMs ? kFastScanIntervalMs : kScanIntervalMs; @@ -470,6 +508,11 @@ bool IsScanning() { return g_scanning; } +// Whether looking for a remote means periodic rescans or waiting for hotplug. +bool PeriodicRescanEnabled() { + return kPeriodicRescan; +} + // Number of rescans since a Wii controller was last seen. uint32_t ScanCount() { return g_scanCount;