Qt: Increase idle polling interval

Use less power.
This commit is contained in:
Stenzek
2025-12-06 15:55:42 +10:00
parent f7ca150c79
commit d9f8302292
13 changed files with 98 additions and 15 deletions

View File

@@ -101,13 +101,14 @@ static constexpr u32 SETTINGS_SAVE_DELAY = 1000;
static constexpr u32 NUM_ASYNC_WORKER_THREADS = 2;
/// Interval at which the controllers are polled when the system is not active.
static constexpr u32 BACKGROUND_CONTROLLER_POLLING_INTERVAL = 100;
static constexpr int BACKGROUND_CONTROLLER_POLLING_INTERVAL_WITH_DEVICES = 100;
static constexpr int BACKGROUND_CONTROLLER_POLLING_INTERVAL_WITHOUT_DEVICES = 1000;
/// Poll at half the vsync rate for FSUI to reduce the chance of getting a press+release in the same frame.
static constexpr u32 FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL = 8;
static constexpr int FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL = 8;
/// Poll at 1ms when running GDB server. We can get rid of this once we move networking to its own thread.
static constexpr u32 GDB_SERVER_POLLING_INTERVAL = 1;
static constexpr int GDB_SERVER_POLLING_INTERVAL = 1;
//////////////////////////////////////////////////////////////////////////
// Local function declarations
@@ -1870,15 +1871,14 @@ void EmuThread::destroyBackgroundControllerPollTimer()
void EmuThread::startBackgroundControllerPollTimer()
{
if (m_background_controller_polling_timer->isActive())
{
updateBackgroundControllerPollInterval();
return;
}
u32 poll_interval = BACKGROUND_CONTROLLER_POLLING_INTERVAL;
if (m_gpu_thread_run_idle)
poll_interval = FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL;
if (GDBServer::HasAnyClients())
poll_interval = GDB_SERVER_POLLING_INTERVAL;
m_background_controller_polling_timer->start(poll_interval);
const int interval = getBackgroundControllerPollInterval();
DEV_LOG("Starting background controller polling timer with interval {} ms", interval);
m_background_controller_polling_timer->start(interval);
}
void EmuThread::stopBackgroundControllerPollTimer()
@@ -1886,9 +1886,42 @@ void EmuThread::stopBackgroundControllerPollTimer()
if (!m_background_controller_polling_timer->isActive())
return;
DEV_LOG("Stopping background controller polling timer");
m_background_controller_polling_timer->stop();
}
void EmuThread::updateBackgroundControllerPollInterval()
{
if (!isCurrentThread())
{
QMetaObject::invokeMethod(this, &EmuThread::updateBackgroundControllerPollInterval, Qt::QueuedConnection);
return;
}
if (!m_background_controller_polling_timer || !m_background_controller_polling_timer->isActive())
return;
const int current_interval = m_background_controller_polling_timer->interval();
const int new_interval = getBackgroundControllerPollInterval();
if (current_interval != new_interval)
{
WARNING_LOG("Changed background polling interval from {} ms to {} ms", current_interval, new_interval);
m_background_controller_polling_timer->setInterval(new_interval);
}
}
int EmuThread::getBackgroundControllerPollInterval() const
{
if (GDBServer::HasAnyClients())
return GDB_SERVER_POLLING_INTERVAL;
else if (m_gpu_thread_run_idle)
return FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL;
else if (InputManager::GetPollableDeviceCount() > 0)
return BACKGROUND_CONTROLLER_POLLING_INTERVAL_WITH_DEVICES;
else
return BACKGROUND_CONTROLLER_POLLING_INTERVAL_WITHOUT_DEVICES;
}
void EmuThread::setGPUThreadRunIdle(bool active)
{
if (!isCurrentThread())
@@ -1907,8 +1940,7 @@ void EmuThread::setGPUThreadRunIdle(bool active)
if (!m_background_controller_polling_timer->isActive())
return;
g_emu_thread->stopBackgroundControllerPollTimer();
g_emu_thread->startBackgroundControllerPollTimer();
g_emu_thread->updateBackgroundControllerPollInterval();
}
void EmuThread::updateFullscreenUITheme()
@@ -2695,6 +2727,7 @@ void Host::OnInputDeviceConnected(InputBindingKey key, std::string_view identifi
QMetaObject::invokeMethod(g_emu_thread->getInputDeviceListModel(), &InputDeviceListModel::onDeviceConnected,
Qt::QueuedConnection, key, QtUtils::StringViewToQString(identifier),
QtUtils::StringViewToQString(device_name), qeffect_list);
g_emu_thread->updateBackgroundControllerPollInterval();
if (System::IsValid() || GPUThread::IsFullscreenUIRequested())
{
@@ -2707,6 +2740,7 @@ void Host::OnInputDeviceDisconnected(InputBindingKey key, std::string_view ident
{
QMetaObject::invokeMethod(g_emu_thread->getInputDeviceListModel(), &InputDeviceListModel::onDeviceDisconnected,
Qt::QueuedConnection, key, QtUtils::StringViewToQString(identifier));
g_emu_thread->updateBackgroundControllerPollInterval();
if (g_settings.pause_on_controller_disconnection && System::GetState() == System::State::Running &&
InputManager::HasAnyBindingsForSource(key))

View File

@@ -83,6 +83,7 @@ public:
void startBackgroundControllerPollTimer();
void stopBackgroundControllerPollTimer();
void updateBackgroundControllerPollInterval();
void wakeThread();
void bootOrLoadState(std::string path);
@@ -188,6 +189,7 @@ protected:
void run() override;
private:
int getBackgroundControllerPollInterval() const;
void stopInThread();
void onDisplayWindowMouseButtonEvent(int button, bool pressed);
void onDisplayWindowMouseWheelEvent(float dx, float dy);

View File

@@ -322,6 +322,11 @@ InputManager::DeviceEffectList DInputSource::EnumerateEffects(std::optional<Inpu
return {};
}
u32 DInputSource::GetPollableDeviceCount() const
{
return static_cast<u32>(m_controllers.size());
}
bool DInputSource::GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping)
{
return {};

View File

@@ -43,6 +43,7 @@ public:
InputManager::DeviceList EnumerateDevices() override;
InputManager::DeviceEffectList EnumerateEffects(std::optional<InputBindingInfo::Type> type,
std::optional<InputBindingKey> for_device) override;
u32 GetPollableDeviceCount() const override;
bool GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping) override;
void UpdateMotorState(InputBindingKey key, float intensity) override;
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity,

View File

@@ -2304,6 +2304,21 @@ InputManager::DeviceEffectList InputManager::EnumerateDeviceEffects(std::optiona
return ret;
}
u32 InputManager::GetPollableDeviceCount()
{
std::unique_lock lock(s_state.mutex);
u32 count = 0;
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{
if (s_state.input_sources[i])
count += s_state.input_sources[i]->GetPollableDeviceCount();
}
return count;
}
static void GetKeyboardGenericBindingMapping(std::vector<std::pair<GenericInputBinding, std::string>>* mapping)
{
mapping->emplace_back(GenericInputBinding::DPadUp, "Keyboard/UpArrow");

View File

@@ -281,6 +281,9 @@ using DeviceEffectList = std::vector<std::pair<InputBindingInfo::Type, InputBind
DeviceEffectList EnumerateDeviceEffects(std::optional<InputBindingInfo::Type> type = std::nullopt,
std::optional<InputBindingKey> for_device = std::nullopt);
/// Returns the number of pollable devices across all input sources.
u32 GetPollableDeviceCount();
/// Retrieves bindings that match the generic bindings for the specified device.
GenericInputBindingMapping GetGenericBindingMapping(std::string_view device);

View File

@@ -62,6 +62,9 @@ public:
virtual InputManager::DeviceEffectList EnumerateEffects(std::optional<InputBindingInfo::Type> type,
std::optional<InputBindingKey> for_device) = 0;
/// Returns the number of pollable devices managed by this source.
virtual u32 GetPollableDeviceCount() const = 0;
/// Retrieves bindings that match the generic bindings for the specified device.
/// Returns false if it's not one of our devices.
virtual bool GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping) = 0;

View File

@@ -1118,9 +1118,6 @@ bool SDLInputSource::CloseDevice(SDL_JoystickID joystick_index)
if (it == m_controllers.end())
return false;
InputManager::OnInputDeviceDisconnected(MakeGenericControllerDeviceKey(InputSourceType::SDL, it->player_id),
fmt::format("SDL-{}", it->player_id));
if (it->haptic)
SDL_CloseHaptic(it->haptic);
@@ -1129,7 +1126,12 @@ bool SDLInputSource::CloseDevice(SDL_JoystickID joystick_index)
else
SDL_CloseJoystick(it->joystick);
const int player_id = it->player_id;
m_controllers.erase(it);
InputManager::OnInputDeviceDisconnected(MakeGenericControllerDeviceKey(InputSourceType::SDL, player_id),
fmt::format("SDL-{}", player_id));
return true;
}
@@ -1372,6 +1374,11 @@ InputManager::DeviceEffectList SDLInputSource::EnumerateEffects(std::optional<In
return ret;
}
u32 SDLInputSource::GetPollableDeviceCount() const
{
return static_cast<u32>(m_controllers.size());
}
bool SDLInputSource::GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping)
{
if (!device.starts_with("SDL-"))

View File

@@ -34,6 +34,7 @@ public:
InputManager::DeviceList EnumerateDevices() override;
InputManager::DeviceEffectList EnumerateEffects(std::optional<InputBindingInfo::Type> type,
std::optional<InputBindingKey> for_device) override;
u32 GetPollableDeviceCount() const override;
bool GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping) override;
void UpdateMotorState(InputBindingKey key, float intensity) override;
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity,

View File

@@ -140,6 +140,11 @@ InputManager::DeviceEffectList Win32RawInputSource::EnumerateEffects(std::option
return {};
}
u32 Win32RawInputSource::GetPollableDeviceCount() const
{
return static_cast<u32>(m_mice.size());
}
bool Win32RawInputSource::GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping)
{
return {};

View File

@@ -30,6 +30,7 @@ public:
InputManager::DeviceList EnumerateDevices() override;
InputManager::DeviceEffectList EnumerateEffects(std::optional<InputBindingInfo::Type> type,
std::optional<InputBindingKey> for_device) override;
u32 GetPollableDeviceCount() const override;
bool GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping) override;
void UpdateMotorState(InputBindingKey key, float intensity) override;
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity,

View File

@@ -399,6 +399,11 @@ InputManager::DeviceEffectList XInputSource::EnumerateEffects(std::optional<Inpu
return ret;
}
u32 XInputSource::GetPollableDeviceCount() const
{
return static_cast<u32>(std::ranges::count_if(m_controllers, [](const ControllerData& cd) { return cd.connected; }));
}
bool XInputSource::GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping)
{
if (!device.starts_with("XInput-"))

View File

@@ -45,6 +45,7 @@ public:
InputManager::DeviceList EnumerateDevices() override;
InputManager::DeviceEffectList EnumerateEffects(std::optional<InputBindingInfo::Type> type,
std::optional<InputBindingKey> for_device) override;
u32 GetPollableDeviceCount() const override;
bool GetGenericBindingMapping(std::string_view device, GenericInputBindingMapping* mapping) override;
void UpdateMotorState(InputBindingKey key, float intensity) override;
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity,