1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

Input: multithreaded handlers

Implements naive multithreading for input handlers.
This commit is contained in:
Megamouse 2022-01-28 00:09:11 +01:00
parent ec3e8de780
commit d6597038ee
9 changed files with 136 additions and 8 deletions

View File

@ -253,6 +253,8 @@ struct cfg_root : cfg::node
cfg::_enum<buzz_handler> buzz{ this, "Buzz emulated controller", buzz_handler::null };
cfg::_enum<turntable_handler> turntable{this, "Turntable emulated controller", turntable_handler::null};
cfg::_enum<ghltar_handler> ghltar{this, "GHLtar emulated controller", ghltar_handler::null};
cfg::_enum<pad_handler_mode> pad_mode{this, "Pad handler mode", pad_handler_mode::single_threaded, true};
cfg::uint<0, 100'000> pad_sleep{this, "Pad handler sleep (microseconds)", 1'000, true};
} io{ this };
struct node_sys : cfg::node

View File

@ -385,6 +385,21 @@ void fmt_class_string<move_handler>::format(std::string& out, u64 arg)
});
}
template <>
void fmt_class_string<pad_handler_mode>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](auto value)
{
switch (value)
{
case pad_handler_mode::single_threaded: return "Single-threaded";
case pad_handler_mode::multi_threaded: return "Multi-threaded";
}
return unknown;
});
}
template <>
void fmt_class_string<buzz_handler>::format(std::string& out, u64 arg)
{

View File

@ -135,6 +135,12 @@ enum class microphone_handler
rocksmith,
};
enum class pad_handler_mode
{
single_threaded, // All pad handlers run on the same thread sequentially.
multi_threaded // Each pad handler has its own thread.
};
enum class video_resolution
{
_1080,

View File

@ -15,7 +15,9 @@
#include "Emu/Io/PadHandler.h"
#include "Emu/Io/pad_config.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
#include "Utilities/Thread.h"
#include "util/atomic.hpp"
LOG_CHANNEL(input_log, "Input");
@ -212,6 +214,55 @@ void pad_thread::operator()()
{
pad::g_reset = true;
atomic_t<pad_handler_mode> pad_mode{g_cfg.io.pad_mode.get()};
std::vector<std::unique_ptr<named_thread<std::function<void()>>>> threads;
const auto stop_threads = [&threads]()
{
for (auto& thread : threads)
{
if (thread)
{
auto& enumeration_thread = *thread;
enumeration_thread = thread_state::aborting;
enumeration_thread();
}
}
threads.clear();
};
const auto start_threads = [this, &threads, &pad_mode]()
{
if (pad_mode == pad_handler_mode::single_threaded)
{
return;
}
for (const auto& handler : handlers)
{
if (handler.first == pad_handler::null)
{
continue;
}
threads.push_back(std::make_unique<named_thread<std::function<void()>>>(fmt::format("%s Thread", handler.second->m_type), [&handler = handler.second, &pad_mode]()
{
while (thread_ctrl::state() != thread_state::aborting)
{
if (!pad::g_enabled || Emu.IsPaused())
{
thread_ctrl::wait_for(10'000);
continue;
}
handler->ThreadProc();
thread_ctrl::wait_for(g_cfg.io.pad_sleep);
}
}));
}
};
while (thread_ctrl::state() != thread_state::aborting)
{
if (!pad::g_enabled || Emu.IsPaused())
@ -220,17 +271,43 @@ void pad_thread::operator()()
continue;
}
if (pad::g_reset && pad::g_reset.exchange(false))
// Update variables
const bool needs_reset = pad::g_reset && pad::g_reset.exchange(false);
const bool mode_changed = pad_mode != pad_mode.exchange(g_cfg.io.pad_mode.get());
// Reset pad handlers if necessary
if (needs_reset || mode_changed)
{
Init();
stop_threads();
if (needs_reset)
{
Init();
}
else
{
input_log.success("The pad mode was changed to %s", pad_mode.load());
}
start_threads();
}
u32 connected_devices = 0;
for (auto& cur_pad_handler : handlers)
if (pad_mode == pad_handler_mode::single_threaded)
{
cur_pad_handler.second->ThreadProc();
connected_devices += cur_pad_handler.second->connected_devices;
for (auto& handler : handlers)
{
handler.second->ThreadProc();
connected_devices += handler.second->connected_devices;
}
}
else
{
for (auto& handler : handlers)
{
connected_devices += handler.second->connected_devices;
}
}
m_info.now_connect = connected_devices + num_ldd_pad;
@ -271,8 +348,10 @@ void pad_thread::operator()()
}
}
thread_ctrl::wait_for(1000);
thread_ctrl::wait_for(g_cfg.io.pad_sleep);
}
stop_threads();
}
void pad_thread::InitLddPad(u32 handle)

View File

@ -1027,6 +1027,13 @@ QString emu_settings::GetLocalizedSetting(const QString& original, emu_settings_
case camera_handler::qt: return tr("Qt", "Camera handler");
}
break;
case emu_settings_type::PadHandlerMode:
switch (static_cast<pad_handler_mode>(index))
{
case pad_handler_mode::single_threaded: return tr("Single-threaded", "Pad handler mode");
case pad_handler_mode::multi_threaded: return tr("Multi-threaded", "Pad handler mode");
}
break;
case emu_settings_type::Move:
switch (static_cast<move_handler>(index))
{

View File

@ -126,6 +126,7 @@ enum class emu_settings_type
MicrophoneDevices,
// Input / Output
PadHandlerMode,
KeyboardHandler,
MouseHandler,
Camera,
@ -287,6 +288,7 @@ inline static const QMap<emu_settings_type, cfg_location> settings_location =
{ emu_settings_type::MicrophoneDevices, { "Audio", "Microphone Devices" }},
// Input / Output
{ emu_settings_type::PadHandlerMode, { "Input/Output", "Pad handler mode"}},
{ emu_settings_type::KeyboardHandler, { "Input/Output", "Keyboard"}},
{ emu_settings_type::MouseHandler, { "Input/Output", "Mouse"}},
{ emu_settings_type::Camera, { "Input/Output", "Camera"}},

View File

@ -1063,6 +1063,9 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
SubscribeTooltip(ui->gb_camera_id, tooltips.settings.camera_id);
}
m_emu_settings->EnhanceComboBox(ui->padModeBox, emu_settings_type::PadHandlerMode);
SubscribeTooltip(ui->gb_pad_mode, tooltips.settings.pad_mode);
m_emu_settings->EnhanceComboBox(ui->moveBox, emu_settings_type::Move);
SubscribeTooltip(ui->gb_move_handler, tooltips.settings.move);

View File

@ -53,6 +53,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="coreTab">
<attribute name="title">
<string>CPU</string>
@ -1572,6 +1575,18 @@
</layout>
</widget>
</item>
<item row="3" column="0">
<widget class="QGroupBox" name="gb_pad_mode">
<property name="title">
<string>Pad Handler Mode</string>
</property>
<layout class="QVBoxLayout" name="gb_pad_mode_layout">
<item>
<widget class="QComboBox" name="padModeBox"/>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>

View File

@ -193,8 +193,7 @@ public:
// input
const QString pad_handler = tr("If you want to use the keyboard to control, select the Keyboard option.\nIf you have a DualShock 4, select DualShock 4.\nIf you have an Xbox controller, or another compatible device, use XInput.\nOlder controllers such as PS2 controllers with an adapter usually work fine with MMJoystick.\nCheck button mappings in the Windows control panel.");
const QString pad_handler_linux = tr("If you want to use the keyboard to control, select the Keyboard option.\nIf you have a DualShock 4, select DualShock 4.");
const QString pad_mode = tr("Single-threaded: All pad handlers run on the same thread sequentially.\nMulti-threaded: Each pad handler has its own thread.\nOnly use multi-threaded if you can spare the extra threads.");
const QString keyboard_handler = tr("Some games support native keyboard input.\nBasic will work in these cases.");
const QString mouse_handler = tr("Some games support native mouse input.\nBasic will work in these cases.");
const QString camera = tr("Select Qt Camera to use the default camera device of your operating system.");