From ad339f521253bc6d1101072a145a8b838e4a4ffc Mon Sep 17 00:00:00 2001 From: Megamouse Date: Wed, 8 Jan 2025 02:56:20 +0100 Subject: [PATCH] cellGem: Update controllers at 10 Hz in separate thread Some games don't use cellGemGetInfo. Which means we had to reboot the game if the controller wasn't connected on boot. Updating controllers outside of the cell functions fixes this problem. --- rpcs3/Emu/Cell/Modules/cellGem.cpp | 145 ++++++++++++++++------------- 1 file changed, 79 insertions(+), 66 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index 22988d25e6..28ae92e8d3 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -280,10 +280,74 @@ public: return controllers[gem_num].status == CELL_GEM_STATUS_READY; } + void update_connections() + { + switch (g_cfg.io.move) + { + case move_handler::real: + case move_handler::fake: + { + connected_controllers = 0; + + std::lock_guard lock(pad::g_pad_mutex); + const auto handler = pad::get_current_handler(); + + for (u32 i = 0; i < CELL_GEM_MAX_NUM; i++) + { + const auto& pad = ::at32(handler->GetPads(), pad_num(i)); + const bool connected = (pad && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && i < attribute.max_connect); + const bool is_real_move = g_cfg.io.move != move_handler::real || pad->m_pad_handler == pad_handler::move; + + if (connected && is_real_move) + { + connected_controllers++; + controllers[i].status = CELL_GEM_STATUS_READY; + controllers[i].port = port_num(i); + } + else + { + controllers[i].status = CELL_GEM_STATUS_DISCONNECTED; + controllers[i].port = 0; + } + } + break; + } + case move_handler::raw_mouse: + { + connected_controllers = 0; + + auto& handler = g_fxo->get(); + std::lock_guard mouse_lock(handler.mutex); + + const MouseInfo& info = handler.GetInfo(); + + for (u32 i = 0; i < CELL_GEM_MAX_NUM; i++) + { + const bool connected = i < attribute.max_connect && info.status[i] == CELL_MOUSE_STATUS_CONNECTED; + + if (connected) + { + connected_controllers++; + controllers[i].status = CELL_GEM_STATUS_READY; + controllers[i].port = port_num(i); + } + else + { + controllers[i].status = CELL_GEM_STATUS_DISCONNECTED; + controllers[i].port = 0; + } + } + break; + } + default: + { + break; + } + } + } + void update_calibration_status() { - std::scoped_lock lock(mtx); - for (u32 gem_num = 0; gem_num < CELL_GEM_MAX_NUM; gem_num++) { gem_controller& controller = controllers[gem_num]; @@ -1154,13 +1218,25 @@ void gem_config_data::operator()() { cellGem.notice("Starting thread"); + u64 last_update_us = 0; + while (thread_ctrl::state() != thread_state::aborting && !Emu.IsStopped()) { while (!video_conversion_in_progress && thread_ctrl::state() != thread_state::aborting && !Emu.IsStopped()) { if (state) { - update_calibration_status(); + const u64 now_us = get_system_time(); + constexpr u64 update_timeout = 100000; // Update controllers at 10Hz + + if (now_us - last_update_us >= update_timeout) + { + last_update_us = now_us; + + std::scoped_lock lock(mtx); + update_connections(); + update_calibration_status(); + } } thread_ctrl::wait_for(1000); @@ -2632,69 +2708,6 @@ error_code cellGemGetInfo(vm::ptr info) return CELL_GEM_ERROR_INVALID_PARAMETER; } - switch (g_cfg.io.move) - { - case move_handler::real: - case move_handler::fake: - { - gem.connected_controllers = 0; - - std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); - - for (u32 i = 0; i < CELL_GEM_MAX_NUM; i++) - { - const auto& pad = ::at32(handler->GetPads(), pad_num(i)); - const bool connected = (pad && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && i < gem.attribute.max_connect); - const bool is_real_move = g_cfg.io.move != move_handler::real || pad->m_pad_handler == pad_handler::move; - - if (connected && is_real_move) - { - gem.connected_controllers++; - gem.controllers[i].status = CELL_GEM_STATUS_READY; - gem.controllers[i].port = port_num(i); - } - else - { - gem.controllers[i].status = CELL_GEM_STATUS_DISCONNECTED; - gem.controllers[i].port = 0; - } - } - break; - } - case move_handler::raw_mouse: - { - gem.connected_controllers = 0; - - auto& handler = g_fxo->get(); - std::lock_guard mouse_lock(handler.mutex); - - const MouseInfo& info = handler.GetInfo(); - - for (u32 i = 0; i < CELL_GEM_MAX_NUM; i++) - { - const bool connected = i < gem.attribute.max_connect && info.status[i] == CELL_MOUSE_STATUS_CONNECTED; - - if (connected) - { - gem.connected_controllers++; - gem.controllers[i].status = CELL_GEM_STATUS_READY; - gem.controllers[i].port = port_num(i); - } - else - { - gem.controllers[i].status = CELL_GEM_STATUS_DISCONNECTED; - gem.controllers[i].port = 0; - } - } - break; - } - default: - { - break; - } - } - info->max_connect = gem.attribute.max_connect; info->now_connect = gem.connected_controllers;