summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/fiber.cpp4
-rw-r--r--src/common/fiber.h2
-rw-r--r--src/core/hle/kernel/kernel.cpp5
-rw-r--r--src/core/hle/kernel/process.cpp3
-rw-r--r--src/core/hle/service/am/am.cpp2
-rw-r--r--src/core/hle/service/hid/hid.cpp2
-rw-r--r--src/core/hle/service/mii/mii.cpp1
-rw-r--r--src/core/hle/service/set/set.cpp1
-rw-r--r--src/core/hle/service/set/set_sys.cpp2
-rw-r--r--src/input_common/gcadapter/gc_adapter.cpp462
-rw-r--r--src/input_common/gcadapter/gc_adapter.h146
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp128
-rw-r--r--src/tests/common/fibers.cpp71
-rw-r--r--src/video_core/CMakeLists.txt3
-rw-r--r--src/video_core/cdma_pusher.cpp2
-rw-r--r--src/video_core/command_classes/codecs/vp9.cpp2
-rw-r--r--src/video_core/command_classes/sync_manager.cpp14
-rw-r--r--src/video_core/command_classes/sync_manager.h4
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/wrapper.cpp2
-rw-r--r--src/web_service/CMakeLists.txt2
-rw-r--r--src/web_service/web_backend.cpp26
-rw-r--r--src/yuzu/configuration/config.cpp12
-rw-r--r--src/yuzu_cmd/config.cpp6
-rw-r--r--src/yuzu_cmd/default_ini.h4
25 files changed, 520 insertions, 389 deletions
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp
index 1c1d09ccb..e186ed880 100644
--- a/src/common/fiber.cpp
+++ b/src/common/fiber.cpp
@@ -91,7 +91,7 @@ void Fiber::Rewind() {
SwitchToFiber(impl->rewind_handle);
}
-void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) {
+void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) {
ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
ASSERT_MSG(to != nullptr, "Next fiber is null!");
to->guard.lock();
@@ -199,7 +199,7 @@ void Fiber::Rewind() {
boost::context::detail::jump_fcontext(impl->rewind_context, this);
}
-void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) {
+void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) {
ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
ASSERT_MSG(to != nullptr, "Next fiber is null!");
to->guard.lock();
diff --git a/src/common/fiber.h b/src/common/fiber.h
index 89dde5e36..cefd61df9 100644
--- a/src/common/fiber.h
+++ b/src/common/fiber.h
@@ -46,7 +46,7 @@ public:
/// Yields control from Fiber 'from' to Fiber 'to'
/// Fiber 'from' must be the currently running fiber.
- static void YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to);
+ static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to);
[[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter);
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index b2b5b8adf..bb3e312a7 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -86,8 +86,6 @@ struct KernelCore::Impl {
}
cores.clear();
- registered_core_threads.reset();
-
process_list.clear();
current_process = nullptr;
@@ -199,9 +197,7 @@ struct KernelCore::Impl {
const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
ASSERT(it == end);
- ASSERT(!registered_core_threads[core_id]);
InsertHostThread(static_cast<u32>(core_id));
- registered_core_threads.set(core_id);
}
void RegisterHostThread() {
@@ -332,7 +328,6 @@ struct KernelCore::Impl {
// 0-3 IDs represent core threads, >3 represent others
std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
- std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads;
// Number of host threads is a relatively high number to avoid overflowing
static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64;
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index ff9d9248b..b17529dee 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -4,6 +4,7 @@
#include <algorithm>
#include <bitset>
+#include <ctime>
#include <memory>
#include <random>
#include "common/alignment.h"
@@ -123,7 +124,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
: kernel.CreateNewUserProcessID();
process->capabilities.InitializeForMetadatalessProcess();
- std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(0));
+ std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
std::uniform_int_distribution<u64> distribution;
std::generate(process->random_entropy.begin(), process->random_entropy.end(),
[&] { return distribution(rng); });
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d7a81f64a..2ce742e35 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1201,6 +1201,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
{151, nullptr, "TryPopFromNotificationStorageChannel"},
{160, nullptr, "GetHealthWarningDisappearedSystemEvent"},
{170, nullptr, "SetHdcpAuthenticationActivated"},
+ {180, nullptr, "GetLaunchRequiredVersion"},
+ {181, nullptr, "UpgradeLaunchRequiredVersion"},
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
{1000, nullptr, "CreateMovieMaker"},
{1001, nullptr, "PrepareForJit"},
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 8918946a1..50f709b25 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -260,7 +260,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
{404, nullptr, "HasLeftRightBattery"},
{405, nullptr, "GetNpadInterfaceType"},
{406, nullptr, "GetNpadLeftRightInterfaceType"},
- {407, nullptr, "GetNpadOfHighestBatteryLevelForJoyLeft"},
+ {407, nullptr, "GetNpadOfHighestBatteryLevel"},
{408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"},
{500, nullptr, "GetPalmaConnectionHandle"},
{501, nullptr, "InitializePalma"},
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index b81bf6277..d7080b715 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -47,6 +47,7 @@ public:
{23, nullptr, "Convert"},
{24, nullptr, "ConvertCoreDataToCharInfo"},
{25, nullptr, "ConvertCharInfoToCoreData"},
+ {26, nullptr, "Append"},
};
// clang-format on
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index e64777668..ffbf90b00 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -202,6 +202,7 @@ SET::SET() : ServiceFramework("set") {
{8, &SET::GetQuestFlag, "GetQuestFlag"},
{9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"},
{10, nullptr, "GetFirmwareVersionForDebug"},
+ {11, nullptr, "GetDeviceNickName"},
};
// clang-format on
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index 8bd4c7e79..080b5743e 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -300,6 +300,8 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
{198, nullptr, "SetButtonConfigRegisteredSettingsEmbedded"},
{199, nullptr, "GetButtonConfigRegisteredSettings"},
{200, nullptr, "SetButtonConfigRegisteredSettings"},
+ {201, nullptr, "GetFieldTestingFlag"},
+ {202, nullptr, "SetFieldTestingFlag"},
};
// clang-format on
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp
index c95feb0d7..b912188b6 100644
--- a/src/input_common/gcadapter/gc_adapter.cpp
+++ b/src/input_common/gcadapter/gc_adapter.cpp
@@ -21,26 +21,6 @@
namespace GCAdapter {
-// Used to loop through and assign button in poller
-constexpr std::array<PadButton, 12> PadButtonArray{
- PadButton::PAD_BUTTON_LEFT, PadButton::PAD_BUTTON_RIGHT, PadButton::PAD_BUTTON_DOWN,
- PadButton::PAD_BUTTON_UP, PadButton::PAD_TRIGGER_Z, PadButton::PAD_TRIGGER_R,
- PadButton::PAD_TRIGGER_L, PadButton::PAD_BUTTON_A, PadButton::PAD_BUTTON_B,
- PadButton::PAD_BUTTON_X, PadButton::PAD_BUTTON_Y, PadButton::PAD_BUTTON_START,
-};
-
-static void PadToState(const GCPadStatus& pad, GCState& out_state) {
- for (const auto& button : PadButtonArray) {
- const auto button_key = static_cast<u16>(button);
- const auto button_value = (pad.button & button_key) != 0;
- out_state.buttons.insert_or_assign(static_cast<s32>(button_key), button_value);
- }
-
- for (std::size_t i = 0; i < pad.axis_values.size(); ++i) {
- out_state.axes.insert_or_assign(static_cast<u32>(i), pad.axis_values[i]);
- }
-}
-
Adapter::Adapter() {
if (usb_adapter_handle != nullptr) {
return;
@@ -49,168 +29,263 @@ Adapter::Adapter() {
const int init_res = libusb_init(&libusb_ctx);
if (init_res == LIBUSB_SUCCESS) {
- Setup();
+ adapter_scan_thread = std::thread(&Adapter::AdapterScanThread, this);
} else {
LOG_ERROR(Input, "libusb could not be initialized. failed with error = {}", init_res);
}
}
-GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload) {
- GCPadStatus pad = {};
- const std::size_t offset = 1 + (9 * port);
+Adapter::~Adapter() {
+ Reset();
+}
+
+void Adapter::AdapterInputThread() {
+ LOG_DEBUG(Input, "GC Adapter input thread started");
+ s32 payload_size{};
+ AdapterPayload adapter_payload{};
+
+ if (adapter_scan_thread.joinable()) {
+ adapter_scan_thread.join();
+ }
+
+ while (adapter_input_thread_running) {
+ libusb_interrupt_transfer(usb_adapter_handle, input_endpoint, adapter_payload.data(),
+ static_cast<s32>(adapter_payload.size()), &payload_size, 16);
+ if (IsPayloadCorrect(adapter_payload, payload_size)) {
+ UpdateControllers(adapter_payload);
+ UpdateVibrations();
+ }
+ std::this_thread::yield();
+ }
- adapter_controllers_status[port] = static_cast<ControllerTypes>(adapter_payload[offset] >> 4);
+ if (restart_scan_thread) {
+ adapter_scan_thread = std::thread(&Adapter::AdapterScanThread, this);
+ restart_scan_thread = false;
+ }
+}
+
+bool Adapter::IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size) {
+ if (payload_size != static_cast<s32>(adapter_payload.size()) ||
+ adapter_payload[0] != LIBUSB_DT_HID) {
+ LOG_DEBUG(Input, "Error reading payload (size: {}, type: {:02x})", payload_size,
+ adapter_payload[0]);
+ if (input_error_counter++ > 20) {
+ LOG_ERROR(Input, "GC adapter timeout, Is the adapter connected?");
+ adapter_input_thread_running = false;
+ restart_scan_thread = true;
+ }
+ return false;
+ }
+
+ input_error_counter = 0;
+ return true;
+}
+
+void Adapter::UpdateControllers(const AdapterPayload& adapter_payload) {
+ for (std::size_t port = 0; port < pads.size(); ++port) {
+ const std::size_t offset = 1 + (9 * port);
+ const auto type = static_cast<ControllerTypes>(adapter_payload[offset] >> 4);
+ UpdatePadType(port, type);
+ if (DeviceConnected(port)) {
+ const u8 b1 = adapter_payload[offset + 1];
+ const u8 b2 = adapter_payload[offset + 2];
+ UpdateStateButtons(port, b1, b2);
+ UpdateStateAxes(port, adapter_payload);
+ if (configuring) {
+ UpdateYuzuSettings(port);
+ }
+ }
+ }
+}
+
+void Adapter::UpdatePadType(std::size_t port, ControllerTypes pad_type) {
+ if (pads[port].type == pad_type) {
+ return;
+ }
+ // Device changed reset device and set new type
+ ResetDevice(port);
+ pads[port].type = pad_type;
+}
+
+void Adapter::UpdateStateButtons(std::size_t port, u8 b1, u8 b2) {
+ if (port >= pads.size()) {
+ return;
+ }
static constexpr std::array<PadButton, 8> b1_buttons{
- PadButton::PAD_BUTTON_A, PadButton::PAD_BUTTON_B, PadButton::PAD_BUTTON_X,
- PadButton::PAD_BUTTON_Y, PadButton::PAD_BUTTON_LEFT, PadButton::PAD_BUTTON_RIGHT,
- PadButton::PAD_BUTTON_DOWN, PadButton::PAD_BUTTON_UP,
+ PadButton::ButtonA, PadButton::ButtonB, PadButton::ButtonX, PadButton::ButtonY,
+ PadButton::ButtonLeft, PadButton::ButtonRight, PadButton::ButtonDown, PadButton::ButtonUp,
};
static constexpr std::array<PadButton, 4> b2_buttons{
- PadButton::PAD_BUTTON_START,
- PadButton::PAD_TRIGGER_Z,
- PadButton::PAD_TRIGGER_R,
- PadButton::PAD_TRIGGER_L,
+ PadButton::ButtonStart,
+ PadButton::TriggerZ,
+ PadButton::TriggerR,
+ PadButton::TriggerL,
};
+ pads[port].buttons = 0;
+ for (std::size_t i = 0; i < b1_buttons.size(); ++i) {
+ if ((b1 & (1U << i)) != 0) {
+ pads[port].buttons =
+ static_cast<u16>(pads[port].buttons | static_cast<u16>(b1_buttons[i]));
+ pads[port].last_button = b1_buttons[i];
+ }
+ }
+ for (std::size_t j = 0; j < b2_buttons.size(); ++j) {
+ if ((b2 & (1U << j)) != 0) {
+ pads[port].buttons =
+ static_cast<u16>(pads[port].buttons | static_cast<u16>(b2_buttons[j]));
+ pads[port].last_button = b2_buttons[j];
+ }
+ }
+}
+
+void Adapter::UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload) {
+ if (port >= pads.size()) {
+ return;
+ }
+
+ const std::size_t offset = 1 + (9 * port);
static constexpr std::array<PadAxes, 6> axes{
PadAxes::StickX, PadAxes::StickY, PadAxes::SubstickX,
PadAxes::SubstickY, PadAxes::TriggerLeft, PadAxes::TriggerRight,
};
- if (adapter_controllers_status[port] == ControllerTypes::None && !get_origin[port]) {
- // Controller may have been disconnected, recalibrate if reconnected.
- get_origin[port] = true;
+ for (const PadAxes axis : axes) {
+ const auto index = static_cast<std::size_t>(axis);
+ const u8 axis_value = adapter_payload[offset + 3 + index];
+ if (pads[port].axis_origin[index] == 255) {
+ pads[port].axis_origin[index] = axis_value;
+ }
+ pads[port].axis_values[index] =
+ static_cast<s16>(axis_value - pads[port].axis_origin[index]);
}
+}
- if (adapter_controllers_status[port] != ControllerTypes::None) {
- const u8 b1 = adapter_payload[offset + 1];
- const u8 b2 = adapter_payload[offset + 2];
+void Adapter::UpdateYuzuSettings(std::size_t port) {
+ if (port >= pads.size()) {
+ return;
+ }
- for (std::size_t i = 0; i < b1_buttons.size(); ++i) {
- if ((b1 & (1U << i)) != 0) {
- pad.button = static_cast<u16>(pad.button | static_cast<u16>(b1_buttons[i]));
- }
- }
+ constexpr u8 axis_threshold = 50;
+ GCPadStatus pad_status = {.port = port};
- for (std::size_t j = 0; j < b2_buttons.size(); ++j) {
- if ((b2 & (1U << j)) != 0) {
- pad.button = static_cast<u16>(pad.button | static_cast<u16>(b2_buttons[j]));
- }
- }
- for (PadAxes axis : axes) {
- const auto index = static_cast<std::size_t>(axis);
- pad.axis_values[index] = adapter_payload[offset + 3 + index];
- }
+ if (pads[port].buttons != 0) {
+ pad_status.button = pads[port].last_button;
+ pad_queue.Push(pad_status);
+ }
+
+ // Accounting for a threshold here to ensure an intentional press
+ for (std::size_t i = 0; i < pads[port].axis_values.size(); ++i) {
+ const s16 value = pads[port].axis_values[i];
- if (get_origin[port]) {
- origin_status[port].axis_values = pad.axis_values;
- get_origin[port] = false;
+ if (value > axis_threshold || value < -axis_threshold) {
+ pad_status.axis = static_cast<PadAxes>(i);
+ pad_status.axis_value = value;
+ pad_status.axis_threshold = axis_threshold;
+ pad_queue.Push(pad_status);
}
}
- return pad;
}
-void Adapter::Read() {
- LOG_DEBUG(Input, "GC Adapter Read() thread started");
+void Adapter::UpdateVibrations() {
+ // Use 8 states to keep the switching between on/off fast enough for
+ // a human to not notice the difference between switching from on/off
+ // More states = more rumble strengths = slower update time
+ constexpr u8 vibration_states = 8;
- int payload_size;
- std::array<u8, 37> adapter_payload;
- std::array<GCPadStatus, 4> pads;
-
- while (adapter_thread_running) {
- libusb_interrupt_transfer(usb_adapter_handle, input_endpoint, adapter_payload.data(),
- sizeof(adapter_payload), &payload_size, 16);
-
- if (payload_size != sizeof(adapter_payload) || adapter_payload[0] != LIBUSB_DT_HID) {
- LOG_ERROR(Input,
- "Error reading payload (size: {}, type: {:02x}) Is the adapter connected?",
- payload_size, adapter_payload[0]);
- adapter_thread_running = false; // error reading from adapter, stop reading.
- break;
- }
- for (std::size_t port = 0; port < pads.size(); ++port) {
- pads[port] = GetPadStatus(port, adapter_payload);
- if (DeviceConnected(port) && configuring) {
- if (pads[port].button != 0) {
- pad_queue[port].Push(pads[port]);
- }
+ vibration_counter = (vibration_counter + 1) % vibration_states;
- // Accounting for a threshold here to ensure an intentional press
- for (size_t i = 0; i < pads[port].axis_values.size(); ++i) {
- const u8 value = pads[port].axis_values[i];
- const u8 origin = origin_status[port].axis_values[i];
-
- if (value > origin + pads[port].THRESHOLD ||
- value < origin - pads[port].THRESHOLD) {
- pads[port].axis = static_cast<PadAxes>(i);
- pads[port].axis_value = pads[port].axis_values[i];
- pad_queue[port].Push(pads[port]);
- }
- }
- }
- PadToState(pads[port], state[port]);
- }
- std::this_thread::yield();
+ for (GCController& pad : pads) {
+ const bool vibrate = pad.rumble_amplitude > vibration_counter;
+ vibration_changed |= vibrate != pad.enable_vibration;
+ pad.enable_vibration = vibrate;
}
+ SendVibrations();
}
-void Adapter::Setup() {
- // Initialize all controllers as unplugged
- adapter_controllers_status.fill(ControllerTypes::None);
- // Initialize all ports to store axis origin values
- get_origin.fill(true);
-
- // pointer to list of connected usb devices
- libusb_device** devices{};
-
- // populate the list of devices, get the count
- const ssize_t device_count = libusb_get_device_list(libusb_ctx, &devices);
- if (device_count < 0) {
- LOG_ERROR(Input, "libusb_get_device_list failed with error: {}", device_count);
+void Adapter::SendVibrations() {
+ if (!rumble_enabled || !vibration_changed) {
return;
}
-
- if (devices != nullptr) {
- for (std::size_t index = 0; index < static_cast<std::size_t>(device_count); ++index) {
- if (CheckDeviceAccess(devices[index])) {
- // GC Adapter found and accessible, registering it
- GetGCEndpoint(devices[index]);
- break;
- }
+ s32 size{};
+ constexpr u8 rumble_command = 0x11;
+ const u8 p1 = pads[0].enable_vibration;
+ const u8 p2 = pads[1].enable_vibration;
+ const u8 p3 = pads[2].enable_vibration;
+ const u8 p4 = pads[3].enable_vibration;
+ std::array<u8, 5> payload = {rumble_command, p1, p2, p3, p4};
+ const int err = libusb_interrupt_transfer(usb_adapter_handle, output_endpoint, payload.data(),
+ static_cast<s32>(payload.size()), &size, 16);
+ if (err) {
+ LOG_DEBUG(Input, "Adapter libusb write failed: {}", libusb_error_name(err));
+ if (output_error_counter++ > 5) {
+ LOG_ERROR(Input, "GC adapter output timeout, Rumble disabled");
+ rumble_enabled = false;
}
- libusb_free_device_list(devices, 1);
+ return;
}
+ output_error_counter = 0;
+ vibration_changed = false;
}
-bool Adapter::CheckDeviceAccess(libusb_device* device) {
- libusb_device_descriptor desc;
- const int get_descriptor_error = libusb_get_device_descriptor(device, &desc);
- if (get_descriptor_error) {
- // could not acquire the descriptor, no point in trying to use it.
- LOG_ERROR(Input, "libusb_get_device_descriptor failed with error: {}",
- get_descriptor_error);
- return false;
+bool Adapter::RumblePlay(std::size_t port, f32 amplitude) {
+ amplitude = std::clamp(amplitude, 0.0f, 1.0f);
+ const auto raw_amp = static_cast<u8>(amplitude * 0x8);
+ pads[port].rumble_amplitude = raw_amp;
+
+ return rumble_enabled;
+}
+
+void Adapter::AdapterScanThread() {
+ adapter_scan_thread_running = true;
+ adapter_input_thread_running = false;
+ if (adapter_input_thread.joinable()) {
+ adapter_input_thread.join();
+ }
+ ClearLibusbHandle();
+ ResetDevices();
+ while (adapter_scan_thread_running && !adapter_input_thread_running) {
+ Setup();
+ std::this_thread::sleep_for(std::chrono::seconds(1));
}
+}
- if (desc.idVendor != 0x057e || desc.idProduct != 0x0337) {
- // This isn't the device we are looking for.
- return false;
+void Adapter::Setup() {
+ usb_adapter_handle = libusb_open_device_with_vid_pid(libusb_ctx, 0x057e, 0x0337);
+
+ if (usb_adapter_handle == NULL) {
+ return;
+ }
+ if (!CheckDeviceAccess()) {
+ ClearLibusbHandle();
+ return;
}
- const int open_error = libusb_open(device, &usb_adapter_handle);
- if (open_error == LIBUSB_ERROR_ACCESS) {
- LOG_ERROR(Input, "Yuzu can not gain access to this device: ID {:04X}:{:04X}.",
- desc.idVendor, desc.idProduct);
- return false;
+ libusb_device* device = libusb_get_device(usb_adapter_handle);
+
+ LOG_INFO(Input, "GC adapter is now connected");
+ // GC Adapter found and accessible, registering it
+ if (GetGCEndpoint(device)) {
+ adapter_scan_thread_running = false;
+ adapter_input_thread_running = true;
+ rumble_enabled = true;
+ input_error_counter = 0;
+ output_error_counter = 0;
+ adapter_input_thread = std::thread(&Adapter::AdapterInputThread, this);
}
- if (open_error) {
- LOG_ERROR(Input, "libusb_open failed to open device with error = {}", open_error);
- return false;
+}
+
+bool Adapter::CheckDeviceAccess() {
+ // This fixes payload problems from offbrand GCAdapters
+ const s32 control_transfer_error =
+ libusb_control_transfer(usb_adapter_handle, 0x21, 11, 0x0001, 0, nullptr, 0, 1000);
+ if (control_transfer_error < 0) {
+ LOG_ERROR(Input, "libusb_control_transfer failed with error= {}", control_transfer_error);
}
- int kernel_driver_error = libusb_kernel_driver_active(usb_adapter_handle, 0);
+ s32 kernel_driver_error = libusb_kernel_driver_active(usb_adapter_handle, 0);
if (kernel_driver_error == 1) {
kernel_driver_error = libusb_detach_kernel_driver(usb_adapter_handle, 0);
if (kernel_driver_error != 0 && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) {
@@ -236,13 +311,13 @@ bool Adapter::CheckDeviceAccess(libusb_device* device) {
return true;
}
-void Adapter::GetGCEndpoint(libusb_device* device) {
+bool Adapter::GetGCEndpoint(libusb_device* device) {
libusb_config_descriptor* config = nullptr;
const int config_descriptor_return = libusb_get_config_descriptor(device, 0, &config);
if (config_descriptor_return != LIBUSB_SUCCESS) {
LOG_ERROR(Input, "libusb_get_config_descriptor failed with error = {}",
config_descriptor_return);
- return;
+ return false;
}
for (u8 ic = 0; ic < config->bNumInterfaces; ic++) {
@@ -264,31 +339,51 @@ void Adapter::GetGCEndpoint(libusb_device* device) {
unsigned char clear_payload = 0x13;
libusb_interrupt_transfer(usb_adapter_handle, output_endpoint, &clear_payload,
sizeof(clear_payload), nullptr, 16);
-
- adapter_thread_running = true;
- adapter_input_thread = std::thread(&Adapter::Read, this);
+ return true;
}
-Adapter::~Adapter() {
- Reset();
-}
+void Adapter::JoinThreads() {
+ restart_scan_thread = false;
+ adapter_input_thread_running = false;
+ adapter_scan_thread_running = false;
-void Adapter::Reset() {
- if (adapter_thread_running) {
- adapter_thread_running = false;
+ if (adapter_scan_thread.joinable()) {
+ adapter_scan_thread.join();
}
+
if (adapter_input_thread.joinable()) {
adapter_input_thread.join();
}
+}
- adapter_controllers_status.fill(ControllerTypes::None);
- get_origin.fill(true);
-
+void Adapter::ClearLibusbHandle() {
if (usb_adapter_handle) {
libusb_release_interface(usb_adapter_handle, 1);
libusb_close(usb_adapter_handle);
usb_adapter_handle = nullptr;
}
+}
+
+void Adapter::ResetDevices() {
+ for (std::size_t i = 0; i < pads.size(); ++i) {
+ ResetDevice(i);
+ }
+}
+
+void Adapter::ResetDevice(std::size_t port) {
+ pads[port].type = ControllerTypes::None;
+ pads[port].enable_vibration = false;
+ pads[port].rumble_amplitude = 0;
+ pads[port].buttons = 0;
+ pads[port].last_button = PadButton::Undefined;
+ pads[port].axis_values.fill(0);
+ pads[port].axis_origin.fill(255);
+}
+
+void Adapter::Reset() {
+ JoinThreads();
+ ClearLibusbHandle();
+ ResetDevices();
if (libusb_ctx) {
libusb_exit(libusb_ctx);
@@ -297,11 +392,11 @@ void Adapter::Reset() {
std::vector<Common::ParamPackage> Adapter::GetInputDevices() const {
std::vector<Common::ParamPackage> devices;
- for (std::size_t port = 0; port < state.size(); ++port) {
+ for (std::size_t port = 0; port < pads.size(); ++port) {
if (!DeviceConnected(port)) {
continue;
}
- std::string name = fmt::format("Gamecube Controller {}", port);
+ std::string name = fmt::format("Gamecube Controller {}", port + 1);
devices.emplace_back(Common::ParamPackage{
{"class", "gcpad"},
{"display", std::move(name)},
@@ -318,18 +413,18 @@ InputCommon::ButtonMapping Adapter::GetButtonMappingForDevice(
// This list also excludes any button that can't be really mapped
static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 12>
switch_to_gcadapter_button = {
- std::pair{Settings::NativeButton::A, PadButton::PAD_BUTTON_A},
- {Settings::NativeButton::B, PadButton::PAD_BUTTON_B},
- {Settings::NativeButton::X, PadButton::PAD_BUTTON_X},
- {Settings::NativeButton::Y, PadButton::PAD_BUTTON_Y},
- {Settings::NativeButton::Plus, PadButton::PAD_BUTTON_START},
- {Settings::NativeButton::DLeft, PadButton::PAD_BUTTON_LEFT},
- {Settings::NativeButton::DUp, PadButton::PAD_BUTTON_UP},
- {Settings::NativeButton::DRight, PadButton::PAD_BUTTON_RIGHT},
- {Settings::NativeButton::DDown, PadButton::PAD_BUTTON_DOWN},
- {Settings::NativeButton::SL, PadButton::PAD_TRIGGER_L},
- {Settings::NativeButton::SR, PadButton::PAD_TRIGGER_R},
- {Settings::NativeButton::R, PadButton::PAD_TRIGGER_Z},
+ std::pair{Settings::NativeButton::A, PadButton::ButtonA},
+ {Settings::NativeButton::B, PadButton::ButtonB},
+ {Settings::NativeButton::X, PadButton::ButtonX},
+ {Settings::NativeButton::Y, PadButton::ButtonY},
+ {Settings::NativeButton::Plus, PadButton::ButtonStart},
+ {Settings::NativeButton::DLeft, PadButton::ButtonLeft},
+ {Settings::NativeButton::DUp, PadButton::ButtonUp},
+ {Settings::NativeButton::DRight, PadButton::ButtonRight},
+ {Settings::NativeButton::DDown, PadButton::ButtonDown},
+ {Settings::NativeButton::SL, PadButton::TriggerL},
+ {Settings::NativeButton::SR, PadButton::TriggerR},
+ {Settings::NativeButton::R, PadButton::TriggerZ},
};
if (!params.Has("port")) {
return {};
@@ -352,8 +447,10 @@ InputCommon::ButtonMapping Adapter::GetButtonMappingForDevice(
for (const auto& [switch_button, gcadapter_axis] : switch_to_gcadapter_axis) {
Common::ParamPackage button_params({{"engine", "gcpad"}});
button_params.Set("port", params.Get("port", 0));
- button_params.Set("button", static_cast<int>(PadButton::PAD_STICK));
- button_params.Set("axis", static_cast<int>(gcadapter_axis));
+ button_params.Set("button", static_cast<s32>(PadButton::Stick));
+ button_params.Set("axis", static_cast<s32>(gcadapter_axis));
+ button_params.Set("threshold", 0.5f);
+ button_params.Set("direction", "+");
mapping.insert_or_assign(switch_button, std::move(button_params));
}
return mapping;
@@ -382,46 +479,33 @@ InputCommon::AnalogMapping Adapter::GetAnalogMappingForDevice(
}
bool Adapter::DeviceConnected(std::size_t port) const {
- return adapter_controllers_status[port] != ControllerTypes::None;
-}
-
-void Adapter::ResetDeviceType(std::size_t port) {
- adapter_controllers_status[port] = ControllerTypes::None;
+ return pads[port].type != ControllerTypes::None;
}
void Adapter::BeginConfiguration() {
- get_origin.fill(true);
- for (auto& pq : pad_queue) {
- pq.Clear();
- }
+ pad_queue.Clear();
configuring = true;
}
void Adapter::EndConfiguration() {
- for (auto& pq : pad_queue) {
- pq.Clear();
- }
+ pad_queue.Clear();
configuring = false;
}
-std::array<Common::SPSCQueue<GCPadStatus>, 4>& Adapter::GetPadQueue() {
+Common::SPSCQueue<GCPadStatus>& Adapter::GetPadQueue() {
return pad_queue;
}
-const std::array<Common::SPSCQueue<GCPadStatus>, 4>& Adapter::GetPadQueue() const {
+const Common::SPSCQueue<GCPadStatus>& Adapter::GetPadQueue() const {
return pad_queue;
}
-std::array<GCState, 4>& Adapter::GetPadState() {
- return state;
-}
-
-const std::array<GCState, 4>& Adapter::GetPadState() const {
- return state;
+GCController& Adapter::GetPadState(std::size_t port) {
+ return pads.at(port);
}
-int Adapter::GetOriginValue(u32 port, u32 axis) const {
- return origin_status[port].axis_values[axis];
+const GCController& Adapter::GetPadState(std::size_t port) const {
+ return pads.at(port);
}
} // namespace GCAdapter
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h
index 4f5f3de8e..d28dcfad3 100644
--- a/src/input_common/gcadapter/gc_adapter.h
+++ b/src/input_common/gcadapter/gc_adapter.h
@@ -19,24 +19,23 @@ struct libusb_device_handle;
namespace GCAdapter {
enum class PadButton {
- PAD_BUTTON_LEFT = 0x0001,
- PAD_BUTTON_RIGHT = 0x0002,
- PAD_BUTTON_DOWN = 0x0004,
- PAD_BUTTON_UP = 0x0008,
- PAD_TRIGGER_Z = 0x0010,
- PAD_TRIGGER_R = 0x0020,
- PAD_TRIGGER_L = 0x0040,
- PAD_BUTTON_A = 0x0100,
- PAD_BUTTON_B = 0x0200,
- PAD_BUTTON_X = 0x0400,
- PAD_BUTTON_Y = 0x0800,
- PAD_BUTTON_START = 0x1000,
+ Undefined = 0x0000,
+ ButtonLeft = 0x0001,
+ ButtonRight = 0x0002,
+ ButtonDown = 0x0004,
+ ButtonUp = 0x0008,
+ TriggerZ = 0x0010,
+ TriggerR = 0x0020,
+ TriggerL = 0x0040,
+ ButtonA = 0x0100,
+ ButtonB = 0x0200,
+ ButtonX = 0x0400,
+ ButtonY = 0x0800,
+ ButtonStart = 0x1000,
// Below is for compatibility with "AxisButton" type
- PAD_STICK = 0x2000,
+ Stick = 0x2000,
};
-extern const std::array<PadButton, 12> PadButtonArray;
-
enum class PadAxes : u8 {
StickX,
StickY,
@@ -47,87 +46,122 @@ enum class PadAxes : u8 {
Undefined,
};
+enum class ControllerTypes {
+ None,
+ Wired,
+ Wireless,
+};
+
struct GCPadStatus {
- u16 button{}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits
+ std::size_t port{};
- std::array<u8, 6> axis_values{}; // Triggers and sticks, following indices defined in PadAxes
- static constexpr u8 THRESHOLD = 50; // Threshold for axis press for polling
+ PadButton button{PadButton::Undefined}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits
- u8 port{};
PadAxes axis{PadAxes::Undefined};
- u8 axis_value{255};
+ s16 axis_value{};
+ u8 axis_threshold{50};
};
-struct GCState {
- std::unordered_map<int, bool> buttons;
- std::unordered_map<u32, u16> axes;
+struct GCController {
+ ControllerTypes type{};
+ bool enable_vibration{};
+ u8 rumble_amplitude{};
+ u16 buttons{};
+ PadButton last_button{};
+ std::array<s16, 6> axis_values{};
+ std::array<u8, 6> axis_origin{};
};
-enum class ControllerTypes { None, Wired, Wireless };
-
class Adapter {
public:
- /// Initialize the GC Adapter capture and read sequence
Adapter();
-
- /// Close the adapter read thread and release the adapter
~Adapter();
+
+ /// Request a vibration for a controlelr
+ bool RumblePlay(std::size_t port, f32 amplitude);
+
/// Used for polling
void BeginConfiguration();
void EndConfiguration();
+ Common::SPSCQueue<GCPadStatus>& GetPadQueue();
+ const Common::SPSCQueue<GCPadStatus>& GetPadQueue() const;
+
+ GCController& GetPadState(std::size_t port);
+ const GCController& GetPadState(std::size_t port) const;
+
+ /// Returns true if there is a device connected to port
+ bool DeviceConnected(std::size_t port) const;
+
+ /// Used for automapping features
std::vector<Common::ParamPackage> GetInputDevices() const;
InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const;
InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const;
- /// Returns true if there is a device connected to port
- bool DeviceConnected(std::size_t port) const;
+private:
+ using AdapterPayload = std::array<u8, 37>;
- std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue();
- const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const;
+ void UpdatePadType(std::size_t port, ControllerTypes pad_type);
+ void UpdateControllers(const AdapterPayload& adapter_payload);
+ void UpdateYuzuSettings(std::size_t port);
+ void UpdateStateButtons(std::size_t port, u8 b1, u8 b2);
+ void UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload);
+ void UpdateVibrations();
- std::array<GCState, 4>& GetPadState();
- const std::array<GCState, 4>& GetPadState() const;
+ void AdapterInputThread();
- int GetOriginValue(u32 port, u32 axis) const;
+ void AdapterScanThread();
-private:
- GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload);
+ bool IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size);
+
+ // Updates vibration state of all controllers
+ void SendVibrations();
+
+ /// For use in initialization, querying devices to find the adapter
+ void Setup();
- void Read();
+ /// Resets status of all GC controller devices to a disconected state
+ void ResetDevices();
- /// Resets status of device connected to port
- void ResetDeviceType(std::size_t port);
+ /// Resets status of device connected to a disconected state
+ void ResetDevice(std::size_t port);
/// Returns true if we successfully gain access to GC Adapter
- bool CheckDeviceAccess(libusb_device* device);
+ bool CheckDeviceAccess();
- /// Captures GC Adapter endpoint address,
- void GetGCEndpoint(libusb_device* device);
+ /// Captures GC Adapter endpoint address
+ /// Returns true if the endpoind was set correctly
+ bool GetGCEndpoint(libusb_device* device);
/// For shutting down, clear all data, join all threads, release usb
void Reset();
- /// For use in initialization, querying devices to find the adapter
- void Setup();
+ // Join all threads
+ void JoinThreads();
+
+ // Release usb handles
+ void ClearLibusbHandle();
libusb_device_handle* usb_adapter_handle = nullptr;
+ std::array<GCController, 4> pads;
+ Common::SPSCQueue<GCPadStatus> pad_queue;
std::thread adapter_input_thread;
- bool adapter_thread_running;
+ std::thread adapter_scan_thread;
+ bool adapter_input_thread_running;
+ bool adapter_scan_thread_running;
+ bool restart_scan_thread;
libusb_context* libusb_ctx;
- u8 input_endpoint = 0;
- u8 output_endpoint = 0;
-
- bool configuring = false;
+ u8 input_endpoint{0};
+ u8 output_endpoint{0};
+ u8 input_error_counter{0};
+ u8 output_error_counter{0};
+ int vibration_counter{0};
- std::array<GCState, 4> state;
- std::array<bool, 4> get_origin;
- std::array<GCPadStatus, 4> origin_status;
- std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue;
- std::array<ControllerTypes, 4> adapter_controllers_status{};
+ bool configuring{false};
+ bool rumble_enabled{true};
+ bool vibration_changed{true};
};
-
} // namespace GCAdapter
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index 893556916..6bd6f57fc 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -15,22 +15,30 @@ namespace InputCommon {
class GCButton final : public Input::ButtonDevice {
public:
- explicit GCButton(u32 port_, int button_, const GCAdapter::Adapter* adapter)
+ explicit GCButton(u32 port_, s32 button_, GCAdapter::Adapter* adapter)
: port(port_), button(button_), gcadapter(adapter) {}
~GCButton() override;
bool GetStatus() const override {
if (gcadapter->DeviceConnected(port)) {
- return gcadapter->GetPadState()[port].buttons.at(button);
+ return (gcadapter->GetPadState(port).buttons & button) != 0;
}
return false;
}
+ bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const override {
+ const float amplitude = amp_high + amp_low > 2.0f ? 1.0f : (amp_high + amp_low) * 0.5f;
+ const auto new_amp =
+ static_cast<f32>(pow(amplitude, 0.5f) * (3.0f - 2.0f * pow(amplitude, 0.15f)));
+
+ return gcadapter->RumblePlay(port, new_amp);
+ }
+
private:
const u32 port;
- const int button;
- const GCAdapter::Adapter* gcadapter;
+ const s32 button;
+ GCAdapter::Adapter* gcadapter;
};
class GCAxisButton final : public Input::ButtonDevice {
@@ -38,13 +46,12 @@ public:
explicit GCAxisButton(u32 port_, u32 axis_, float threshold_, bool trigger_if_greater_,
const GCAdapter::Adapter* adapter)
: port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_),
- gcadapter(adapter),
- origin_value(static_cast<float>(adapter->GetOriginValue(port_, axis_))) {}
+ gcadapter(adapter) {}
bool GetStatus() const override {
if (gcadapter->DeviceConnected(port)) {
- const float current_axis_value = gcadapter->GetPadState()[port].axes.at(axis);
- const float axis_value = (current_axis_value - origin_value) / 128.0f;
+ const float current_axis_value = gcadapter->GetPadState(port).axis_values.at(axis);
+ const float axis_value = current_axis_value / 128.0f;
if (trigger_if_greater) {
// TODO: Might be worthwile to set a slider for the trigger threshold. It is
// currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick
@@ -61,7 +68,6 @@ private:
float threshold;
bool trigger_if_greater;
const GCAdapter::Adapter* gcadapter;
- const float origin_value;
};
GCButtonFactory::GCButtonFactory(std::shared_ptr<GCAdapter::Adapter> adapter_)
@@ -73,7 +79,7 @@ std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::Param
const auto button_id = params.Get("button", 0);
const auto port = static_cast<u32>(params.Get("port", 0));
- constexpr int PAD_STICK_ID = static_cast<u16>(GCAdapter::PadButton::PAD_STICK);
+ constexpr s32 PAD_STICK_ID = static_cast<s32>(GCAdapter::PadButton::Stick);
// button is not an axis/stick button
if (button_id != PAD_STICK_ID) {
@@ -106,32 +112,25 @@ Common::ParamPackage GCButtonFactory::GetNextInput() const {
Common::ParamPackage params;
GCAdapter::GCPadStatus pad;
auto& queue = adapter->GetPadQueue();
- for (std::size_t port = 0; port < queue.size(); ++port) {
- while (queue[port].Pop(pad)) {
- // This while loop will break on the earliest detected button
- params.Set("engine", "gcpad");
- params.Set("port", static_cast<int>(port));
- for (const auto& button : GCAdapter::PadButtonArray) {
- const u16 button_value = static_cast<u16>(button);
- if (pad.button & button_value) {
- params.Set("button", button_value);
- break;
- }
- }
+ while (queue.Pop(pad)) {
+ // This while loop will break on the earliest detected button
+ params.Set("engine", "gcpad");
+ params.Set("port", static_cast<s32>(pad.port));
+ if (pad.button != GCAdapter::PadButton::Undefined) {
+ params.Set("button", static_cast<u16>(pad.button));
+ }
- // For Axis button implementation
- if (pad.axis != GCAdapter::PadAxes::Undefined) {
- params.Set("axis", static_cast<u8>(pad.axis));
- params.Set("button", static_cast<u16>(GCAdapter::PadButton::PAD_STICK));
- if (pad.axis_value > 128) {
- params.Set("direction", "+");
- params.Set("threshold", "0.25");
- } else {
- params.Set("direction", "-");
- params.Set("threshold", "-0.25");
- }
- break;
+ // For Axis button implementation
+ if (pad.axis != GCAdapter::PadAxes::Undefined) {
+ params.Set("axis", static_cast<u8>(pad.axis));
+ params.Set("button", static_cast<u16>(GCAdapter::PadButton::Stick));
+ params.Set("threshold", "0.25");
+ if (pad.axis_value > 0) {
+ params.Set("direction", "+");
+ } else {
+ params.Set("direction", "-");
}
+ break;
}
}
return params;
@@ -152,17 +151,14 @@ public:
explicit GCAnalog(u32 port_, u32 axis_x_, u32 axis_y_, float deadzone_,
const GCAdapter::Adapter* adapter, float range_)
: port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter),
- origin_value_x(static_cast<float>(adapter->GetOriginValue(port_, axis_x_))),
- origin_value_y(static_cast<float>(adapter->GetOriginValue(port_, axis_y_))),
range(range_) {}
float GetAxis(u32 axis) const {
if (gcadapter->DeviceConnected(port)) {
std::lock_guard lock{mutex};
- const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y;
const auto axis_value =
- static_cast<float>(gcadapter->GetPadState()[port].axes.at(axis));
- return (axis_value - origin_value) / (100.0f * range);
+ static_cast<float>(gcadapter->GetPadState(port).axis_values.at(axis));
+ return (axis_value) / (100.0f * range);
}
return 0.0f;
}
@@ -215,8 +211,6 @@ private:
const u32 axis_y;
const float deadzone;
const GCAdapter::Adapter* gcadapter;
- const float origin_value_x;
- const float origin_value_y;
const float range;
mutable std::mutex mutex;
};
@@ -254,26 +248,44 @@ void GCAnalogFactory::EndConfiguration() {
Common::ParamPackage GCAnalogFactory::GetNextInput() {
GCAdapter::GCPadStatus pad;
+ Common::ParamPackage params;
auto& queue = adapter->GetPadQueue();
- for (std::size_t port = 0; port < queue.size(); ++port) {
- while (queue[port].Pop(pad)) {
- if (pad.axis == GCAdapter::PadAxes::Undefined ||
- std::abs((static_cast<float>(pad.axis_value) - 128.0f) / 128.0f) < 0.1f) {
- continue;
- }
- // An analog device needs two axes, so we need to store the axis for later and wait for
- // a second input event. The axes also must be from the same joystick.
- const u8 axis = static_cast<u8>(pad.axis);
- if (analog_x_axis == -1) {
- analog_x_axis = axis;
- controller_number = static_cast<int>(port);
- } else if (analog_y_axis == -1 && analog_x_axis != axis &&
- controller_number == static_cast<int>(port)) {
- analog_y_axis = axis;
- }
+ while (queue.Pop(pad)) {
+ if (pad.button != GCAdapter::PadButton::Undefined) {
+ params.Set("engine", "gcpad");
+ params.Set("port", static_cast<s32>(pad.port));
+ params.Set("button", static_cast<u16>(pad.button));
+ return params;
+ }
+ if (pad.axis == GCAdapter::PadAxes::Undefined ||
+ std::abs(static_cast<float>(pad.axis_value) / 128.0f) < 0.1f) {
+ continue;
+ }
+ // An analog device needs two axes, so we need to store the axis for later and wait for
+ // a second input event. The axes also must be from the same joystick.
+ const u8 axis = static_cast<u8>(pad.axis);
+ if (axis == 0 || axis == 1) {
+ analog_x_axis = 0;
+ analog_y_axis = 1;
+ controller_number = static_cast<s32>(pad.port);
+ break;
+ }
+ if (axis == 2 || axis == 3) {
+ analog_x_axis = 2;
+ analog_y_axis = 3;
+ controller_number = static_cast<s32>(pad.port);
+ break;
+ }
+
+ if (analog_x_axis == -1) {
+ analog_x_axis = axis;
+ controller_number = static_cast<s32>(pad.port);
+ } else if (analog_y_axis == -1 && analog_x_axis != axis &&
+ controller_number == static_cast<s32>(pad.port)) {
+ analog_y_axis = axis;
+ break;
}
}
- Common::ParamPackage params;
if (analog_x_axis != -1 && analog_y_axis != -1) {
params.Set("engine", "gcpad");
params.Set("port", controller_number);
diff --git a/src/tests/common/fibers.cpp b/src/tests/common/fibers.cpp
index 4fd92428f..4757dd2b4 100644
--- a/src/tests/common/fibers.cpp
+++ b/src/tests/common/fibers.cpp
@@ -6,18 +6,40 @@
#include <cstdlib>
#include <functional>
#include <memory>
+#include <mutex>
+#include <stdexcept>
#include <thread>
#include <unordered_map>
#include <vector>
#include <catch2/catch.hpp>
-#include <math.h>
+
#include "common/common_types.h"
#include "common/fiber.h"
-#include "common/spin_lock.h"
namespace Common {
+class ThreadIds {
+public:
+ void Register(u32 id) {
+ const auto thread_id = std::this_thread::get_id();
+ std::scoped_lock lock{mutex};
+ if (ids.contains(thread_id)) {
+ throw std::logic_error{"Registering the same thread twice"};
+ }
+ ids.emplace(thread_id, id);
+ }
+
+ [[nodiscard]] u32 Get() const {
+ std::scoped_lock lock{mutex};
+ return ids.at(std::this_thread::get_id());
+ }
+
+private:
+ mutable std::mutex mutex;
+ std::unordered_map<std::thread::id, u32> ids;
+};
+
class TestControl1 {
public:
TestControl1() = default;
@@ -26,7 +48,7 @@ public:
void ExecuteThread(u32 id);
- std::unordered_map<std::thread::id, u32> ids;
+ ThreadIds thread_ids;
std::vector<std::shared_ptr<Common::Fiber>> thread_fibers;
std::vector<std::shared_ptr<Common::Fiber>> work_fibers;
std::vector<u32> items;
@@ -39,8 +61,7 @@ static void WorkControl1(void* control) {
}
void TestControl1::DoWork() {
- std::thread::id this_id = std::this_thread::get_id();
- u32 id = ids[this_id];
+ const u32 id = thread_ids.Get();
u32 value = items[id];
for (u32 i = 0; i < id; i++) {
value++;
@@ -50,8 +71,7 @@ void TestControl1::DoWork() {
}
void TestControl1::ExecuteThread(u32 id) {
- std::thread::id this_id = std::this_thread::get_id();
- ids[this_id] = id;
+ thread_ids.Register(id);
auto thread_fiber = Fiber::ThreadToFiber();
thread_fibers[id] = thread_fiber;
work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this);
@@ -98,8 +118,7 @@ public:
value1 += i;
}
Fiber::YieldTo(fiber1, fiber3);
- std::thread::id this_id = std::this_thread::get_id();
- u32 id = ids[this_id];
+ const u32 id = thread_ids.Get();
assert1 = id == 1;
value2 += 5000;
Fiber::YieldTo(fiber1, thread_fibers[id]);
@@ -115,8 +134,7 @@ public:
}
void DoWork3() {
- std::thread::id this_id = std::this_thread::get_id();
- u32 id = ids[this_id];
+ const u32 id = thread_ids.Get();
assert2 = id == 0;
value1 += 1000;
Fiber::YieldTo(fiber3, thread_fibers[id]);
@@ -125,14 +143,12 @@ public:
void ExecuteThread(u32 id);
void CallFiber1() {
- std::thread::id this_id = std::this_thread::get_id();
- u32 id = ids[this_id];
+ const u32 id = thread_ids.Get();
Fiber::YieldTo(thread_fibers[id], fiber1);
}
void CallFiber2() {
- std::thread::id this_id = std::this_thread::get_id();
- u32 id = ids[this_id];
+ const u32 id = thread_ids.Get();
Fiber::YieldTo(thread_fibers[id], fiber2);
}
@@ -145,7 +161,7 @@ public:
u32 value2{};
std::atomic<bool> trap{true};
std::atomic<bool> trap2{true};
- std::unordered_map<std::thread::id, u32> ids;
+ ThreadIds thread_ids;
std::vector<std::shared_ptr<Common::Fiber>> thread_fibers;
std::shared_ptr<Common::Fiber> fiber1;
std::shared_ptr<Common::Fiber> fiber2;
@@ -168,15 +184,13 @@ static void WorkControl2_3(void* control) {
}
void TestControl2::ExecuteThread(u32 id) {
- std::thread::id this_id = std::this_thread::get_id();
- ids[this_id] = id;
+ thread_ids.Register(id);
auto thread_fiber = Fiber::ThreadToFiber();
thread_fibers[id] = thread_fiber;
}
void TestControl2::Exit() {
- std::thread::id this_id = std::this_thread::get_id();
- u32 id = ids[this_id];
+ const u32 id = thread_ids.Get();
thread_fibers[id]->Exit();
}
@@ -228,24 +242,21 @@ public:
void DoWork1() {
value1 += 1;
Fiber::YieldTo(fiber1, fiber2);
- std::thread::id this_id = std::this_thread::get_id();
- u32 id = ids[this_id];
+ const u32 id = thread_ids.Get();
value3 += 1;
Fiber::YieldTo(fiber1, thread_fibers[id]);
}
void DoWork2() {
value2 += 1;
- std::thread::id this_id = std::this_thread::get_id();
- u32 id = ids[this_id];
+ const u32 id = thread_ids.Get();
Fiber::YieldTo(fiber2, thread_fibers[id]);
}
void ExecuteThread(u32 id);
void CallFiber1() {
- std::thread::id this_id = std::this_thread::get_id();
- u32 id = ids[this_id];
+ const u32 id = thread_ids.Get();
Fiber::YieldTo(thread_fibers[id], fiber1);
}
@@ -254,7 +265,7 @@ public:
u32 value1{};
u32 value2{};
u32 value3{};
- std::unordered_map<std::thread::id, u32> ids;
+ ThreadIds thread_ids;
std::vector<std::shared_ptr<Common::Fiber>> thread_fibers;
std::shared_ptr<Common::Fiber> fiber1;
std::shared_ptr<Common::Fiber> fiber2;
@@ -271,15 +282,13 @@ static void WorkControl3_2(void* control) {
}
void TestControl3::ExecuteThread(u32 id) {
- std::thread::id this_id = std::this_thread::get_id();
- ids[this_id] = id;
+ thread_ids.Register(id);
auto thread_fiber = Fiber::ThreadToFiber();
thread_fibers[id] = thread_fiber;
}
void TestControl3::Exit() {
- std::thread::id this_id = std::this_thread::get_id();
- u32 id = ids[this_id];
+ const u32 id = thread_ids.Get();
thread_fibers[id]->Exit();
}
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index fdfc885fc..abcee2a1c 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -302,7 +302,10 @@ else()
target_compile_options(video_core PRIVATE
-Werror=conversion
-Wno-error=sign-conversion
+ -Werror=pessimizing-move
+ -Werror=redundant-move
-Werror=switch
+ -Werror=type-limits
-Werror=unused-variable
$<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess>
diff --git a/src/video_core/cdma_pusher.cpp b/src/video_core/cdma_pusher.cpp
index d774db107..b60f86260 100644
--- a/src/video_core/cdma_pusher.cpp
+++ b/src/video_core/cdma_pusher.cpp
@@ -144,7 +144,7 @@ void CDmaPusher::ExecuteCommand(u32 offset, u32 data) {
}
case ThiMethod::SetMethod1:
LOG_DEBUG(Service_NVDRV, "VIC method 0x{:X}, Args=({})",
- static_cast<u32>(vic_thi_state.method_0));
+ static_cast<u32>(vic_thi_state.method_0), data);
vic_processor->ProcessMethod(static_cast<Tegra::Vic::Method>(vic_thi_state.method_0),
{data});
break;
diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp
index bcbea9c05..b3e98aa9f 100644
--- a/src/video_core/command_classes/codecs/vp9.cpp
+++ b/src/video_core/command_classes/codecs/vp9.cpp
@@ -917,7 +917,7 @@ void VpxRangeEncoder::Write(bool bit, s32 probability) {
if (((low_value << (offset - 1)) >> 31) != 0) {
const s32 current_pos = static_cast<s32>(base_stream.GetPosition());
base_stream.Seek(-1, Common::SeekOrigin::FromCurrentPos);
- while (base_stream.GetPosition() >= 0 && PeekByte() == 0xff) {
+ while (PeekByte() == 0xff) {
base_stream.WriteByte(0);
base_stream.Seek(-2, Common::SeekOrigin::FromCurrentPos);
diff --git a/src/video_core/command_classes/sync_manager.cpp b/src/video_core/command_classes/sync_manager.cpp
index a0ab44855..19dc9e0ab 100644
--- a/src/video_core/command_classes/sync_manager.cpp
+++ b/src/video_core/command_classes/sync_manager.cpp
@@ -27,22 +27,22 @@ SyncptIncrManager::SyncptIncrManager(GPU& gpu_) : gpu(gpu_) {}
SyncptIncrManager::~SyncptIncrManager() = default;
void SyncptIncrManager::Increment(u32 id) {
- increments.push_back(SyncptIncr{0, id, true});
+ increments.emplace_back(0, 0, id, true);
IncrementAllDone();
}
u32 SyncptIncrManager::IncrementWhenDone(u32 class_id, u32 id) {
const u32 handle = current_id++;
- increments.push_back(SyncptIncr{handle, class_id, id});
+ increments.emplace_back(handle, class_id, id);
return handle;
}
void SyncptIncrManager::SignalDone(u32 handle) {
- auto done_incr = std::find_if(increments.begin(), increments.end(),
- [handle](SyncptIncr incr) { return incr.id == handle; });
- if (done_incr != increments.end()) {
- const SyncptIncr incr = *done_incr;
- *done_incr = SyncptIncr{incr.id, incr.class_id, incr.syncpt_id, true};
+ const auto done_incr =
+ std::find_if(increments.begin(), increments.end(),
+ [handle](const SyncptIncr& incr) { return incr.id == handle; });
+ if (done_incr != increments.cend()) {
+ done_incr->complete = true;
}
IncrementAllDone();
}
diff --git a/src/video_core/command_classes/sync_manager.h b/src/video_core/command_classes/sync_manager.h
index 353b67573..2c321ec58 100644
--- a/src/video_core/command_classes/sync_manager.h
+++ b/src/video_core/command_classes/sync_manager.h
@@ -32,8 +32,8 @@ struct SyncptIncr {
u32 syncpt_id;
bool complete;
- SyncptIncr(u32 id, u32 syncpt_id_, u32 class_id_, bool done = false)
- : id(id), class_id(class_id_), syncpt_id(syncpt_id_), complete(done) {}
+ SyncptIncr(u32 id_, u32 class_id_, u32 syncpt_id_, bool done = false)
+ : id(id_), class_id(class_id_), syncpt_id(syncpt_id_), complete(done) {}
};
class SyncptIncrManager {
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index 166ee34e1..70dd0c3c6 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -317,8 +317,7 @@ std::optional<std::vector<ShaderDiskCachePrecompiled>> ShaderDiskCacheOpenGL::Lo
return std::nullopt;
}
}
-
- return std::move(entries);
+ return entries;
}
void ShaderDiskCacheOpenGL::InvalidateTransferable() {
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
index c034558a3..4e83303d8 100644
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ b/src/video_core/renderer_vulkan/wrapper.cpp
@@ -844,7 +844,7 @@ std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProp
VK_SUCCESS) {
return std::nullopt;
}
- return std::move(properties);
+ return properties;
}
std::optional<std::vector<VkLayerProperties>> EnumerateInstanceLayerProperties(
diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt
index 7e484b906..ae85a72ea 100644
--- a/src/web_service/CMakeLists.txt
+++ b/src/web_service/CMakeLists.txt
@@ -9,4 +9,4 @@ add_library(web_service STATIC
)
create_target_directory_groups(web_service)
-target_link_libraries(web_service PRIVATE common nlohmann_json::nlohmann_json httplib lurlparser)
+target_link_libraries(web_service PRIVATE common nlohmann_json::nlohmann_json httplib)
diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp
index 534960d09..67183e64c 100644
--- a/src/web_service/web_backend.cpp
+++ b/src/web_service/web_backend.cpp
@@ -7,7 +7,6 @@
#include <mutex>
#include <string>
-#include <LUrlParser.h>
#include <fmt/format.h>
#include <httplib.h>
@@ -19,9 +18,6 @@ namespace WebService {
constexpr std::array<const char, 1> API_VERSION{'1'};
-constexpr int HTTP_PORT = 80;
-constexpr int HTTPS_PORT = 443;
-
constexpr std::size_t TIMEOUT_SECONDS = 30;
struct Client::Impl {
@@ -67,22 +63,14 @@ struct Client::Impl {
const std::string& jwt = "", const std::string& username = "",
const std::string& token = "") {
if (cli == nullptr) {
- const auto parsedUrl = LUrlParser::clParseURL::ParseURL(host);
- int port{};
- if (parsedUrl.m_Scheme == "http") {
- if (!parsedUrl.GetPort(&port)) {
- port = HTTP_PORT;
- }
- } else if (parsedUrl.m_Scheme == "https") {
- if (!parsedUrl.GetPort(&port)) {
- port = HTTPS_PORT;
- }
- } else {
- LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme);
- return WebResult{WebResult::Code::InvalidURL, "Bad URL scheme", ""};
- }
- cli = std::make_unique<httplib::Client>(parsedUrl.m_Host.c_str(), port);
+ cli = std::make_unique<httplib::Client>(host.c_str());
+ }
+
+ if (!cli->is_valid()) {
+ LOG_ERROR(WebService, "Client is invalid, skipping request!");
+ return {};
}
+
cli->set_connection_timeout(TIMEOUT_SECONDS);
cli->set_read_timeout(TIMEOUT_SECONDS);
cli->set_write_timeout(TIMEOUT_SECONDS);
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index abbc83929..1ce62e4a6 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -515,7 +515,7 @@ void Config::ReadMotionTouchValues() {
void Config::ReadCoreValues() {
qt_config->beginGroup(QStringLiteral("Core"));
- ReadSettingGlobal(Settings::values.use_multi_core, QStringLiteral("use_multi_core"), false);
+ ReadSettingGlobal(Settings::values.use_multi_core, QStringLiteral("use_multi_core"), true);
qt_config->endGroup();
}
@@ -716,12 +716,12 @@ void Config::ReadRendererValues() {
QStringLiteral("use_disk_shader_cache"), true);
ReadSettingGlobal(Settings::values.gpu_accuracy, QStringLiteral("gpu_accuracy"), 0);
ReadSettingGlobal(Settings::values.use_asynchronous_gpu_emulation,
- QStringLiteral("use_asynchronous_gpu_emulation"), false);
+ QStringLiteral("use_asynchronous_gpu_emulation"), true);
ReadSettingGlobal(Settings::values.use_nvdec_emulation, QStringLiteral("use_nvdec_emulation"),
true);
ReadSettingGlobal(Settings::values.use_vsync, QStringLiteral("use_vsync"), true);
ReadSettingGlobal(Settings::values.use_assembly_shaders, QStringLiteral("use_assembly_shaders"),
- false);
+ true);
ReadSettingGlobal(Settings::values.use_asynchronous_shaders,
QStringLiteral("use_asynchronous_shaders"), false);
ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"),
@@ -1110,7 +1110,7 @@ void Config::SaveControlValues() {
void Config::SaveCoreValues() {
qt_config->beginGroup(QStringLiteral("Core"));
- WriteSettingGlobal(QStringLiteral("use_multi_core"), Settings::values.use_multi_core, false);
+ WriteSettingGlobal(QStringLiteral("use_multi_core"), Settings::values.use_multi_core, true);
qt_config->endGroup();
}
@@ -1266,12 +1266,12 @@ void Config::SaveRendererValues() {
static_cast<int>(Settings::values.gpu_accuracy.GetValue(global)),
Settings::values.gpu_accuracy.UsingGlobal(), 0);
WriteSettingGlobal(QStringLiteral("use_asynchronous_gpu_emulation"),
- Settings::values.use_asynchronous_gpu_emulation, false);
+ Settings::values.use_asynchronous_gpu_emulation, true);
WriteSettingGlobal(QStringLiteral("use_nvdec_emulation"), Settings::values.use_nvdec_emulation,
true);
WriteSettingGlobal(QStringLiteral("use_vsync"), Settings::values.use_vsync, true);
WriteSettingGlobal(QStringLiteral("use_assembly_shaders"),
- Settings::values.use_assembly_shaders, false);
+ Settings::values.use_assembly_shaders, true);
WriteSettingGlobal(QStringLiteral("use_asynchronous_shaders"),
Settings::values.use_asynchronous_shaders, false);
WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time,
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 23448e747..334038ef9 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -371,7 +371,7 @@ void Config::ReadValues() {
// Core
Settings::values.use_multi_core.SetValue(
- sdl2_config->GetBoolean("Core", "use_multi_core", false));
+ sdl2_config->GetBoolean("Core", "use_multi_core", true));
// Renderer
const int renderer_backend = sdl2_config->GetInteger(
@@ -395,11 +395,11 @@ void Config::ReadValues() {
const int gpu_accuracy_level = sdl2_config->GetInteger("Renderer", "gpu_accuracy", 0);
Settings::values.gpu_accuracy.SetValue(static_cast<Settings::GPUAccuracy>(gpu_accuracy_level));
Settings::values.use_asynchronous_gpu_emulation.SetValue(
- sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", false));
+ sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", true));
Settings::values.use_vsync.SetValue(
static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync", 1)));
Settings::values.use_assembly_shaders.SetValue(
- sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", false));
+ sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", true));
Settings::values.use_asynchronous_shaders.SetValue(
sdl2_config->GetBoolean("Renderer", "use_asynchronous_shaders", false));
Settings::values.use_asynchronous_shaders.SetValue(
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index aa9e40380..796e27df4 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -94,7 +94,7 @@ udp_pad_index=
[Core]
# Whether to use multi-core for CPU emulation
-# 0 (default): Disabled, 1: Enabled
+# 0: Disabled, 1 (default): Enabled
use_multi_core=
[Cpu]
@@ -163,7 +163,7 @@ max_anisotropy =
use_vsync =
# Whether to use OpenGL assembly shaders or not. NV_gpu_program5 is required.
-# 0 (default): Off, 1: On
+# 0: Off, 1 (default): On
use_assembly_shaders =
# Whether to allow asynchronous shader building.