diff options
Diffstat (limited to 'src')
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. |