Merge branch 'master' into support-device-change

This commit is contained in:
Megamouse 2025-01-23 08:27:50 +01:00 committed by GitHub
commit c8eabd795b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 308 additions and 204 deletions

View file

@ -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<int>(state));
send_attach_state(true);
is_attached = true;
is_attached_dirty = true;
}
break;
}

View file

@ -427,6 +427,7 @@ public:
atomic_t<u8> read_mode{CELL_CAMERA_READ_FUNCCALL};
atomic_t<bool> is_streaming{false};
atomic_t<bool> is_attached{false};
atomic_t<bool> is_attached_dirty{false};
atomic_t<bool> is_open{false};
CellCameraInfoEx info{};
@ -471,6 +472,13 @@ using camera_thread = named_thread<camera_context>;
/// 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<u64> frame_timestamp_us{}; // latest read timestamp from cellCamera (cellCameraRead(Ex))
atomic_t<s32> width{640};
atomic_t<s32> height{480};

View file

@ -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<u32>(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<u32>(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<u8>& 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<u32>(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<usz>(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<usz>(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<usz>(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<usz>(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<usz>(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<usz>(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<gem_camera_shared>();
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<CellGemImageState>& 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<CellGemImageState>& gem_image_state, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max)
{
const auto& shared_data = g_fxo->get<gem_camera_shared>();
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<f32>(shared_data.width);
const f32 scaling_height = y_max / static_cast<f32>(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<f32>(shared_data.width);
const f32 scaling_height = y_max / static_cast<f32>(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<u16>& digital_buttons, be_t<u16>& analog_t)
@ -1721,7 +1767,7 @@ static void ds3_input_to_pad(const u32 gem_num, be_t<u16>& 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<Pad>&
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 <typename T>
@ -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<u16>& digital_buttons, be_t<u1
}
});
analog_t = (digital_buttons & CELL_GEM_CTRL_T) ? 0xFFFF : 0;
analog_t = (digital_buttons & CELL_GEM_CTRL_T) ? 255 : 0;
return true;
}
@ -2144,7 +2185,7 @@ static bool gun_input_to_pad(u32 gem_no, be_t<u16>& digital_buttons, be_t<u16>&
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<gem_config>();
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<named_thread<gem_tracker>>();
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<gem_config>();
@ -2631,6 +2674,7 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr<CellGemImageState> gem_imag
cellGem.warning("cellGemGetImageState(gem_num=%d, image_state=&0x%x)", gem_num, gem_image_state);
auto& gem = g_fxo->get<gem_config>();
std::scoped_lock lock(gem.mtx);
if (!gem.state)
{
@ -2646,15 +2690,11 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr<CellGemImageState> gem_imag
if (g_cfg.io.move != move_handler::null)
{
auto& shared_data = g_fxo->get<gem_camera_shared>();
const auto& shared_data = g_fxo->get<gem_camera_shared>();
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<CellGemImageState> 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<u32> 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::ptr<u8[CELL_GEM_EXTERNAL_PO
{
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))

View file

@ -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<pad_info>();
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<CellPadData> 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<CellPadPeriphInfo> 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<CellPadPeriphData> 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<CellPadData> 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<CellPadActParam> 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<CellPadInfo> 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<CellPadInfo2> 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<CellPadCapabilityInfo>
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<CellPadData> 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<u32>(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<u32>(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<u32>(handle) >= pads.size())

View file

@ -420,10 +420,8 @@ error_code sys_event_queue_tryreceive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sy
while (count < size && !queue->events.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();

View file

@ -271,7 +271,7 @@ error_code _sys_process_get_paramsfo(vm::ptr<char> buffer)
{
sys_process.warning("_sys_process_get_paramsfo(buffer=0x%x)", buffer);
if (!Emu.GetTitleID().length())
if (Emu.GetTitleID().empty())
{
return CELL_ENOENT;
}

View file

@ -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);

View file

@ -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))

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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);

View file

@ -32,6 +32,20 @@ std::string cfg_pad::get_buttons(std::vector<std::string> vec)
return fmt::merge(vec, ",");
}
u8 cfg_pad::get_large_motor_speed(const std::array<VibrateMotor, 2>& motor_speed) const
{
const u8 idx = switch_vibration_motors ? 1 : 0;
const f32 multiplier = multiplier_vibration_motor_large / 100.0f;
return static_cast<u8>(std::clamp(motor_speed[idx].m_value * multiplier, 0.0f, 255.0f));
}
u8 cfg_pad::get_small_motor_speed(const std::array<VibrateMotor, 2>& motor_speed) const
{
const u8 idx = switch_vibration_motors ? 0 : 1;
const f32 multiplier = multiplier_vibration_motor_small / 100.0f;
return static_cast<u8>(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);

View file

@ -28,6 +28,9 @@ struct cfg_pad final : cfg::node
static std::vector<std::string> get_buttons(const std::string& str);
static std::string get_buttons(std::vector<std::string> vec);
u8 get_large_motor_speed(const std::array<VibrateMotor, 2>& motor_speed) const;
u8 get_small_motor_speed(const std::array<VibrateMotor, 2>& 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_movement_mode> mouse_move_mode{ this, "Mouse Movement Mode", mouse_movement_mode::relative };

View file

@ -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<u8> input_buf(0x60);
constexpr le_t<u16> 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<u8> input_buf(0x180);
le_t<u64> digital_input[2]{};

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -40,6 +40,8 @@
LOG_CHANNEL(gui_log, "GUI");
atomic_t<bool> gui_pad_thread::m_reset = false;
gui_pad_thread::gui_pad_thread()
{
m_thread = std::make_unique<std::thread>(&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()))
{

View file

@ -23,6 +23,11 @@ public:
static std::shared_ptr<PadHandlerBase> GetHandler(pad_handler type);
static void InitPadConfig(cfg_pad& cfg, pad_handler type, std::shared_ptr<PadHandlerBase>& handler);
static void reset()
{
m_reset = true;
}
protected:
bool init();
void run();
@ -60,6 +65,7 @@ protected:
std::unique_ptr<std::thread> m_thread;
atomic_t<bool> m_terminate = false;
atomic_t<bool> m_allow_global_input = false;
static atomic_t<bool> m_reset;
std::array<bool, static_cast<u32>(pad_button::pad_button_max_enum)> m_last_button_state{};

View file

@ -37,7 +37,7 @@ extern std::string g_input_config_override;
namespace pad
{
atomic_t<pad_thread*> g_current = nullptr;
atomic_t<pad_thread*> g_pad_thread = nullptr;
shared_mutex g_pad_mutex;
std::string g_title_id;
atomic_t<bool> 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()

View file

@ -70,7 +70,7 @@ private:
namespace pad
{
extern atomic_t<pad_thread*> g_current;
extern atomic_t<pad_thread*> g_pad_thread;
extern shared_mutex g_pad_mutex;
extern std::string g_title_id;
extern atomic_t<bool> g_enabled;
@ -78,14 +78,14 @@ namespace pad
extern atomic_t<bool> g_started;
extern atomic_t<bool> 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);
}
}

View file

@ -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;

View file

@ -15,7 +15,7 @@ namespace gem
{
extern bool convert_image_format(CellCameraFormat input_format, CellGemVideoConvertFormatEnum output_format,
const std::vector<u8>& 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 <bool DiagnosticsEnabled>
@ -238,7 +238,7 @@ void ps_move_tracker<DiagnosticsEnabled>::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});
}

View file

@ -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;

View file

@ -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;

View file

@ -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<u8>(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<u8>(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());

View file

@ -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);

View file

@ -937,7 +937,7 @@
<property name="title">
<string>Enable Vibration</string>
</property>
<layout class="QHBoxLayout" name="gb_vibration_layout">
<layout class="QHBoxLayout" name="gb_vibration_layout" stretch="1,1,1">
<property name="leftMargin">
<number>5</number>
</property>
@ -951,22 +951,22 @@
<number>5</number>
</property>
<item>
<widget class="QCheckBox" name="chb_vibration_large">
<property name="text">
<string>Large</string>
<widget class="QSpinBox" name="sb_vibration_large">
<property name="suffix">
<string>%</string>
</property>
<property name="checked">
<bool>true</bool>
<property name="prefix">
<string>Large </string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chb_vibration_small">
<property name="text">
<string>Small</string>
<widget class="QSpinBox" name="sb_vibration_small">
<property name="suffix">
<string>%</string>
</property>
<property name="checked">
<bool>true</bool>
<property name="prefix">
<string>Small </string>
</property>
</widget>
</item>

View file

@ -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<int>(error));
set_state(camera_handler_state::closed);
}
void qt_camera_handler::open_camera()