diff --git a/rpcs3/Emu/Cell/Modules/cellCamera.cpp b/rpcs3/Emu/Cell/Modules/cellCamera.cpp index 64135ca5fa..95cf0a56f9 100644 --- a/rpcs3/Emu/Cell/Modules/cellCamera.cpp +++ b/rpcs3/Emu/Cell/Modules/cellCamera.cpp @@ -148,9 +148,44 @@ void camera_context::save(utils::serial& ar) return; } - GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellCamera); + const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellCamera); ar(notify_data_map, start_timestamp_us, read_mode, is_streaming, is_attached, is_open, info, attr, frame_num); + + if (ar.is_writing() || version >= 2) + { + ar(is_attached_dirty); + } + + if (!ar.is_writing()) + { + if (is_open) + { + if (!open_camera()) + { + cellCamera.error("Failed to open camera while loading savestate"); + } + else if (is_streaming && !start_camera()) + { + cellCamera.error("Failed to start camera while loading savestate"); + } + } + } +} + +gem_camera_shared::gem_camera_shared(utils::serial& ar) +{ + save(ar); +} + +void gem_camera_shared::save(utils::serial& ar) +{ + const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellCamera); + + if (ar.is_writing() || version >= 2) + { + ar(frame_timestamp_us, width, height, size, format); + } } static bool check_dev_num(s32 dev_num) @@ -435,7 +470,6 @@ error_code cellCameraInit() g_camera.attr[CELL_CAMERA_USBLOAD] = { 4 }; break; } - case fake_camera_type::eyetoy2: { g_camera.attr[CELL_CAMERA_SATURATION] = { 64 }; @@ -455,7 +489,6 @@ error_code cellCameraInit() g_camera.attr[CELL_CAMERA_AGCHIGH] = { 64 }; break; } - case fake_camera_type::uvc1_1: { g_camera.attr[CELL_CAMERA_DEVICEID] = { 0x5ca, 0x18d0 }; // KBCR-S01MU @@ -463,14 +496,14 @@ error_code cellCameraInit() g_camera.attr[CELL_CAMERA_NUMFRAME] = { 1 }; // Amount of supported resolutions break; } - default: cellCamera.todo("Trying to init cellCamera with un-researched camera type."); + break; } // TODO: Some other default attributes? Need to check the actual behaviour on a real PS3. - g_camera.is_attached = true; + g_camera.is_attached = g_cfg.io.camera != camera_handler::null; g_camera.init = 1; return CELL_OK; } @@ -816,8 +849,8 @@ s32 cellCameraIsAttached(s32 dev_num) // normally should be attached immediately after event queue is registered, but just to be sure if (!is_attached) { - g_camera.send_attach_state(true); - is_attached = g_camera.is_attached; + g_camera.is_attached = is_attached = true; + g_camera.is_attached_dirty = true; } } @@ -1606,9 +1639,15 @@ void camera_context::operator()() { while (thread_ctrl::state() != thread_state::aborting && !Emu.IsStopped()) { + // send ATTACH event + if (init && is_attached_dirty && !Emu.IsPaused()) + { + send_attach_state(is_attached); + } + const s32 fps = info.framerate; - if (!fps || Emu.IsPaused() || g_cfg.io.camera == camera_handler::null) + if (!init || !fps || Emu.IsPaused() || g_cfg.io.camera == camera_handler::null) { thread_ctrl::wait_for(1000); // hack continue; @@ -1783,6 +1822,7 @@ void camera_context::reset_state() read_mode = CELL_CAMERA_READ_FUNCCALL; is_streaming = false; is_attached = false; + is_attached_dirty = false; is_open = false; info.framerate = 0; std::memset(&attr, 0, sizeof(attr)); @@ -1828,6 +1868,7 @@ void camera_context::send_attach_state(bool attached) // We're not expected to send any events for attaching/detaching is_attached = attached; + is_attached_dirty = false; } void camera_context::set_attr(s32 attrib, u32 arg1, u32 arg2) @@ -1862,15 +1903,13 @@ void camera_context::set_attr(s32 attrib, u32 arg1, u32 arg2) void camera_context::add_queue(u64 key, u64 source, u64 flag) { - std::lock_guard lock(mutex); { std::lock_guard lock_data_map(mutex_notify_data_map); notify_data_map[key] = { source, flag }; } - // send ATTACH event - HACKY - send_attach_state(is_attached); + is_attached_dirty = true; } void camera_context::remove_queue(u64 key) @@ -1897,7 +1936,8 @@ bool camera_context::on_handler_state(camera_handler_base::camera_handler_state { if (is_attached) { - send_attach_state(false); + is_attached = false; + is_attached_dirty = true; } if (handler) { @@ -1938,7 +1978,8 @@ bool camera_context::on_handler_state(camera_handler_base::camera_handler_state if (!is_attached) { cellCamera.warning("Camera handler not attached. Sending attach event...", static_cast(state)); - send_attach_state(true); + is_attached = true; + is_attached_dirty = true; } break; } diff --git a/rpcs3/Emu/Cell/Modules/cellCamera.h b/rpcs3/Emu/Cell/Modules/cellCamera.h index ae4786cdcc..28e8a3152c 100644 --- a/rpcs3/Emu/Cell/Modules/cellCamera.h +++ b/rpcs3/Emu/Cell/Modules/cellCamera.h @@ -427,6 +427,7 @@ public: atomic_t read_mode{CELL_CAMERA_READ_FUNCCALL}; atomic_t is_streaming{false}; atomic_t is_attached{false}; + atomic_t is_attached_dirty{false}; atomic_t is_open{false}; CellCameraInfoEx info{}; @@ -471,6 +472,13 @@ using camera_thread = named_thread; /// Shared data between cellGem and cellCamera struct gem_camera_shared { + gem_camera_shared() {} + gem_camera_shared(utils::serial& ar); + + void save(utils::serial& ar); + + SAVESTATE_INIT_POS(7); + atomic_t frame_timestamp_us{}; // latest read timestamp from cellCamera (cellCameraRead(Ex)) atomic_t width{640}; atomic_t height{480}; diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index da3c7f6261..d9585f1dcd 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -247,7 +247,7 @@ public: u32 hue = 0; // Tracking hue of the motion controller f32 distance_mm{3000.0f}; // Distance from the camera in mm f32 radius{5.0f}; // Radius of the sphere in camera pixels - bool radius_valid = true; // If the radius and distance of the sphere was computed. + bool radius_valid = false; // If the radius and distance of the sphere was computed. Also used for visibility. bool is_calibrating{false}; // Whether or not we are currently calibrating u64 calibration_start_us{0}; // The start timestamp of the calibration in microseconds @@ -292,6 +292,12 @@ public: bool wait_for_result(ppu_thread& ppu) { + // Notify gem thread that the initial state after loading a savestate can be updated. + if (m_done.compare_and_swap_test(2, 0)) + { + m_done.notify_one(); + } + while (!m_done && !ppu.is_stopped()) { thread_ctrl::wait_on(m_done, 0); @@ -323,7 +329,8 @@ public: connected_controllers = 0; std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(true); + if (!handler) break; for (u32 i = 0; i < CELL_GEM_MAX_NUM; i++) { @@ -392,7 +399,7 @@ public: if (g_cfg.io.move == move_handler::real) { std::lock_guard pad_lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); if (pad && pad->m_pad_handler == pad_handler::move) { @@ -422,7 +429,7 @@ public: if (g_cfg.io.move == move_handler::real) { std::lock_guard pad_lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); if (pad && pad->m_pad_handler == pad_handler::move) { @@ -452,7 +459,7 @@ public: { connected_controllers = 0; std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); for (u32 i = 0; i < std::min(attribute.max_connect, CELL_GEM_MAX_NUM); i++) { const auto& pad = ::at32(handler->GetPads(), pad_num(i)); @@ -473,7 +480,7 @@ public: { connected_controllers = 0; std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); for (u32 i = 0; i < std::min(attribute.max_connect, CELL_GEM_MAX_NUM); i++) { const auto& pad = ::at32(handler->GetPads(), pad_num(i)); @@ -540,7 +547,7 @@ public: load_configs(); }; - SAVESTATE_INIT_POS(15); + SAVESTATE_INIT_POS(16.1); // Depends on cellCamera void save(utils::serial& ar) { @@ -581,6 +588,11 @@ public: } ar(connected_controllers, updating, camera_frame, memory_ptr, start_timestamp_us); + + if (ar.is_writing() || version >= 3) + { + ar(video_conversion_in_progress, video_data_out_size); + } } gem_config_data(utils::serial& ar) @@ -685,7 +697,7 @@ namespace gem bool convert_image_format(CellCameraFormat input_format, CellGemVideoConvertFormatEnum output_format, const std::vector& video_data_in, u32 width, u32 height, - u8* video_data_out, u32 video_data_out_size) + u8* video_data_out, u32 video_data_out_size, std::string_view caller) { if (output_format != CELL_GEM_NO_VIDEO_OUTPUT && !video_data_out) { @@ -697,13 +709,13 @@ namespace gem if (video_data_in.size() != required_in_size) { - cellGem.error("convert: in_size mismatch: required=%d, actual=%d", required_in_size, video_data_in.size()); + cellGem.error("convert: in_size mismatch: required=%d, actual=%d (called from %s)", required_in_size, video_data_in.size(), caller); return false; } if (required_out_size < 0 || video_data_out_size != static_cast(required_out_size)) { - cellGem.error("convert: out_size unknown: required=%d, format %d", required_out_size, output_format); + cellGem.error("convert: out_size unknown: required=%d, actual=%d, format %d (called from %s)", required_out_size, video_data_out_size, output_format, caller); return false; } @@ -763,7 +775,7 @@ namespace gem } default: { - cellGem.error("Unimplemented: Converting %s to %s", input_format, output_format); + cellGem.error("Unimplemented: Converting %s to %s (called from %s)", input_format, output_format, caller); std::memcpy(video_data_out, video_data_in.data(), std::min(required_in_size, required_out_size)); return false; } @@ -778,7 +790,7 @@ namespace gem } else { - cellGem.error("Unimplemented: Converting %s to %s", input_format, output_format); + cellGem.error("Unimplemented: Converting %s to %s (called from %s)", input_format, output_format, caller); return false; } break; @@ -860,7 +872,7 @@ namespace gem } default: { - cellGem.error("Unimplemented: Converting %s to %s", input_format, output_format); + cellGem.error("Unimplemented: Converting %s to %s (called from %s)", input_format, output_format, caller); std::memcpy(video_data_out, video_data_in.data(), std::min(required_in_size, required_out_size)); return false; } @@ -950,7 +962,7 @@ namespace gem } default: { - cellGem.error("Unimplemented: Converting %s to %s", input_format, output_format); + cellGem.error("Unimplemented: Converting %s to %s (called from %s)", input_format, output_format, caller); std::memcpy(video_data_out, video_data_in.data(), std::min(required_in_size, required_out_size)); return false; } @@ -1060,7 +1072,7 @@ namespace gem } default: { - cellGem.error("Unimplemented: Converting %s to %s", input_format, output_format); + cellGem.error("Unimplemented: Converting %s to %s (called from %s)", input_format, output_format, caller); std::memcpy(video_data_out, video_data_in.data(), std::min(required_in_size, required_out_size)); return false; } @@ -1122,7 +1134,7 @@ namespace gem } default: { - cellGem.error("Unimplemented: Converting %s to %s", input_format, output_format); + cellGem.error("Unimplemented: Converting %s to %s (called from %s)", input_format, output_format, caller); std::memcpy(video_data_out, video_data_in.data(), std::min(required_in_size, required_out_size)); return false; } @@ -1132,18 +1144,18 @@ namespace gem case CELL_GEM_BAYER_RESTORED_RGGB: // Restored Bayer output, 2x2 pixels rearranged into 320x240 RG1G2B case CELL_GEM_BAYER_RESTORED_RASTERIZED: // Restored Bayer output, R,G1,G2,B rearranged into 4 contiguous 320x240 1-channel rasters { - cellGem.error("Unimplemented: Converting %s to %s", input_format, output_format); + cellGem.error("Unimplemented: Converting %s to %s (called from %s)", input_format, output_format, caller); std::memcpy(video_data_out, video_data_in.data(), std::min(required_in_size, required_out_size)); return false; } case CELL_GEM_NO_VIDEO_OUTPUT: // Disable video output { - cellGem.trace("Ignoring frame conversion for CELL_GEM_NO_VIDEO_OUTPUT"); + cellGem.trace("Ignoring frame conversion for CELL_GEM_NO_VIDEO_OUTPUT (called from %s)", caller); break; } default: { - cellGem.error("Trying to convert %s to %s", input_format, output_format); + cellGem.error("Trying to convert %s to %s (called from %s)", input_format, output_format, caller); return false; } } @@ -1253,6 +1265,18 @@ void gem_config_data::operator()() u64 last_update_us = 0; + // Handle initial state after loading a savestate + if (state && video_conversion_in_progress) + { + // Wait for cellGemConvertVideoFinish. The initial savestate loading may take a while. + m_done = 2; // Use special value 2 for this case + thread_ctrl::wait_on(m_done, 2, 5'000'000); + + // Just mark this conversion as complete (there's no real downside to this, except for a black image) + video_conversion_in_progress = false; + done(); + } + while (thread_ctrl::state() != thread_state::aborting && !Emu.IsStopped()) { u64 timeout = umax; @@ -1310,7 +1334,7 @@ void gem_config_data::operator()() const auto& shared_data = g_fxo->get(); - if (gem::convert_image_format(shared_data.format, vc.output_format, video_data_in, shared_data.width, shared_data.height, vc_attribute.video_data_out ? vc_attribute.video_data_out.get_ptr() : nullptr, video_data_out_size)) + if (gem::convert_image_format(shared_data.format, vc.output_format, video_data_in, shared_data.width, shared_data.height, vc_attribute.video_data_out ? vc_attribute.video_data_out.get_ptr() : nullptr, video_data_out_size, "cellGem")) { cellGem.trace("Converted video frame of format %s to %s", shared_data.format.load(), vc.output_format.get()); @@ -1459,7 +1483,7 @@ public: // Update PS Move LED colors { std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); auto& handlers = handler->get_handlers(); if (auto it = handlers.find(pad_handler::move); it != handlers.end() && it->second) { @@ -1574,13 +1598,17 @@ static inline void draw_overlay_cursor(u32 gem_num, const gem_config::gem_contro rsx::overlays::set_cursor(rsx::overlays::cursor_offset::cell_gem + gem_num, x, y, color, 2'000'000, false); } -static inline void pos_to_gem_image_state(u32 gem_num, const gem_config::gem_controller& controller, vm::ptr& gem_image_state, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max) +static inline void pos_to_gem_image_state(u32 gem_num, gem_config::gem_controller& controller, vm::ptr& gem_image_state, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max) { const auto& shared_data = g_fxo->get(); if (x_max <= 0) x_max = shared_data.width; if (y_max <= 0) y_max = shared_data.height; + // Move the cursor out of the screen if we're at the screen border (Time Crisis 4 needs this) + if (x_pos <= 0) x_pos -= x_max / 10; else if (x_pos >= x_max) x_pos += x_max / 10; + if (y_pos <= 0) y_pos -= y_max / 10; else if (y_pos >= y_max) y_pos += y_max / 10; + const f32 scaling_width = x_max / static_cast(shared_data.width); const f32 scaling_height = y_max / static_cast(shared_data.height); const f32 mmPerPixel = CELL_GEM_SPHERE_RADIUS_MM / controller.radius; @@ -1605,6 +1633,13 @@ static inline void pos_to_gem_image_state(u32 gem_num, const gem_config::gem_con gem_image_state->projectionx = camera_x / controller.distance_mm; gem_image_state->projectiony = camera_y / controller.distance_mm; + // Update visibility for fake handlers + if (g_cfg.io.move != move_handler::real) + { + // Let's say the sphere is not visible if the position is at the edge of the screen + controller.radius_valid = x_pos > 0 && x_pos < x_max && y_pos > 0 && y_pos < y_max; + } + if (g_cfg.io.show_move_cursor) { draw_overlay_cursor(gem_num, controller, x_pos, y_pos, x_max, y_max); @@ -1623,6 +1658,10 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con if (x_max <= 0) x_max = shared_data.width; if (y_max <= 0) y_max = shared_data.height; + // Move the cursor out of the screen if we're at the screen border (Time Crisis 4 needs this) + if (x_pos <= 0) x_pos -= x_max / 10; else if (x_pos >= x_max) x_pos += x_max / 10; + if (y_pos <= 0) y_pos -= y_max / 10; else if (y_pos >= y_max) y_pos += y_max / 10; + const f32 scaling_width = x_max / static_cast(shared_data.width); const f32 scaling_height = y_max / static_cast(shared_data.height); const f32 mmPerPixel = CELL_GEM_SPHERE_RADIUS_MM / controller.radius; @@ -1688,6 +1727,13 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con gem_state->quat[3] = q_w; } + // Update visibility for fake handlers + if (g_cfg.io.move != move_handler::real) + { + // Let's say the sphere is not visible if the position is at the edge of the screen + controller.radius_valid = x_pos > 0 && x_pos < x_max && y_pos > 0 && y_pos < y_max; + } + if (g_cfg.io.show_move_cursor) { draw_overlay_cursor(gem_num, controller, x_pos, y_pos, x_max, y_max); @@ -1706,7 +1752,7 @@ extern bool is_input_allowed(); * Unavoidably buttons conflict with DS3 mappings, which is problematic for some games. * \param gem_num gem index to use * \param digital_buttons Bitmask filled with CELL_GEM_CTRL_* values - * \param analog_t Analog value of Move's Trigger. Currently mapped to R2. + * \param analog_t Analog value of Move's Trigger. * \return true on success, false if controller is disconnected */ static void ds3_input_to_pad(const u32 gem_num, be_t& digital_buttons, be_t& analog_t) @@ -1721,7 +1767,7 @@ static void ds3_input_to_pad(const u32 gem_num, be_t& digital_buttons, be_t std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) @@ -1786,22 +1832,17 @@ static inline void ds3_get_stick_values(u32 gem_num, const std::shared_ptr& const auto& cfg = ::at32(g_cfg_gem_fake.players, gem_num); cfg->handle_input(pad, true, [&](gem_btn btn, pad_button /*pad_btn*/, u16 value, bool pressed, bool& /*abort*/) - { - if (!pressed) - return; + { + if (!pressed) + return; - switch (btn) - { - case gem_btn::x_axis: - x_pos = value; - break; - case gem_btn::y_axis: - y_pos = value; - break; - default: - break; - } - }); + switch (btn) + { + case gem_btn::x_axis: x_pos = value; break; + case gem_btn::y_axis: y_pos = value; break; + default: break; + } + }); } template @@ -1814,7 +1855,7 @@ static void ds3_pos_to_gem_state(u32 gem_num, gem_config::gem_controller& contro std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) @@ -1845,7 +1886,7 @@ static void ps_move_pos_to_gem_state(u32 gem_num, gem_config::gem_controller& co std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); if (pad->m_pad_handler != pad_handler::move || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) @@ -1890,7 +1931,7 @@ static void ds3_input_to_ext(u32 gem_num, gem_config::gem_controller& controller std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) @@ -2071,7 +2112,7 @@ static bool mouse_input_to_pad(u32 mouse_no, be_t& digital_buttons, be_t& digital_buttons, be_t& if (gun.handler.get_button(gem_no, gun_button::btn_6) == 1) digital_buttons |= CELL_GEM_CTRL_SQUARE; - analog_t = gun.handler.get_button(gem_no, gun_button::btn_left) ? 0xFFFF : 0; + analog_t = gun.handler.get_button(gem_no, gun_button::btn_left) ? 255 : 0; return true; } @@ -2350,7 +2391,7 @@ error_code cellGemEnableMagnetometer(u32 gem_num, u32 enable) { std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); if (pad && pad->m_pad_handler == pad_handler::move) @@ -2398,7 +2439,7 @@ error_code cellGemEnableMagnetometer2(u32 gem_num, u32 enable) { std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); if (pad && pad->m_pad_handler == pad_handler::move) @@ -2416,7 +2457,7 @@ error_code cellGemEnd(ppu_thread& ppu) auto& gem = g_fxo->get(); - std::scoped_lock lock(gem.mtx); + std::unique_lock lock(gem.mtx); if (gem.state.compare_and_swap_test(1, 0)) { @@ -2428,6 +2469,8 @@ error_code cellGemEnd(ppu_thread& ppu) return CELL_OK; } + lock.unlock(); + auto& tracker = g_fxo->get>(); if (!tracker.wait_for_tracker_result(ppu)) { @@ -2464,7 +2507,7 @@ error_code cellGemFilterState(u32 gem_num, u32 enable) error_code cellGemForceRGB(u32 gem_num, f32 r, f32 g, f32 b) { - cellGem.todo("cellGemForceRGB(gem_num=%d, r=%f, g=%f, b=%f)", gem_num, r, g, b); + cellGem.warning("cellGemForceRGB(gem_num=%d, r=%f, g=%f, b=%f)", gem_num, r, g, b); auto& gem = g_fxo->get(); @@ -2631,6 +2674,7 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr gem_imag cellGem.warning("cellGemGetImageState(gem_num=%d, image_state=&0x%x)", gem_num, gem_image_state); auto& gem = g_fxo->get(); + std::scoped_lock lock(gem.mtx); if (!gem.state) { @@ -2646,15 +2690,11 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr gem_imag if (g_cfg.io.move != move_handler::null) { - auto& shared_data = g_fxo->get(); + const auto& shared_data = g_fxo->get(); auto& controller = gem.controllers[gem_num]; gem_image_state->frame_timestamp = shared_data.frame_timestamp_us.load(); gem_image_state->timestamp = gem_image_state->frame_timestamp + 10; - gem_image_state->r = controller.radius; // Radius in camera pixels - gem_image_state->distance = controller.distance_mm; - gem_image_state->visible = gem.is_controller_ready(gem_num); - gem_image_state->r_valid = controller.radius_valid; switch (g_cfg.io.move) { @@ -2676,6 +2716,11 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr gem_imag case move_handler::null: fmt::throw_exception("Unreachable"); } + + gem_image_state->r = controller.radius; // Radius in camera pixels + gem_image_state->distance = controller.distance_mm; + gem_image_state->visible = controller.radius_valid && gem.is_controller_ready(gem_num); + gem_image_state->r_valid = controller.radius_valid; } return CELL_OK; @@ -2723,7 +2768,7 @@ error_code cellGemGetInertialState(u32 gem_num, u32 state_flag, u64 timestamp, v { std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); if (pad && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) @@ -3310,7 +3355,7 @@ error_code cellGemReadExternalPortDeviceInfo(u32 gem_num, vm::ptr ext_id, v { std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); if (pad->m_pad_handler != pad_handler::move || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) @@ -3394,7 +3439,7 @@ error_code cellGemSetRumble(u32 gem_num, u8 rumble) if (g_cfg.io.move == move_handler::real) { std::lock_guard pad_lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); auto& handlers = handler->get_handlers(); if (auto it = handlers.find(pad_handler::move); it != handlers.end() && it->second) { @@ -3533,8 +3578,6 @@ error_code cellGemUpdateFinish(ppu_thread& ppu) return CELL_GEM_ERROR_UNINITIALIZED; } - std::scoped_lock lock(gem.mtx); - if (!gem.updating) { return CELL_GEM_ERROR_UPDATE_NOT_STARTED; @@ -3546,6 +3589,8 @@ error_code cellGemUpdateFinish(ppu_thread& ppu) return {}; } + std::scoped_lock lock(gem.mtx); + gem.updating = false; if (!gem.camera_frame) @@ -3624,7 +3669,7 @@ error_code cellGemWriteExternalPort(u32 gem_num, vm::ptrGetPads(), pad_num(gem_num)); if (pad->m_pad_handler != pad_handler::move || !(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) diff --git a/rpcs3/Emu/Cell/Modules/cellPad.cpp b/rpcs3/Emu/Cell/Modules/cellPad.cpp index 771bb04a6e..74b3c5fc60 100644 --- a/rpcs3/Emu/Cell/Modules/cellPad.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPad.cpp @@ -196,7 +196,7 @@ bool cellPad_NotifyStateChange(usz index, u64 /*state*/, bool locked, bool is_bl return true; } - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); const auto& pad = pads[index]; @@ -268,7 +268,7 @@ error_code cellPadInit(ppu_thread& ppu, u32 max_connect) config.port_setting.fill(CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF); config.reported_info = {}; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); for (usz i = 0; i < config.get_max_connect(); ++i) @@ -336,7 +336,7 @@ error_code cellPadClearBuf(u32 port_no) if (port_no >= config.get_max_connect()) return CELL_PAD_ERROR_NO_DEVICE; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; @@ -351,7 +351,7 @@ error_code cellPadClearBuf(u32 port_no) void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) { auto& config = g_fxo->get(); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pad = handler->GetPads()[port_no]; const PadInfo& rinfo = handler->GetInfo(); @@ -709,7 +709,7 @@ error_code cellPadGetData(u32 port_no, vm::ptr data) if (port_no >= config.get_max_connect()) return CELL_PAD_ERROR_NO_DEVICE; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; @@ -740,7 +740,7 @@ error_code cellPadPeriphGetInfo(vm::ptr info) if (!info) return CELL_PAD_ERROR_INVALID_PARAMETER; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const PadInfo& rinfo = handler->GetInfo(); std::memset(info.get_ptr(), 0, sizeof(CellPadPeriphInfo)); @@ -795,7 +795,7 @@ error_code cellPadPeriphGetData(u32 port_no, vm::ptr data) if (port_no >= config.get_max_connect()) return CELL_PAD_ERROR_NO_DEVICE; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; @@ -827,7 +827,7 @@ error_code cellPadGetRawData(u32 port_no, vm::ptr data) if (port_no >= config.get_max_connect()) return CELL_PAD_ERROR_NO_DEVICE; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; @@ -891,7 +891,7 @@ error_code cellPadSetActDirect(u32 port_no, vm::ptr param) if (port_no >= config.get_max_connect()) return CELL_PAD_ERROR_NO_DEVICE; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; @@ -923,7 +923,7 @@ error_code cellPadGetInfo(vm::ptr info) std::memset(info.get_ptr(), 0, sizeof(CellPadInfo)); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const PadInfo& rinfo = handler->GetInfo(); info->max_connect = config.max_connect; info->system_info = rinfo.system_info; @@ -968,7 +968,7 @@ error_code cellPadGetInfo2(vm::ptr info) std::memset(info.get_ptr(), 0, sizeof(CellPadInfo2)); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const PadInfo& rinfo = handler->GetInfo(); info->max_connect = config.get_max_connect(); // Here it is forcibly clamped info->system_info = rinfo.system_info; @@ -1018,7 +1018,7 @@ error_code cellPadGetCapabilityInfo(u32 port_no, vm::ptr if (port_no >= config.get_max_connect()) return CELL_PAD_ERROR_NO_DEVICE; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; @@ -1074,7 +1074,7 @@ error_code cellPadInfoPressMode(u32 port_no) if (port_no >= config.get_max_connect()) return CELL_PAD_ERROR_NO_DEVICE; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; @@ -1101,7 +1101,7 @@ error_code cellPadInfoSensorMode(u32 port_no) if (port_no >= config.get_max_connect()) return CELL_PAD_ERROR_NO_DEVICE; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; @@ -1129,7 +1129,7 @@ error_code cellPadSetPressMode(u32 port_no, u32 mode) if (port_no >= CELL_PAD_MAX_PORT_NUM) return CELL_OK; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; @@ -1163,7 +1163,7 @@ error_code cellPadSetSensorMode(u32 port_no, u32 mode) if (port_no >= CELL_PAD_MAX_PORT_NUM) return CELL_OK; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); const auto& pad = pads[port_no]; @@ -1190,7 +1190,7 @@ error_code cellPadLddRegisterController() if (!config.max_connect) return CELL_PAD_ERROR_UNINITIALIZED; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const s32 handle = handler->AddLddPad(); @@ -1215,7 +1215,7 @@ error_code cellPadLddDataInsert(s32 handle, vm::ptr data) if (!config.max_connect) return CELL_PAD_ERROR_UNINITIALIZED; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); auto& pads = handler->GetPads(); if (handle < 0 || static_cast(handle) >= pads.size() || !data) // data == NULL stalls on decr @@ -1240,7 +1240,7 @@ error_code cellPadLddGetPortNo(s32 handle) if (!config.max_connect) return CELL_PAD_ERROR_UNINITIALIZED; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); auto& pads = handler->GetPads(); if (handle < 0 || static_cast(handle) >= pads.size()) @@ -1264,7 +1264,7 @@ error_code cellPadLddUnregisterController(s32 handle) if (!config.max_connect) return CELL_PAD_ERROR_UNINITIALIZED; - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); if (handle < 0 || static_cast(handle) >= pads.size()) diff --git a/rpcs3/Emu/Cell/lv2/sys_event.cpp b/rpcs3/Emu/Cell/lv2/sys_event.cpp index d5ad126142..db72972b91 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event.cpp @@ -420,10 +420,8 @@ error_code sys_event_queue_tryreceive(ppu_thread& ppu, u32 equeue_id, vm::ptrevents.empty()) { auto& dest = events[count++]; - const auto event = queue->events.front(); + std::tie(dest.source, dest.data1, dest.data2, dest.data3) = queue->events.front(); queue->events.pop_front(); - - std::tie(dest.source, dest.data1, dest.data2, dest.data3) = event; } lock.unlock(); diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp index 45eb5c1858..b914408ec9 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -271,7 +271,7 @@ error_code _sys_process_get_paramsfo(vm::ptr buffer) { sys_process.warning("_sys_process_get_paramsfo(buffer=0x%x)", buffer); - if (!Emu.GetTitleID().length()) + if (Emu.GetTitleID().empty()) { return CELL_ENOENT; } diff --git a/rpcs3/Emu/Io/Buzz.cpp b/rpcs3/Emu/Io/Buzz.cpp index 108bdec0ab..575c5585b1 100644 --- a/rpcs3/Emu/Io/Buzz.cpp +++ b/rpcs3/Emu/Io/Buzz.cpp @@ -146,7 +146,7 @@ void usb_device_buzz::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint*/ } std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); ensure(pads.size() > m_last_controller); ensure(g_cfg_buzz.players.size() > m_last_controller); diff --git a/rpcs3/Emu/Io/GHLtar.cpp b/rpcs3/Emu/Io/GHLtar.cpp index d6fe87e9fc..db60cccd5b 100644 --- a/rpcs3/Emu/Io/GHLtar.cpp +++ b/rpcs3/Emu/Io/GHLtar.cpp @@ -138,7 +138,7 @@ void usb_device_ghltar::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint } std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pad = ::at32(handler->GetPads(), m_controller_index); if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) diff --git a/rpcs3/Emu/Io/GameTablet.cpp b/rpcs3/Emu/Io/GameTablet.cpp index 56286a8bff..31ed81f3af 100644 --- a/rpcs3/Emu/Io/GameTablet.cpp +++ b/rpcs3/Emu/Io/GameTablet.cpp @@ -195,7 +195,7 @@ void usb_device_gametablet::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endp { std::lock_guard lock(pad::g_pad_mutex); - const auto gamepad_handler = pad::get_current_handler(); + const auto gamepad_handler = pad::get_pad_thread(); const auto& pads = gamepad_handler->GetPads(); const auto& pad = ::at32(pads, m_controller_index); if (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) diff --git a/rpcs3/Emu/Io/GunCon3.cpp b/rpcs3/Emu/Io/GunCon3.cpp index 7eef591ecc..d229693907 100644 --- a/rpcs3/Emu/Io/GunCon3.cpp +++ b/rpcs3/Emu/Io/GunCon3.cpp @@ -255,7 +255,7 @@ void usb_device_guncon3::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, { std::lock_guard lock(pad::g_pad_mutex); - const auto gamepad_handler = pad::get_current_handler(); + const auto gamepad_handler = pad::get_pad_thread(); const auto& pads = gamepad_handler->GetPads(); const auto& pad = ::at32(pads, m_controller_index); if (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) diff --git a/rpcs3/Emu/Io/TopShotElite.cpp b/rpcs3/Emu/Io/TopShotElite.cpp index b170027a9f..06cddab9f0 100644 --- a/rpcs3/Emu/Io/TopShotElite.cpp +++ b/rpcs3/Emu/Io/TopShotElite.cpp @@ -315,7 +315,7 @@ void usb_device_topshotelite::interrupt_transfer(u32 buf_size, u8* buf, u32 /*en { std::lock_guard lock(pad::g_pad_mutex); - const auto gamepad_handler = pad::get_current_handler(); + const auto gamepad_handler = pad::get_pad_thread(); const auto& pads = gamepad_handler->GetPads(); const auto& pad = ::at32(pads, m_controller_index); if (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) diff --git a/rpcs3/Emu/Io/TopShotFearmaster.cpp b/rpcs3/Emu/Io/TopShotFearmaster.cpp index aba831fa9c..98b54700d9 100644 --- a/rpcs3/Emu/Io/TopShotFearmaster.cpp +++ b/rpcs3/Emu/Io/TopShotFearmaster.cpp @@ -339,7 +339,7 @@ void usb_device_topshotfearmaster::interrupt_transfer(u32 buf_size, u8* buf, u32 { std::lock_guard lock(pad::g_pad_mutex); - const auto gamepad_handler = pad::get_current_handler(); + const auto gamepad_handler = pad::get_pad_thread(); const auto& pads = gamepad_handler->GetPads(); const auto& pad = ::at32(pads, m_controller_index); if (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) diff --git a/rpcs3/Emu/Io/Turntable.cpp b/rpcs3/Emu/Io/Turntable.cpp index 63bb815a1d..0ef979725e 100644 --- a/rpcs3/Emu/Io/Turntable.cpp +++ b/rpcs3/Emu/Io/Turntable.cpp @@ -151,7 +151,7 @@ void usb_device_turntable::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpo // All other bufs are always 0x00 std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const auto& pads = handler->GetPads(); const auto& pad = ::at32(pads, m_controller_index); diff --git a/rpcs3/Emu/Io/pad_config.cpp b/rpcs3/Emu/Io/pad_config.cpp index cdca3f6101..fb0b140aeb 100644 --- a/rpcs3/Emu/Io/pad_config.cpp +++ b/rpcs3/Emu/Io/pad_config.cpp @@ -32,6 +32,20 @@ std::string cfg_pad::get_buttons(std::vector vec) return fmt::merge(vec, ","); } +u8 cfg_pad::get_large_motor_speed(const std::array& motor_speed) const +{ + const u8 idx = switch_vibration_motors ? 1 : 0; + const f32 multiplier = multiplier_vibration_motor_large / 100.0f; + return static_cast(std::clamp(motor_speed[idx].m_value * multiplier, 0.0f, 255.0f)); +} + +u8 cfg_pad::get_small_motor_speed(const std::array& motor_speed) const +{ + const u8 idx = switch_vibration_motors ? 0 : 1; + const f32 multiplier = multiplier_vibration_motor_small / 100.0f; + return static_cast(std::clamp(motor_speed[idx].m_value * multiplier, 0.0f, 255.0f)); +} + bool cfg_input::load(const std::string& title_id, const std::string& config_file, bool strict) { input_log.notice("Loading pad config (title_id='%s', config_file='%s', strict=%d)", title_id, config_file, strict); diff --git a/rpcs3/Emu/Io/pad_config.h b/rpcs3/Emu/Io/pad_config.h index 5a7517aa72..7c39a79411 100644 --- a/rpcs3/Emu/Io/pad_config.h +++ b/rpcs3/Emu/Io/pad_config.h @@ -28,6 +28,9 @@ struct cfg_pad final : cfg::node static std::vector get_buttons(const std::string& str); static std::string get_buttons(std::vector vec); + u8 get_large_motor_speed(const std::array& motor_speed) const; + u8 get_small_motor_speed(const std::array& motor_speed) const; + cfg::string ls_left{ this, "Left Stick Left", "" }; cfg::string ls_down{ this, "Left Stick Down", "" }; cfg::string ls_right{ this, "Left Stick Right", "" }; @@ -96,8 +99,8 @@ struct cfg_pad final : cfg::node cfg::uint<0, 100> led_battery_indicator_brightness{ this, "LED battery indicator brightness", 50 }; cfg::_bool player_led_enabled{ this, "Player LED enabled", true }; - cfg::_bool enable_vibration_motor_large{ this, "Enable Large Vibration Motor", true }; - cfg::_bool enable_vibration_motor_small{ this, "Enable Small Vibration Motor", true }; + cfg::uint<0, 200> multiplier_vibration_motor_large{ this, "Large Vibration Motor Multiplier", 100 }; + cfg::uint<0, 200> multiplier_vibration_motor_small{ this, "Small Vibration Motor Multiplier", 100 }; cfg::_bool switch_vibration_motors{ this, "Switch Vibration Motors", false }; cfg::_enum mouse_move_mode{ this, "Mouse Movement Mode", mouse_movement_mode::relative }; diff --git a/rpcs3/Emu/Io/usio.cpp b/rpcs3/Emu/Io/usio.cpp index faecec177d..077f6c7d62 100644 --- a/rpcs3/Emu/Io/usio.cpp +++ b/rpcs3/Emu/Io/usio.cpp @@ -189,7 +189,7 @@ void usb_device_usio::save_backup() void usb_device_usio::translate_input_taiko() { std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); std::vector input_buf(0x60); constexpr le_t c_hit = 0x1800; @@ -273,7 +273,7 @@ void usb_device_usio::translate_input_taiko() void usb_device_usio::translate_input_tekken() { std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); std::vector input_buf(0x180); le_t digital_input[2]{}; diff --git a/rpcs3/Emu/RSX/Overlays/overlays.cpp b/rpcs3/Emu/RSX/Overlays/overlays.cpp index e118b3a68c..a1fe40d8ce 100644 --- a/rpcs3/Emu/RSX/Overlays/overlays.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlays.cpp @@ -193,7 +193,7 @@ namespace rsx // Get gamepad input std::lock_guard lock(pad::g_pad_mutex); - const auto handler = pad::get_current_handler(); + const auto handler = pad::get_pad_thread(); const PadInfo& rinfo = handler->GetInfo(); const bool ignore_gamepad_input = (!rinfo.now_connect || !input::g_pads_intercepted); diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 179eb7f1ad..cb31823026 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -417,7 +417,7 @@ void Emulator::Init() if (!fs::rename(old_path, cfg_path, false)) { - sys_log.error("Failed to move '%s' to '%s' (error='%s')", old_path, cfg_path, fs::g_tls_error); + (fs::g_tls_error == fs::error::exist ? sys_log.warning : sys_log.error)("Failed to move '%s' to '%s' (error='%s')", old_path, cfg_path, fs::g_tls_error); } } #endif diff --git a/rpcs3/Emu/games_config.cpp b/rpcs3/Emu/games_config.cpp index 27c086abdf..cfa43f6e15 100644 --- a/rpcs3/Emu/games_config.cpp +++ b/rpcs3/Emu/games_config.cpp @@ -159,7 +159,7 @@ void games_config::load() if (!fs::rename(old_path, path, false)) { - cfg_log.error("Failed to move '%s' to '%s' (error='%s')", old_path, path, fs::g_tls_error); + (fs::g_tls_error == fs::error::exist ? cfg_log.warning : cfg_log.error)("Failed to move '%s' to '%s' (error='%s')", old_path, path, fs::g_tls_error); } } #endif diff --git a/rpcs3/Emu/savestate_utils.cpp b/rpcs3/Emu/savestate_utils.cpp index a40cda95c3..bb3e440564 100644 --- a/rpcs3/Emu/savestate_utils.cpp +++ b/rpcs3/Emu/savestate_utils.cpp @@ -71,8 +71,8 @@ SERIALIZATION_VER(sceNp, 11) SERIALIZATION_VER(cellVdec, 12, 1) SERIALIZATION_VER(cellAudio, 13, 1) -SERIALIZATION_VER(cellCamera, 14, 1) -SERIALIZATION_VER(cellGem, 15, 1, 2/*calibration_status_flags*/) +SERIALIZATION_VER(cellCamera, 14, 1, 2/*gem_camera_shared*/) +SERIALIZATION_VER(cellGem, 15, 1, 2/*calibration_status_flags*/, 3/*video_conversion*/) SERIALIZATION_VER(sceNpTrophy, 16, 1) SERIALIZATION_VER(cellMusic, 17, 1) SERIALIZATION_VER(cellVoice, 18, 1) diff --git a/rpcs3/Input/ds3_pad_handler.cpp b/rpcs3/Input/ds3_pad_handler.cpp index d5dc2ef7d8..0ea5aad19f 100644 --- a/rpcs3/Input/ds3_pad_handler.cpp +++ b/rpcs3/Input/ds3_pad_handler.cpp @@ -551,11 +551,8 @@ void ds3_pad_handler::apply_pad_data(const pad_ensemble& binding) cfg_pad* config = dev->config; - const int idx_l = config->switch_vibration_motors ? 1 : 0; - const int idx_s = config->switch_vibration_motors ? 0 : 1; - - const u8 speed_large = config->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : 0; - const u8 speed_small = config->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : 0; + const u8 speed_large = config->get_large_motor_speed(pad->m_vibrateMotors); + const u8 speed_small = config->get_small_motor_speed(pad->m_vibrateMotors); const bool wireless = dev->cable_state == 0; const bool low_battery = dev->battery_level < 25; diff --git a/rpcs3/Input/ds4_pad_handler.cpp b/rpcs3/Input/ds4_pad_handler.cpp index d7fc6dd9ae..a24351fad9 100644 --- a/rpcs3/Input/ds4_pad_handler.cpp +++ b/rpcs3/Input/ds4_pad_handler.cpp @@ -920,11 +920,8 @@ void ds4_pad_handler::apply_pad_data(const pad_ensemble& binding) cfg_pad* config = dev->config; // Attempt to send rumble no matter what - const int idx_l = config->switch_vibration_motors ? 1 : 0; - const int idx_s = config->switch_vibration_motors ? 0 : 1; - - const u8 speed_large = config->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : 0; - const u8 speed_small = config->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : 0; + const u8 speed_large = config->get_large_motor_speed(pad->m_vibrateMotors); + const u8 speed_small = config->get_small_motor_speed(pad->m_vibrateMotors); const bool wireless = dev->cable_state == 0; const bool low_battery = dev->battery_level < 2; diff --git a/rpcs3/Input/dualsense_pad_handler.cpp b/rpcs3/Input/dualsense_pad_handler.cpp index e7b34b45bf..4c0253adba 100644 --- a/rpcs3/Input/dualsense_pad_handler.cpp +++ b/rpcs3/Input/dualsense_pad_handler.cpp @@ -941,11 +941,8 @@ void dualsense_pad_handler::apply_pad_data(const pad_ensemble& binding) cfg_pad* config = dev->config; // Attempt to send rumble no matter what - const int idx_l = config->switch_vibration_motors ? 1 : 0; - const int idx_s = config->switch_vibration_motors ? 0 : 1; - - const u8 speed_large = config->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : 0; - const u8 speed_small = config->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : 0; + const u8 speed_large = config->get_large_motor_speed(pad->m_vibrateMotors); + const u8 speed_small = config->get_small_motor_speed(pad->m_vibrateMotors); const bool wireless = dev->cable_state == 0; const bool low_battery = dev->battery_level <= 1; diff --git a/rpcs3/Input/evdev_joystick_handler.cpp b/rpcs3/Input/evdev_joystick_handler.cpp index 09872203d6..d101d74173 100644 --- a/rpcs3/Input/evdev_joystick_handler.cpp +++ b/rpcs3/Input/evdev_joystick_handler.cpp @@ -1271,10 +1271,8 @@ void evdev_joystick_handler::apply_pad_data(const pad_ensemble& binding) return; // Handle vibration - const int idx_l = cfg->switch_vibration_motors ? 1 : 0; - const int idx_s = cfg->switch_vibration_motors ? 0 : 1; - const u8 force_large = cfg->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value * 257 : 0; - const u8 force_small = cfg->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : 0; + const u8 force_large = cfg->get_large_motor_speed(pad->m_vibrateMotors); + const u8 force_small = cfg->get_small_motor_speed(pad->m_vibrateMotors); SetRumble(evdev_device, force_large, force_small); } diff --git a/rpcs3/Input/gui_pad_thread.cpp b/rpcs3/Input/gui_pad_thread.cpp index 87fa0999f3..7b69b24209 100644 --- a/rpcs3/Input/gui_pad_thread.cpp +++ b/rpcs3/Input/gui_pad_thread.cpp @@ -40,6 +40,8 @@ LOG_CHANNEL(gui_log, "GUI"); +atomic_t gui_pad_thread::m_reset = false; + gui_pad_thread::gui_pad_thread() { m_thread = std::make_unique(&gui_pad_thread::run, this); @@ -145,6 +147,11 @@ bool gui_pad_thread::init() gui_log.notice("gui_pad_thread: Pad %d: device='%s', handler=%s, VID=0x%x, PID=0x%x, class_type=0x%x, class_profile=0x%x", i, cfg->device.to_string(), m_pad->m_pad_handler, m_pad->m_vendor_id, m_pad->m_product_id, m_pad->m_class_type, m_pad->m_class_profile); + if (handler_type != pad_handler::null) + { + input_log.notice("gui_pad_thread %d: config=\n%s", i, cfg->to_string()); + } + // We only use one pad break; } @@ -251,14 +258,19 @@ void gui_pad_thread::run() gui_log.notice("gui_pad_thread: Pad thread started"); - if (!init()) - { - gui_log.warning("gui_pad_thread: Pad thread stopped (init failed)"); - return; - } + m_reset = true; while (!m_terminate) { + if (m_reset && m_reset.exchange(false)) + { + if (!init()) + { + gui_log.warning("gui_pad_thread: Pad thread stopped (init failed during reset)"); + return; + } + } + // Only process input if there is an active window if (m_handler && m_pad && (m_allow_global_input || QApplication::activeWindow())) { diff --git a/rpcs3/Input/gui_pad_thread.h b/rpcs3/Input/gui_pad_thread.h index 4bc0414200..235d97e8b1 100644 --- a/rpcs3/Input/gui_pad_thread.h +++ b/rpcs3/Input/gui_pad_thread.h @@ -23,6 +23,11 @@ public: static std::shared_ptr GetHandler(pad_handler type); static void InitPadConfig(cfg_pad& cfg, pad_handler type, std::shared_ptr& handler); + static void reset() + { + m_reset = true; + } + protected: bool init(); void run(); @@ -60,6 +65,7 @@ protected: std::unique_ptr m_thread; atomic_t m_terminate = false; atomic_t m_allow_global_input = false; + static atomic_t m_reset; std::array(pad_button::pad_button_max_enum)> m_last_button_state{}; diff --git a/rpcs3/Input/pad_thread.cpp b/rpcs3/Input/pad_thread.cpp index e01663db6c..2b433a6996 100644 --- a/rpcs3/Input/pad_thread.cpp +++ b/rpcs3/Input/pad_thread.cpp @@ -37,7 +37,7 @@ extern std::string g_input_config_override; namespace pad { - atomic_t g_current = nullptr; + atomic_t g_pad_thread = nullptr; shared_mutex g_pad_mutex; std::string g_title_id; atomic_t g_started{false}; @@ -65,13 +65,13 @@ struct pad_setting pad_thread::pad_thread(void* curthread, void* curwindow, std::string_view title_id) : m_curthread(curthread), m_curwindow(curwindow) { pad::g_title_id = title_id; - pad::g_current = this; + pad::g_pad_thread = this; pad::g_started = false; } pad_thread::~pad_thread() { - pad::g_current = nullptr; + pad::g_pad_thread = nullptr; } void pad_thread::Init() diff --git a/rpcs3/Input/pad_thread.h b/rpcs3/Input/pad_thread.h index fe9fa015c5..1939ce0104 100644 --- a/rpcs3/Input/pad_thread.h +++ b/rpcs3/Input/pad_thread.h @@ -70,7 +70,7 @@ private: namespace pad { - extern atomic_t g_current; + extern atomic_t g_pad_thread; extern shared_mutex g_pad_mutex; extern std::string g_title_id; extern atomic_t g_enabled; @@ -78,14 +78,14 @@ namespace pad extern atomic_t g_started; extern atomic_t g_home_menu_requested; - static inline class pad_thread* get_current_handler(bool relaxed = false) + static inline class pad_thread* get_pad_thread(bool relaxed = false) { if (relaxed) { - return g_current.observe(); + return g_pad_thread.observe(); } - return ensure(g_current.load()); + return ensure(g_pad_thread.load()); } static inline void set_enabled(bool enabled) @@ -102,7 +102,7 @@ namespace pad static inline void SetIntercepted(bool intercepted) { std::lock_guard lock(g_pad_mutex); - const auto handler = get_current_handler(); + const auto handler = get_pad_thread(); handler->SetIntercepted(intercepted); } } diff --git a/rpcs3/Input/ps_move_handler.cpp b/rpcs3/Input/ps_move_handler.cpp index b53b4bcd7e..4acf46cf5f 100644 --- a/rpcs3/Input/ps_move_handler.cpp +++ b/rpcs3/Input/ps_move_handler.cpp @@ -820,9 +820,7 @@ void ps_move_handler::apply_pad_data(const pad_ensemble& binding) cfg_pad* config = dev->config; - const int idx_l = config->switch_vibration_motors ? 1 : 0; - - const u8 speed_large = config->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : 0; + const u8 speed_large = config->get_large_motor_speed(pad->m_vibrateMotors); dev->new_output_data |= dev->large_motor != speed_large; dev->large_motor = speed_large; diff --git a/rpcs3/Input/ps_move_tracker.cpp b/rpcs3/Input/ps_move_tracker.cpp index b831e87967..d3deead687 100644 --- a/rpcs3/Input/ps_move_tracker.cpp +++ b/rpcs3/Input/ps_move_tracker.cpp @@ -15,7 +15,7 @@ namespace gem { extern bool convert_image_format(CellCameraFormat input_format, CellGemVideoConvertFormatEnum output_format, const std::vector& video_data_in, u32 width, u32 height, - u8* video_data_out, u32 video_data_out_size); + u8* video_data_out, u32 video_data_out_size, std::string_view caller); } template @@ -238,7 +238,7 @@ void ps_move_tracker::convert_image(s32 output_format) m_image_binary[index].resize(size); } - if (gem::convert_image_format(CellCameraFormat{m_format}, CellGemVideoConvertFormatEnum{output_format}, m_image_data, width, height, m_image_rgba.data(), ::size32(m_image_rgba))) + if (gem::convert_image_format(CellCameraFormat{m_format}, CellGemVideoConvertFormatEnum{output_format}, m_image_data, width, height, m_image_rgba.data(), ::size32(m_image_rgba), "gemTracker")) { ps_move.trace("Converted video frame of format %s to %s", CellCameraFormat{m_format}, CellGemVideoConvertFormatEnum{output_format}); } diff --git a/rpcs3/Input/sdl_pad_handler.cpp b/rpcs3/Input/sdl_pad_handler.cpp index 202eca4038..562085f037 100644 --- a/rpcs3/Input/sdl_pad_handler.cpp +++ b/rpcs3/Input/sdl_pad_handler.cpp @@ -800,13 +800,10 @@ void sdl_pad_handler::apply_pad_data(const pad_ensemble& binding) // The left motor is the low-frequency rumble motor. The right motor is the high-frequency rumble motor. // The two motors are not the same, and they create different vibration effects. Values range between 0 to 65535. - const usz idx_l = cfg->switch_vibration_motors ? 1 : 0; - const usz idx_s = cfg->switch_vibration_motors ? 0 : 1; - if (dev->sdl.has_rumble || dev->sdl.has_rumble_triggers) { - const u8 speed_large = cfg->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : 0; - const u8 speed_small = cfg->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : 0; + const u8 speed_large = cfg->get_large_motor_speed(pad->m_vibrateMotors); + const u8 speed_small = cfg->get_small_motor_speed(pad->m_vibrateMotors); dev->new_output_data |= dev->large_motor != speed_large || dev->small_motor != speed_small; diff --git a/rpcs3/Input/xinput_pad_handler.cpp b/rpcs3/Input/xinput_pad_handler.cpp index d7d3c7991f..49c2467faf 100644 --- a/rpcs3/Input/xinput_pad_handler.cpp +++ b/rpcs3/Input/xinput_pad_handler.cpp @@ -575,11 +575,8 @@ void xinput_pad_handler::apply_pad_data(const pad_ensemble& binding) // The left motor is the low-frequency rumble motor. The right motor is the high-frequency rumble motor. // The two motors are not the same, and they create different vibration effects. Values range between 0 to 65535. - const usz idx_l = cfg->switch_vibration_motors ? 1 : 0; - const usz idx_s = cfg->switch_vibration_motors ? 0 : 1; - - const u8 speed_large = cfg->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : 0; - const u8 speed_small = cfg->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : 0; + const u8 speed_large = cfg->get_large_motor_speed(pad->m_vibrateMotors); + const u8 speed_small = cfg->get_small_motor_speed(pad->m_vibrateMotors); dev->new_output_data |= dev->large_motor != speed_large || dev->small_motor != speed_small; diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index 616d6577aa..9591514dc3 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -20,6 +20,7 @@ #include "Utilities/File.h" #include "Input/pad_thread.h" +#include "Input/gui_pad_thread.h" #include "Input/product_info.h" #include "Input/keyboard_pad_handler.h" @@ -245,6 +246,8 @@ pad_settings_dialog::~pad_settings_dialog() *m_input_thread = thread_state::finished; } + gui_pad_thread::reset(); + if (!Emu.IsStopped()) { pad::reset(Emu.GetTitleID()); @@ -332,33 +335,25 @@ void pad_settings_dialog::InitButtons() } }); - connect(ui->chb_vibration_large, &QCheckBox::clicked, this, [this](bool checked) + connect(ui->sb_vibration_large, &QSpinBox::valueChanged, this, [this](int value) { - if (!checked) - { - return; - } + const u8 force = static_cast(std::clamp(m_max_force * (value / 100.0f), 0.0f, 255.0f)); + ui->chb_vibration_switch->isChecked() ? SetPadData(m_min_force, force) + : SetPadData(force, m_min_force); - ui->chb_vibration_switch->isChecked() ? SetPadData(m_min_force, m_max_force) - : SetPadData(m_max_force, m_min_force); - - QTimer::singleShot(300, [this]() + QTimer::singleShot(300, this, [this]() { SetPadData(m_min_force, m_min_force); }); }); - connect(ui->chb_vibration_small, &QCheckBox::clicked, this, [this](bool checked) + connect(ui->sb_vibration_small, &QSpinBox::valueChanged, this, [this](int value) { - if (!checked) - { - return; - } + const u8 force = static_cast(std::clamp(m_max_force * (value / 100.0f), 0.0f, 255.0f)); + ui->chb_vibration_switch->isChecked() ? SetPadData(force, m_min_force) + : SetPadData(m_min_force, force); - ui->chb_vibration_switch->isChecked() ? SetPadData(m_max_force, m_min_force) - : SetPadData(m_min_force, m_max_force); - - QTimer::singleShot(300, [this]() + QTimer::singleShot(300, this, [this]() { SetPadData(m_min_force, m_min_force); }); @@ -369,12 +364,12 @@ void pad_settings_dialog::InitButtons() checked ? SetPadData(m_min_force, m_max_force) : SetPadData(m_max_force, m_min_force); - QTimer::singleShot(200, [this, checked]() + QTimer::singleShot(200, this, [this, checked]() { checked ? SetPadData(m_max_force, m_min_force) : SetPadData(m_min_force, m_max_force); - QTimer::singleShot(200, [this]() + QTimer::singleShot(200, this, [this]() { SetPadData(m_min_force, m_min_force); }); @@ -618,12 +613,12 @@ void pad_settings_dialog::RefreshPads() } } -void pad_settings_dialog::SetPadData(u32 large_motor, u32 small_motor, bool led_battery_indicator) +void pad_settings_dialog::SetPadData(u8 large_motor, u8 small_motor, bool led_battery_indicator) { - ensure(m_handler); const cfg_pad& cfg = GetPlayerConfig(); std::lock_guard lock(m_handler_mutex); + ensure(m_handler); m_handler->SetPadData(m_device_name, GetPlayerIndex(), large_motor, small_motor, cfg.colorR, cfg.colorG, cfg.colorB, cfg.player_led_enabled.get(), led_battery_indicator, cfg.led_battery_indicator_brightness); } @@ -1116,8 +1111,12 @@ void pad_settings_dialog::UpdateLabels(bool is_reset) } } - ui->chb_vibration_large->setChecked(cfg.enable_vibration_motor_large.get()); - ui->chb_vibration_small->setChecked(cfg.enable_vibration_motor_small.get()); + ui->sb_vibration_large->setRange(cfg.multiplier_vibration_motor_large.min, cfg.multiplier_vibration_motor_large.max); + ui->sb_vibration_large->setValue(cfg.multiplier_vibration_motor_large.get()); + + ui->sb_vibration_small->setRange(cfg.multiplier_vibration_motor_small.min, cfg.multiplier_vibration_motor_small.max); + ui->sb_vibration_small->setValue(cfg.multiplier_vibration_motor_small.get()); + ui->chb_vibration_switch->setChecked(cfg.switch_vibration_motors.get()); // Update Trigger Thresholds @@ -1448,10 +1447,6 @@ void pad_settings_dialog::ChangeHandler() } ui->l_description->setText(m_description); - // Update parameters - m_min_force = 0; - m_max_force = 255; - // Reset parameters m_lx = 0; m_ly = 0; @@ -1873,8 +1868,8 @@ void pad_settings_dialog::ApplyCurrentPlayerConfig(int new_player_id) if (m_handler->has_rumble()) { - cfg.enable_vibration_motor_large.set(ui->chb_vibration_large->isChecked()); - cfg.enable_vibration_motor_small.set(ui->chb_vibration_small->isChecked()); + cfg.multiplier_vibration_motor_large.set(ui->sb_vibration_large->value()); + cfg.multiplier_vibration_motor_small.set(ui->sb_vibration_small->value()); cfg.switch_vibration_motors.set(ui->chb_vibration_switch->isChecked()); } @@ -2025,7 +2020,7 @@ bool pad_settings_dialog::GetIsLddPad(u32 index) const if (!Emu.IsStopped() && (m_title_id.empty() || m_title_id == Emu.GetTitleID())) { std::lock_guard lock(pad::g_pad_mutex); - if (const auto handler = pad::get_current_handler(true)) + if (const auto handler = pad::get_pad_thread(true)) { ensure(index < handler->GetPads().size()); diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.h b/rpcs3/rpcs3qt/pad_settings_dialog.h index 9902dde9ff..c87bf70f95 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/pad_settings_dialog.h @@ -139,8 +139,8 @@ private: int m_ry = 0; // Rumble - s32 m_min_force = 0; - s32 m_max_force = 0; + static constexpr u8 m_min_force = 0; + static constexpr u8 m_max_force = 255; // Backup for standard button palette QPalette m_palette; @@ -190,7 +190,7 @@ private: void CancelExit(); // Set vibrate data while keeping the current color - void SetPadData(u32 large_motor, u32 small_motor, bool led_battery_indicator = false); + void SetPadData(u8 large_motor, u8 small_motor, bool led_battery_indicator = false); /** Update all the Button Labels with current button mapping */ void UpdateLabels(bool is_reset = false); diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.ui b/rpcs3/rpcs3qt/pad_settings_dialog.ui index a886f16b31..0ff621c6a2 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.ui +++ b/rpcs3/rpcs3qt/pad_settings_dialog.ui @@ -937,7 +937,7 @@ Enable Vibration - + 5 @@ -951,22 +951,22 @@ 5 - - - Large + + + % - - true + + Large - - - Small + + + % - - true + + Small diff --git a/rpcs3/rpcs3qt/qt_camera_handler.cpp b/rpcs3/rpcs3qt/qt_camera_handler.cpp index 88d8c15963..4703cf12b6 100644 --- a/rpcs3/rpcs3qt/qt_camera_handler.cpp +++ b/rpcs3/rpcs3qt/qt_camera_handler.cpp @@ -113,6 +113,7 @@ void qt_camera_handler::handle_camera_active(bool is_active) void qt_camera_handler::handle_camera_error(QCamera::Error error, const QString& errorString) { camera_log.error("Error event: \"%s\" (error=%d)", errorString, static_cast(error)); + set_state(camera_handler_state::closed); } void qt_camera_handler::open_camera()