diff --git a/README.md b/README.md index 21c4d2250..f21b3a730 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 1330. +This is the source code for early-access 1331. ## Legal Notice diff --git a/dist/icons/controller/controller.qrc b/dist/icons/controller/controller.qrc index 78eae461c..1c4e960c0 100755 --- a/dist/icons/controller/controller.qrc +++ b/dist/icons/controller/controller.qrc @@ -1,5 +1,26 @@ + dual_joycon.png + dual_joycon_dark.png + dual_joycon_midnight.png + handheld.png + handheld_dark.png + handheld_midnight.png + pro_controller.png + pro_controller_dark.png + pro_controller_midnight.png + single_joycon_left.png + single_joycon_left_dark.png + single_joycon_left_midnight.png + single_joycon_right.png + single_joycon_right_dark.png + single_joycon_right_midnight.png + single_joycon_left_vertical.png + single_joycon_left_vertical_dark.png + single_joycon_left_vertical_midnight.png + single_joycon_right_vertical.png + single_joycon_right_vertical_dark.png + single_joycon_right_vertical_midnight.png applet_dual_joycon.png applet_dual_joycon_dark.png applet_dual_joycon_midnight.png diff --git a/src/common/uint128.cpp b/src/common/uint128.cpp index 343693c2c..16bf7c828 100755 --- a/src/common/uint128.cpp +++ b/src/common/uint128.cpp @@ -38,4 +38,34 @@ u64 MultiplyAndDivide64(u64 a, u64 b, u64 d) { #endif +u128 Multiply64Into128(u64 a, u64 b) { + u128 result; +#ifdef _MSC_VER + result[0] = _umul128(a, b, &result[1]); +#else + unsigned __int128 tmp = a; + tmp *= b; + std::memcpy(&result, &tmp, sizeof(u128)); +#endif + return result; +} + +std::pair Divide128On32(u128 dividend, u32 divisor) { + u64 remainder = dividend[0] % divisor; + u64 accum = dividend[0] / divisor; + if (dividend[1] == 0) + return {accum, remainder}; + // We ignore dividend[1] / divisor as that overflows + const u64 first_segment = (dividend[1] % divisor) << 32; + accum += (first_segment / divisor) << 32; + const u64 second_segment = (first_segment % divisor) << 32; + accum += (second_segment / divisor); + remainder += second_segment % divisor; + if (remainder >= divisor) { + accum++; + remainder -= divisor; + } + return {accum, remainder}; +} + } // namespace Common diff --git a/src/common/uint128.h b/src/common/uint128.h index a313765be..969259ab6 100755 --- a/src/common/uint128.h +++ b/src/common/uint128.h @@ -12,4 +12,11 @@ namespace Common { // This function multiplies 2 u64 values and divides it by a u64 value. [[nodiscard]] u64 MultiplyAndDivide64(u64 a, u64 b, u64 d); +// This function multiplies 2 u64 values and produces a u128 value; +[[nodiscard]] u128 Multiply64Into128(u64 a, u64 b); + +// This function divides a u128 by a u32 value and produces two u64 values: +// the result of division and the remainder +[[nodiscard]] std::pair Divide128On32(u128 dividend, u32 divisor); + } // namespace Common diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index c0505e898..a8c143f85 100755 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/uint128.h" #include "common/wall_clock.h" #ifdef ARCHITECTURE_x86_64 @@ -40,11 +41,16 @@ public: } u64 GetClockCycles() override { - return GetTimeNS().count() * (emulated_clock_frequency / 1000) / 1000000; + std::chrono::nanoseconds time_now = GetTimeNS(); + const u128 temporary = + Common::Multiply64Into128(time_now.count(), emulated_clock_frequency); + return Common::Divide128On32(temporary, 1000000000).first; } u64 GetCPUCycles() override { - return GetTimeNS().count() * (emulated_cpu_frequency / 1000) / 1000000; + std::chrono::nanoseconds time_now = GetTimeNS(); + const u128 temporary = Common::Multiply64Into128(time_now.count(), emulated_cpu_frequency); + return Common::Divide128On32(temporary, 1000000000).first; } void Pause([[maybe_unused]] bool is_paused) override { diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 3906aaf9b..99310dc50 100755 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -19,6 +19,7 @@ add_library(core STATIC core.h core_timing.cpp core_timing.h + core_timing_util.cpp core_timing_util.h cpu_manager.cpp cpu_manager.h diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp new file mode 100755 index 000000000..8ce8e602e --- /dev/null +++ b/src/core/core_timing_util.cpp @@ -0,0 +1,84 @@ +// Copyright 2008 Dolphin Emulator Project / 2017 Citra Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "core/core_timing_util.h" + +#include +#include +#include "common/logging/log.h" +#include "common/uint128.h" +#include "core/hardware_properties.h" + +namespace Core::Timing { + +constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits::max() / Hardware::BASE_CLOCK_RATE; + +s64 msToCycles(std::chrono::milliseconds ms) { + if (static_cast(ms.count() / 1000) > MAX_VALUE_TO_MULTIPLY) { + LOG_ERROR(Core_Timing, "Integer overflow, use max value"); + return std::numeric_limits::max(); + } + if (static_cast(ms.count()) > MAX_VALUE_TO_MULTIPLY) { + LOG_DEBUG(Core_Timing, "Time very big, do rounding"); + return Hardware::BASE_CLOCK_RATE * (ms.count() / 1000); + } + return (Hardware::BASE_CLOCK_RATE * ms.count()) / 1000; +} + +s64 usToCycles(std::chrono::microseconds us) { + if (static_cast(us.count() / 1000000) > MAX_VALUE_TO_MULTIPLY) { + LOG_ERROR(Core_Timing, "Integer overflow, use max value"); + return std::numeric_limits::max(); + } + if (static_cast(us.count()) > MAX_VALUE_TO_MULTIPLY) { + LOG_DEBUG(Core_Timing, "Time very big, do rounding"); + return Hardware::BASE_CLOCK_RATE * (us.count() / 1000000); + } + return (Hardware::BASE_CLOCK_RATE * us.count()) / 1000000; +} + +s64 nsToCycles(std::chrono::nanoseconds ns) { + const u128 temporal = Common::Multiply64Into128(ns.count(), Hardware::BASE_CLOCK_RATE); + return Common::Divide128On32(temporal, static_cast(1000000000)).first; +} + +u64 msToClockCycles(std::chrono::milliseconds ns) { + const u128 temp = Common::Multiply64Into128(ns.count(), Hardware::CNTFREQ); + return Common::Divide128On32(temp, 1000).first; +} + +u64 usToClockCycles(std::chrono::microseconds ns) { + const u128 temp = Common::Multiply64Into128(ns.count(), Hardware::CNTFREQ); + return Common::Divide128On32(temp, 1000000).first; +} + +u64 nsToClockCycles(std::chrono::nanoseconds ns) { + const u128 temp = Common::Multiply64Into128(ns.count(), Hardware::CNTFREQ); + return Common::Divide128On32(temp, 1000000000).first; +} + +u64 CpuCyclesToClockCycles(u64 ticks) { + const u128 temporal = Common::Multiply64Into128(ticks, Hardware::CNTFREQ); + return Common::Divide128On32(temporal, static_cast(Hardware::BASE_CLOCK_RATE)).first; +} + +std::chrono::milliseconds CyclesToMs(s64 cycles) { + const u128 temporal = Common::Multiply64Into128(cycles, 1000); + u64 ms = Common::Divide128On32(temporal, static_cast(Hardware::BASE_CLOCK_RATE)).first; + return std::chrono::milliseconds(ms); +} + +std::chrono::nanoseconds CyclesToNs(s64 cycles) { + const u128 temporal = Common::Multiply64Into128(cycles, 1000000000); + u64 ns = Common::Divide128On32(temporal, static_cast(Hardware::BASE_CLOCK_RATE)).first; + return std::chrono::nanoseconds(ns); +} + +std::chrono::microseconds CyclesToUs(s64 cycles) { + const u128 temporal = Common::Multiply64Into128(cycles, 1000000); + u64 us = Common::Divide128On32(temporal, static_cast(Hardware::BASE_CLOCK_RATE)).first; + return std::chrono::microseconds(us); +} + +} // namespace Core::Timing diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h index 14c36a485..e4a046bf9 100755 --- a/src/core/core_timing_util.h +++ b/src/core/core_timing_util.h @@ -1,59 +1,24 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version +// Copyright 2008 Dolphin Emulator Project / 2017 Citra Emulator Project +// Licensed under GPLv2+ // Refer to the license.txt file included. #pragma once #include - #include "common/common_types.h" -#include "core/hardware_properties.h" namespace Core::Timing { -namespace detail { -constexpr u64 CNTFREQ_ADJUSTED = Hardware::CNTFREQ / 1000; -constexpr u64 BASE_CLOCK_RATE_ADJUSTED = Hardware::BASE_CLOCK_RATE / 1000; -} // namespace detail +s64 msToCycles(std::chrono::milliseconds ms); +s64 usToCycles(std::chrono::microseconds us); +s64 nsToCycles(std::chrono::nanoseconds ns); +u64 msToClockCycles(std::chrono::milliseconds ns); +u64 usToClockCycles(std::chrono::microseconds ns); +u64 nsToClockCycles(std::chrono::nanoseconds ns); +std::chrono::milliseconds CyclesToMs(s64 cycles); +std::chrono::nanoseconds CyclesToNs(s64 cycles); +std::chrono::microseconds CyclesToUs(s64 cycles); -[[nodiscard]] constexpr s64 msToCycles(std::chrono::milliseconds ms) { - return ms.count() * detail::BASE_CLOCK_RATE_ADJUSTED; -} - -[[nodiscard]] constexpr s64 usToCycles(std::chrono::microseconds us) { - return us.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000; -} - -[[nodiscard]] constexpr s64 nsToCycles(std::chrono::nanoseconds ns) { - return ns.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000000; -} - -[[nodiscard]] constexpr u64 msToClockCycles(std::chrono::milliseconds ms) { - return static_cast(ms.count()) * detail::CNTFREQ_ADJUSTED; -} - -[[nodiscard]] constexpr u64 usToClockCycles(std::chrono::microseconds us) { - return us.count() * detail::CNTFREQ_ADJUSTED / 1000; -} - -[[nodiscard]] constexpr u64 nsToClockCycles(std::chrono::nanoseconds ns) { - return ns.count() * detail::CNTFREQ_ADJUSTED / 1000000; -} - -[[nodiscard]] constexpr u64 CpuCyclesToClockCycles(u64 ticks) { - return ticks * detail::CNTFREQ_ADJUSTED / detail::BASE_CLOCK_RATE_ADJUSTED; -} - -[[nodiscard]] constexpr std::chrono::milliseconds CyclesToMs(s64 cycles) { - return std::chrono::milliseconds(cycles / detail::BASE_CLOCK_RATE_ADJUSTED); -} - -[[nodiscard]] constexpr std::chrono::nanoseconds CyclesToNs(s64 cycles) { - return std::chrono::nanoseconds(cycles * 1000000 / detail::BASE_CLOCK_RATE_ADJUSTED); -} - -[[nodiscard]] constexpr std::chrono::microseconds CyclesToUs(s64 cycles) { - return std::chrono::microseconds(cycles * 1000 / detail::BASE_CLOCK_RATE_ADJUSTED); -} +u64 CpuCyclesToClockCycles(u64 ticks); } // namespace Core::Timing diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index ee7a58b1c..8c1193894 100755 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -21,18 +21,21 @@ public: std::mutex mutex; - Input::TouchStatus status; + bool touch_pressed = false; ///< True if touchpad area is currently pressed, otherwise false + + float touch_x = 0.0f; ///< Touchpad X-position + float touch_y = 0.0f; ///< Touchpad Y-position private: class Device : public Input::TouchDevice { public: explicit Device(std::weak_ptr&& touch_state) : touch_state(touch_state) {} - Input::TouchStatus GetStatus() const override { + std::tuple GetStatus() const override { if (auto state = touch_state.lock()) { std::lock_guard guard{state->mutex}; - return state->status; + return std::make_tuple(state->touch_x, state->touch_y, state->touch_pressed); } - return {}; + return std::make_tuple(0.0f, 0.0f, false); } private: @@ -76,44 +79,36 @@ std::tuple EmuWindow::ClipToTouchScreen(unsigned new_x, unsi return std::make_tuple(new_x, new_y); } -void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id) { - if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) { +void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { + if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) return; - } - if (id >= touch_state->status.size()) { - return; - } std::lock_guard guard{touch_state->mutex}; - const float x = + touch_state->touch_x = static_cast(framebuffer_x - framebuffer_layout.screen.left) / static_cast(framebuffer_layout.screen.right - framebuffer_layout.screen.left); - const float y = + touch_state->touch_y = static_cast(framebuffer_y - framebuffer_layout.screen.top) / static_cast(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); - touch_state->status[id] = std::make_tuple(x, y, true); + touch_state->touch_pressed = true; } -void EmuWindow::TouchReleased(std::size_t id) { - if (id >= touch_state->status.size()) { - return; - } +void EmuWindow::TouchReleased() { std::lock_guard guard{touch_state->mutex}; - touch_state->status[id] = std::make_tuple(0.0f, 0.0f, false); + touch_state->touch_pressed = false; + touch_state->touch_x = 0; + touch_state->touch_y = 0; } -void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id) { - if (id >= touch_state->status.size()) { - return; - } - if (!std::get<2>(touch_state->status[id])) +void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { + if (!touch_state->touch_pressed) return; if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); - TouchPressed(framebuffer_x, framebuffer_y, id); + TouchPressed(framebuffer_x, framebuffer_y); } void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) { diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 2436c6580..276d2b906 100755 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -117,23 +117,18 @@ public: * Signal that a touch pressed event has occurred (e.g. mouse click pressed) * @param framebuffer_x Framebuffer x-coordinate that was pressed * @param framebuffer_y Framebuffer y-coordinate that was pressed - * @param id Touch event ID */ - void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id); + void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y); - /** - * Signal that a touch released event has occurred (e.g. mouse click released) - * @param id Touch event ID - */ - void TouchReleased(std::size_t id); + /// Signal that a touch released event has occurred (e.g. mouse click released) + void TouchReleased(); /** * Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window) * @param framebuffer_x Framebuffer x-coordinate * @param framebuffer_y Framebuffer y-coordinate - * @param id Touch event ID */ - void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id); + void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y); /** * Returns currently active configuration. diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index 88ebc6497..de51a754e 100755 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h @@ -21,11 +21,6 @@ enum class AnalogDirection : u8 { UP, DOWN, }; -struct AnalogProperties { - float deadzone; - float range; - float threshold; -}; /// An abstract class template for an input device (a button, an analog input, etc.). template @@ -35,12 +30,6 @@ public: virtual StatusType GetStatus() const { return {}; } - virtual StatusType GetRawStatus() const { - return GetStatus(); - } - virtual AnalogProperties GetAnalogProperties() const { - return {}; - } virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const { return {}; } @@ -174,11 +163,10 @@ using MotionStatus = std::tuple, Common::Vec3, Common using MotionDevice = InputDevice; /** - * A touch status is an object that returns an array of 16 tuple elements of two floats and a bool. - * The floats are x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is - * pressed. + * A touch status is an object that returns a tuple of two floats and a bool. The floats are + * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed. */ -using TouchStatus = std::array, 16>; +using TouchStatus = std::tuple; /** * A touch device is an input device that returns a touch status object diff --git a/src/core/frontend/input_interpreter.h b/src/core/frontend/input_interpreter.h index 36a92a6b6..73fc47ffb 100755 --- a/src/core/frontend/input_interpreter.h +++ b/src/core/frontend/input_interpreter.h @@ -100,12 +100,12 @@ public: /** * Checks whether any of the buttons in the parameter list is pressed once. * - * @tparam HIDButton The buttons to check. + * @tparam T The buttons to check. * * @returns True when at least one of the buttons is pressed once. */ template - [[nodiscard]] bool IsAnyButtonPressedOnce() { + [[nodiscard]] bool IsAnyButtonPressedOnce() const { return (IsButtonPressedOnce(T) || ...); } @@ -121,12 +121,12 @@ public: /** * Checks whether any of the buttons in the parameter list is held down. * - * @tparam HIDButton The buttons to check. + * @tparam T The buttons to check. * * @returns True when at least one of the buttons is held down. */ template - [[nodiscard]] bool IsAnyButtonHeld() { + [[nodiscard]] bool IsAnyButtonHeld() const { return (IsButtonHeld(T) || ...); } diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 5219f2dad..0df395e85 100755 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include #include #include "common/common_types.h" #include "core/core_timing.h" @@ -17,13 +16,7 @@ constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {} Controller_Touchscreen::~Controller_Touchscreen() = default; -void Controller_Touchscreen::OnInit() { - for (std::size_t id = 0; id < MAX_FINGERS; ++id) { - mouse_finger_id[id] = MAX_FINGERS; - keyboard_finger_id[id] = MAX_FINGERS; - udp_finger_id[id] = MAX_FINGERS; - } -} +void Controller_Touchscreen::OnInit() {} void Controller_Touchscreen::OnRelease() {} @@ -47,106 +40,38 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin cur_entry.sampling_number = last_entry.sampling_number + 1; cur_entry.sampling_number2 = cur_entry.sampling_number; - const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); - const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); - for (std::size_t id = 0; id < mouse_status.size(); ++id) { - mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); - udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); + bool pressed = false; + float x, y; + std::tie(x, y, pressed) = touch_device->GetStatus(); + auto& touch_entry = cur_entry.states[0]; + touch_entry.attribute.raw = 0; + if (!pressed && touch_btn_device) { + std::tie(x, y, pressed) = touch_btn_device->GetStatus(); + } + if (pressed && Settings::values.touchscreen.enabled) { + touch_entry.x = static_cast(x * Layout::ScreenUndocked::Width); + touch_entry.y = static_cast(y * Layout::ScreenUndocked::Height); + touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; + touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; + touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; + const u64 tick = core_timing.GetCPUTicks(); + touch_entry.delta_time = tick - last_touch; + last_touch = tick; + touch_entry.finger = Settings::values.touchscreen.finger; + cur_entry.entry_count = 1; + } else { + cur_entry.entry_count = 0; } - if (Settings::values.use_touch_from_button) { - const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); - for (std::size_t id = 0; id < mouse_status.size(); ++id) { - keyboard_finger_id[id] = - UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); - } - } - - std::array active_fingers; - const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), - [](const auto& finger) { return finger.pressed; }); - const auto active_fingers_count = - static_cast(std::distance(active_fingers.begin(), end_iter)); - - const u64 tick = core_timing.GetCPUTicks(); - cur_entry.entry_count = static_cast(active_fingers_count); - for (std::size_t id = 0; id < MAX_FINGERS; ++id) { - auto& touch_entry = cur_entry.states[id]; - if (id < active_fingers_count) { - touch_entry.x = static_cast(active_fingers[id].x * Layout::ScreenUndocked::Width); - touch_entry.y = static_cast(active_fingers[id].y * Layout::ScreenUndocked::Height); - touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; - touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; - touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; - touch_entry.delta_time = tick - active_fingers[id].last_touch; - fingers[active_fingers[id].id].last_touch = tick; - touch_entry.finger = active_fingers[id].id; - touch_entry.attribute.raw = active_fingers[id].attribute.raw; - } else { - // Clear touch entry - touch_entry.attribute.raw = 0; - touch_entry.x = 0; - touch_entry.y = 0; - touch_entry.diameter_x = 0; - touch_entry.diameter_y = 0; - touch_entry.rotation_angle = 0; - touch_entry.delta_time = 0; - touch_entry.finger = 0; - } - } std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory)); } void Controller_Touchscreen::OnLoadInputDevices() { - touch_mouse_device = Input::CreateDevice("engine:emu_window"); - touch_udp_device = Input::CreateDevice("engine:cemuhookudp"); - touch_btn_device = Input::CreateDevice("engine:touch_from_button"); -} - -std::optional Controller_Touchscreen::GetUnusedFingerID() const { - std::size_t first_free_id = 0; - while (first_free_id < MAX_FINGERS) { - if (!fingers[first_free_id].pressed) { - return first_free_id; - } else { - first_free_id++; - } + touch_device = Input::CreateDevice(Settings::values.touchscreen.device); + if (Settings::values.use_touch_from_button) { + touch_btn_device = Input::CreateDevice("engine:touch_from_button"); + } else { + touch_btn_device.reset(); } - return std::nullopt; } - -std::size_t Controller_Touchscreen::UpdateTouchInputEvent( - const std::tuple& touch_input, std::size_t finger_id) { - const auto& [x, y, pressed] = touch_input; - if (pressed) { - Attributes attribute{}; - if (finger_id == MAX_FINGERS) { - const auto first_free_id = GetUnusedFingerID(); - if (!first_free_id) { - // Invalid finger id do nothing - return MAX_FINGERS; - } - finger_id = first_free_id.value(); - fingers[finger_id].pressed = true; - fingers[finger_id].id = static_cast(finger_id); - attribute.start_touch.Assign(1); - } - fingers[finger_id].x = x; - fingers[finger_id].y = y; - fingers[finger_id].attribute = attribute; - return finger_id; - } - - if (finger_id != MAX_FINGERS) { - if (!fingers[finger_id].attribute.end_touch) { - fingers[finger_id].attribute.end_touch.Assign(1); - fingers[finger_id].attribute.start_touch.Assign(0); - return finger_id; - } - fingers[finger_id].pressed = false; - } - - return MAX_FINGERS; -} - } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 784124e25..4d9042adc 100755 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -30,18 +30,6 @@ public: void OnLoadInputDevices() override; private: - static constexpr std::size_t MAX_FINGERS = 16; - - // Returns an unused finger id, if there is no fingers available std::nullopt will be returned - std::optional GetUnusedFingerID() const; - - // If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no - // changes will be made. Updates the coordinates if the finger id it's already set. If the touch - // ends delays the output by one frame to set the end_touch flag before finally freeing the - // finger id - std::size_t UpdateTouchInputEvent(const std::tuple& touch_input, - std::size_t finger_id); - struct Attributes { union { u32 raw{}; @@ -67,7 +55,7 @@ private: s64_le sampling_number; s64_le sampling_number2; s32_le entry_count; - std::array states; + std::array states; }; static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size"); @@ -78,23 +66,9 @@ private: }; static_assert(sizeof(TouchScreenSharedMemory) == 0x3000, "TouchScreenSharedMemory is an invalid size"); - - struct Finger { - u64_le last_touch{}; - float x{}; - float y{}; - u32_le id{}; - bool pressed{}; - Attributes attribute; - }; - TouchScreenSharedMemory shared_memory{}; - std::unique_ptr touch_mouse_device; - std::unique_ptr touch_udp_device; + std::unique_ptr touch_device; std::unique_ptr touch_btn_device; - std::array mouse_finger_id; - std::array keyboard_finger_id; - std::array udp_finger_id; - std::array fingers; + s64_le last_touch{}; }; } // namespace Service::HID diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 0ac5fc6ae..36970f828 100755 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -37,7 +37,6 @@ NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector& input, Tegra::ChCommandHeaderList cmdlist(1); cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F}; system.GPU().PushCommandBuffer(cmdlist); - system.GPU().MemoryManager().InvalidateQueuedCaches(); } return UnmapBuffer(input, output); } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index d1b5136da..4898dc27a 100755 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -193,13 +193,7 @@ NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector& input, std::vec return NvResult::InvalidState; } if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) { - if (vic_device) { - // UnmapVicFrame defers texture_cache invalidation of the frame address until - // the stream is over - gpu.MemoryManager().UnmapVicFrame(object->dma_map_addr, *size); - } else { - gpu.MemoryManager().Unmap(object->dma_map_addr, *size); - } + gpu.MemoryManager().Unmap(object->dma_map_addr, *size); } else { // This occurs quite frequently, however does not seem to impact functionality LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 2e0aece2f..4c9d4ba41 100755 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -160,7 +160,6 @@ protected: s32_le nvmap_fd{}; u32_le submit_timeout{}; - bool vic_device{}; std::shared_ptr nvmap_dev; SyncpointManager& syncpoint_manager; std::array device_syncpoints{}; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 9118ab254..72499654c 100755 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -12,9 +12,8 @@ namespace Service::Nvidia::Devices { nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr nvmap_dev, SyncpointManager& syncpoint_manager) - : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) { - vic_device = true; -} + : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {} + nvhost_vic::~nvhost_vic() = default; NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector& input, std::vector& output) { diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 961f1c028..11609682a 100755 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -195,9 +195,8 @@ struct Memory::Impl { switch (type) { case Common::PageType::Unmapped: { LOG_ERROR(HW_Memory, - "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {}) " - "at PC 0x{:08X}", - current_vaddr, src_addr, size, system.CurrentArmInterface().GetPC()); + "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, src_addr, size); std::memset(dest_buffer, 0, copy_amount); break; } @@ -241,9 +240,8 @@ struct Memory::Impl { switch (type) { case Common::PageType::Unmapped: { LOG_ERROR(HW_Memory, - "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {}) " - "at PC 0x{:08X}", - current_vaddr, src_addr, size, system.CurrentArmInterface().GetPC()); + "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, src_addr, size); std::memset(dest_buffer, 0, copy_amount); break; } @@ -293,9 +291,8 @@ struct Memory::Impl { switch (type) { case Common::PageType::Unmapped: { LOG_ERROR(HW_Memory, - "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {}) " - "at PC 0x{:08X}", - current_vaddr, dest_addr, size, system.CurrentArmInterface().GetPC()); + "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, dest_addr, size); break; } case Common::PageType::Memory: { @@ -337,9 +334,8 @@ struct Memory::Impl { switch (type) { case Common::PageType::Unmapped: { LOG_ERROR(HW_Memory, - "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {}) " - "at PC 0x{:08X}", - current_vaddr, dest_addr, size, system.CurrentArmInterface().GetPC()); + "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, dest_addr, size); break; } case Common::PageType::Memory: { @@ -387,9 +383,8 @@ struct Memory::Impl { switch (type) { case Common::PageType::Unmapped: { LOG_ERROR(HW_Memory, - "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {}) " - "at PC 0x{:08X}", - current_vaddr, dest_addr, size, system.CurrentArmInterface().GetPC()); + "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, dest_addr, size); break; } case Common::PageType::Memory: { @@ -434,9 +429,8 @@ struct Memory::Impl { switch (type) { case Common::PageType::Unmapped: { LOG_ERROR(HW_Memory, - "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {}) " - "at PC 0x{:08X}", - current_vaddr, src_addr, size, system.CurrentArmInterface().GetPC()); + "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, src_addr, size); ZeroBlock(process, dest_addr, copy_amount); break; } @@ -607,8 +601,7 @@ struct Memory::Impl { } switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { case Common::PageType::Unmapped: - LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X} at PC 0x{:08X}", sizeof(T) * 8, vaddr, - system.CurrentArmInterface().GetPC()); + LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); return 0; case Common::PageType::Memory: ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); @@ -645,9 +638,8 @@ struct Memory::Impl { } switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { case Common::PageType::Unmapped: - LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X} at PC 0x{:08X}", - sizeof(data) * 8, static_cast(data), vaddr, - system.CurrentArmInterface().GetPC()); + LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, + static_cast(data), vaddr); return; case Common::PageType::Memory: ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index 1b6ded8d6..9670bdeb2 100755 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp @@ -185,16 +185,6 @@ public: return {0.0f, 0.0f}; } - std::tuple GetRawStatus() const override { - const float x = GetAxis(axis_x); - const float y = GetAxis(axis_y); - return {x, y}; - } - - Input::AnalogProperties GetAnalogProperties() const override { - return {deadzone, range, 0.5f}; - } - bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { const auto [x, y] = GetStatus(); const float directional_deadzone = 0.5f; diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index a87db6084..d32eb732a 100755 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp @@ -373,16 +373,6 @@ public: return {}; } - std::tuple GetRawStatus() const override { - const float x = joystick->GetAxis(axis_x, range); - const float y = joystick->GetAxis(axis_y, range); - return {x, -y}; - } - - Input::AnalogProperties GetAnalogProperties() const override { - return {deadzone, range, 0.5f}; - } - bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { const auto [x, y] = GetStatus(); const float directional_deadzone = 0.5f; diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp index ffbe4f2ed..a07124a86 100755 --- a/src/input_common/touch_from_button.cpp +++ b/src/input_common/touch_from_button.cpp @@ -25,19 +25,18 @@ public: } } - Input::TouchStatus GetStatus() const override { - Input::TouchStatus touch_status{}; - for (std::size_t id = 0; id < map.size() && id < touch_status.size(); ++id) { - const bool state = std::get<0>(map[id])->GetStatus(); + std::tuple GetStatus() const override { + for (const auto& m : map) { + const bool state = std::get<0>(m)->GetStatus(); if (state) { - const float x = static_cast(std::get<1>(map[id])) / + const float x = static_cast(std::get<1>(m)) / static_cast(Layout::ScreenUndocked::Width); - const float y = static_cast(std::get<2>(map[id])) / + const float y = static_cast(std::get<2>(m)) / static_cast(Layout::ScreenUndocked::Height); - touch_status[id] = {x, y, true}; + return {x, y, true}; } } - return touch_status; + return {}; } private: diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index e7e50d789..412d57896 100755 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp @@ -136,7 +136,6 @@ static void SocketLoop(Socket* socket) { Client::Client() { LOG_INFO(Input, "Udp Initialization started"); - finger_id.fill(MAX_TOUCH_FINGERS); ReloadSockets(); } @@ -177,7 +176,7 @@ void Client::ReloadSockets() { std::string server_token; std::size_t client = 0; while (std::getline(servers_ss, server_token, ',')) { - if (client == MAX_UDP_CLIENTS) { + if (client == max_udp_clients) { break; } std::stringstream server_ss(server_token); @@ -195,7 +194,7 @@ void Client::ReloadSockets() { for (std::size_t pad = 0; pad < 4; ++pad) { const std::size_t client_number = GetClientNumber(udp_input_address, udp_input_port, pad); - if (client_number != MAX_UDP_CLIENTS) { + if (client_number != max_udp_clients) { LOG_ERROR(Input, "Duplicated UDP servers found"); continue; } @@ -214,7 +213,7 @@ std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t return client; } } - return MAX_UDP_CLIENTS; + return max_udp_clients; } void Client::OnVersion([[maybe_unused]] Response::Version data) { @@ -260,14 +259,33 @@ void Client::OnPadData(Response::PadData data, std::size_t client) { std::lock_guard guard(clients[client].status.update_mutex); clients[client].status.motion_status = clients[client].motion.GetMotion(); - for (std::size_t id = 0; id < data.touch.size(); ++id) { - UpdateTouchInput(data.touch[id], client, id); + // TODO: add a setting for "click" touch. Click touch refers to a device that differentiates + // between a simple "tap" and a hard press that causes the touch screen to click. + const bool is_active = data.touch_1.is_active != 0; + + float x = 0; + float y = 0; + + if (is_active && clients[client].status.touch_calibration) { + const u16 min_x = clients[client].status.touch_calibration->min_x; + const u16 max_x = clients[client].status.touch_calibration->max_x; + const u16 min_y = clients[client].status.touch_calibration->min_y; + const u16 max_y = clients[client].status.touch_calibration->max_y; + + x = static_cast(std::clamp(static_cast(data.touch_1.x), min_x, max_x) - + min_x) / + static_cast(max_x - min_x); + y = static_cast(std::clamp(static_cast(data.touch_1.y), min_y, max_y) - + min_y) / + static_cast(max_y - min_y); } + clients[client].status.touch_status = {x, y, is_active}; + if (configuring) { const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope(); const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration(); - UpdateYuzuSettings(client, accelerometer, gyroscope); + UpdateYuzuSettings(client, accelerometer, gyroscope, is_active); } } } @@ -302,17 +320,21 @@ void Client::Reset() { } void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3& acc, - const Common::Vec3& gyro) { + const Common::Vec3& gyro, bool touch) { if (gyro.Length() > 0.2f) { - LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client, - gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]); + LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}", + client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch); } UDPPadStatus pad{ .host = clients[client].host, .port = clients[client].port, .pad_index = clients[client].pad_index, }; - for (std::size_t i = 0; i < 3; ++i) { + if (touch) { + pad.touch = PadTouch::Click; + pad_queue.Push(pad); + } + for (size_t i = 0; i < 3; ++i) { if (gyro[i] > 5.0f || gyro[i] < -5.0f) { pad.motion = static_cast(i); pad.motion_value = gyro[i]; @@ -326,50 +348,6 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3& a } } -std::optional Client::GetUnusedFingerID() const { - std::size_t first_free_id = 0; - while (first_free_id < MAX_TOUCH_FINGERS) { - if (!std::get<2>(touch_status[first_free_id])) { - return first_free_id; - } else { - first_free_id++; - } - } - return std::nullopt; -} - -void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) { - // TODO: Use custom calibration per device - const Common::ParamPackage touch_param(Settings::values.touch_device); - const u16 min_x = static_cast(touch_param.Get("min_x", 100)); - const u16 min_y = static_cast(touch_param.Get("min_y", 50)); - const u16 max_x = static_cast(touch_param.Get("max_x", 1800)); - const u16 max_y = static_cast(touch_param.Get("max_y", 850)); - const std::size_t touch_id = client * 2 + id; - if (touch_pad.is_active) { - if (finger_id[touch_id] == MAX_TOUCH_FINGERS) { - const auto first_free_id = GetUnusedFingerID(); - if (!first_free_id) { - // Invalid finger id skip to next input - return; - } - finger_id[touch_id] = *first_free_id; - } - auto& [x, y, pressed] = touch_status[finger_id[touch_id]]; - x = static_cast(std::clamp(static_cast(touch_pad.x), min_x, max_x) - min_x) / - static_cast(max_x - min_x); - y = static_cast(std::clamp(static_cast(touch_pad.y), min_y, max_y) - min_y) / - static_cast(max_y - min_y); - pressed = true; - return; - } - - if (finger_id[touch_id] != MAX_TOUCH_FINGERS) { - touch_status[finger_id[touch_id]] = {}; - finger_id[touch_id] = MAX_TOUCH_FINGERS; - } -} - void Client::BeginConfiguration() { pad_queue.Clear(); configuring = true; @@ -382,7 +360,7 @@ void Client::EndConfiguration() { DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { const std::size_t client_number = GetClientNumber(host, port, pad); - if (client_number == MAX_UDP_CLIENTS) { + if (client_number == max_udp_clients) { return clients[0].status; } return clients[client_number].status; @@ -390,20 +368,12 @@ DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { const std::size_t client_number = GetClientNumber(host, port, pad); - if (client_number == MAX_UDP_CLIENTS) { + if (client_number == max_udp_clients) { return clients[0].status; } return clients[client_number].status; } -Input::TouchStatus& Client::GetTouchState() { - return touch_status; -} - -const Input::TouchStatus& Client::GetTouchState() const { - return touch_status; -} - Common::SPSCQueue& Client::GetPadQueue() { return pad_queue; } @@ -456,24 +426,24 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( current_status = Status::Ready; status_callback(current_status); } - if (data.touch[0].is_active == 0) { + if (data.touch_1.is_active == 0) { return; } - LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, - data.touch[0].y); - min_x = std::min(min_x, static_cast(data.touch[0].x)); - min_y = std::min(min_y, static_cast(data.touch[0].y)); + LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x, + data.touch_1.y); + min_x = std::min(min_x, static_cast(data.touch_1.x)); + min_y = std::min(min_y, static_cast(data.touch_1.y)); if (current_status == Status::Ready) { // First touch - min data (min_x/min_y) current_status = Status::Stage1Completed; status_callback(current_status); } - if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD && - data.touch[0].y - min_y > CALIBRATION_THRESHOLD) { + if (data.touch_1.x - min_x > CALIBRATION_THRESHOLD && + data.touch_1.y - min_y > CALIBRATION_THRESHOLD) { // Set the current position as max value and finishes // configuration - max_x = data.touch[0].x; - max_y = data.touch[0].y; + max_x = data.touch_1.x; + max_y = data.touch_1.y; current_status = Status::Completed; data_callback(min_x, min_y, max_x, max_y); status_callback(current_status); diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h index 822f9c550..00c8b09f5 100755 --- a/src/input_common/udp/client.h +++ b/src/input_common/udp/client.h @@ -28,7 +28,6 @@ class Socket; namespace Response { struct PadData; struct PortInfo; -struct TouchPad; struct Version; } // namespace Response @@ -51,6 +50,7 @@ struct UDPPadStatus { std::string host{"127.0.0.1"}; u16 port{26760}; std::size_t pad_index{}; + PadTouch touch{PadTouch::Undefined}; PadMotion motion{PadMotion::Undefined}; f32 motion_value{0.0f}; }; @@ -93,9 +93,6 @@ public: DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad); const DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad) const; - Input::TouchStatus& GetTouchState(); - const Input::TouchStatus& GetTouchState() const; - private: struct ClientData { std::string host{"127.0.0.1"}; @@ -125,25 +122,14 @@ private: void StartCommunication(std::size_t client, const std::string& host, u16 port, std::size_t pad_index, u32 client_id); void UpdateYuzuSettings(std::size_t client, const Common::Vec3& acc, - const Common::Vec3& gyro); - - // Returns an unused finger id, if there is no fingers available std::nullopt will be - // returned - std::optional GetUnusedFingerID() const; - - // Merges and updates all touch inputs into the touch_status array - void UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id); + const Common::Vec3& gyro, bool touch); bool configuring = false; // Allocate clients for 8 udp servers - static constexpr std::size_t MAX_UDP_CLIENTS = 4 * 8; - // Each client can have up 2 touch inputs - static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2; - std::array clients{}; - Common::SPSCQueue pad_queue{}; - Input::TouchStatus touch_status{}; - std::array finger_id{}; + const std::size_t max_udp_clients = 32; + std::array clients; + Common::SPSCQueue pad_queue; }; /// An async job allowing configuration of the touchpad calibration. diff --git a/src/input_common/udp/protocol.h b/src/input_common/udp/protocol.h index a3d276697..fc1aea4b9 100755 --- a/src/input_common/udp/protocol.h +++ b/src/input_common/udp/protocol.h @@ -140,14 +140,6 @@ static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong si static_assert(std::is_trivially_copyable_v, "UDP Response PortInfo is not trivially copyable"); -struct TouchPad { - u8 is_active{}; - u8 id{}; - u16_le x{}; - u16_le y{}; -}; -static_assert(sizeof(TouchPad) == 6, "UDP Response TouchPad struct has wrong size "); - #pragma pack(push, 1) struct PadData { PortInfo info{}; @@ -198,7 +190,12 @@ struct PadData { u8 button_13{}; } analog_button; - std::array touch; + struct TouchPad { + u8 is_active{}; + u8 id{}; + u16_le x{}; + u16_le y{}; + } touch_1, touch_2; u64_le motion_timestamp; @@ -225,6 +222,7 @@ static_assert(sizeof(Message) == MAX_PACKET_SIZE, static_assert(sizeof(PadData::AnalogButton) == 12, "UDP Response AnalogButton struct has wrong size "); +static_assert(sizeof(PadData::TouchPad) == 6, "UDP Response TouchPad struct has wrong size "); static_assert(sizeof(PadData::Accelerometer) == 12, "UDP Response Accelerometer struct has wrong size "); static_assert(sizeof(PadData::Gyroscope) == 12, "UDP Response Gyroscope struct has wrong size "); diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp index b630281a0..c5da27a38 100755 --- a/src/input_common/udp/udp.cpp +++ b/src/input_common/udp/udp.cpp @@ -78,8 +78,8 @@ public: explicit UDPTouch(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} - Input::TouchStatus GetStatus() const override { - return client->GetTouchState(); + std::tuple GetStatus() const override { + return client->GetPadState(ip, port, pad).touch_status; } private: @@ -107,4 +107,32 @@ std::unique_ptr UDPTouchFactory::Create(const Common::ParamP return std::make_unique(std::move(ip), port, pad, client.get()); } +void UDPTouchFactory::BeginConfiguration() { + polling = true; + client->BeginConfiguration(); +} + +void UDPTouchFactory::EndConfiguration() { + polling = false; + client->EndConfiguration(); +} + +Common::ParamPackage UDPTouchFactory::GetNextInput() { + Common::ParamPackage params; + CemuhookUDP::UDPPadStatus pad; + auto& queue = client->GetPadQueue(); + while (queue.Pop(pad)) { + if (pad.touch == CemuhookUDP::PadTouch::Undefined) { + continue; + } + params.Set("engine", "cemuhookudp"); + params.Set("ip", pad.host); + params.Set("port", static_cast(pad.port)); + params.Set("pad_index", static_cast(pad.pad_index)); + params.Set("touch", static_cast(pad.touch)); + return params; + } + return params; +} + } // namespace InputCommon diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index a883bb049..65feff588 100755 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -101,25 +101,6 @@ void MemoryManager::TryUnlockPage(PageEntry page_entry, std::size_t size) { .IsSuccess()); } -void MemoryManager::UnmapVicFrame(GPUVAddr gpu_addr, std::size_t size) { - if (!size) { - return; - } - - const std::optional cpu_addr = GpuToCpuAddress(gpu_addr); - ASSERT(cpu_addr); - system.GPU().Renderer().Rasterizer().InvalidateExceptTextureCache(*cpu_addr, size); - cache_invalidate_queue.push_back({*cpu_addr, size}); - - UpdateRange(gpu_addr, PageEntry::State::Unmapped, size); -} - -void MemoryManager::InvalidateQueuedCaches() { - for (const auto& entry : cache_invalidate_queue) { - rasterizer->InvalidateTextureCache(entry.first, entry.second); - } - cache_invalidate_queue.clear(); -} PageEntry MemoryManager::GetPageEntry(GPUVAddr gpu_addr) const { return page_table[PageEntryIndex(gpu_addr)]; } diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 74285d059..c35e57689 100755 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h @@ -121,14 +121,6 @@ public: [[nodiscard]] GPUVAddr Allocate(std::size_t size, std::size_t align); void Unmap(GPUVAddr gpu_addr, std::size_t size); - /** - * Some Decoded NVDEC frames require that texture cache does not get invalidated. - * UnmapVicFrame defers the texture cache invalidation until the stream ends - * by invoking InvalidateQueuedCaches to invalidate all frame texture caches. - */ - void UnmapVicFrame(GPUVAddr gpu_addr, std::size_t size); - void InvalidateQueuedCaches(); - private: [[nodiscard]] PageEntry GetPageEntry(GPUVAddr gpu_addr) const; void SetPageEntry(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size = page_size); @@ -158,7 +150,6 @@ private: VideoCore::RasterizerInterface* rasterizer = nullptr; std::vector page_table; - std::vector> cache_invalidate_queue; }; } // namespace Tegra diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 3b5df0586..0cb0f387d 100755 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -64,12 +64,6 @@ public: /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory virtual void FlushRegion(VAddr addr, u64 size) = 0; - /// Notify rasterizer to flush the texture cache to Switch memory - virtual void InvalidateExceptTextureCache(VAddr addr, u64 size) = 0; - - /// Notify rasterizer to invalidate the texture cache - virtual void InvalidateTextureCache(VAddr addr, u64 size) = 0; - /// Check if the the specified memory area requires flushing to CPU Memory. virtual bool MustFlushRegion(VAddr addr, u64 size) = 0; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 34c85baf9..8aa63d329 100755 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -721,23 +721,6 @@ void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) { query_cache.FlushRegion(addr, size); } -void RasterizerOpenGL::InvalidateExceptTextureCache(VAddr addr, u64 size) { - if (addr == 0 || size == 0) { - return; - } - shader_cache.InvalidateRegion(addr, size); - buffer_cache.InvalidateRegion(addr, size); - query_cache.InvalidateRegion(addr, size); -} - -void RasterizerOpenGL::InvalidateTextureCache(VAddr addr, u64 size) { - if (addr == 0 || size == 0) { - return; - } - auto lock = texture_cache.AcquireLock(); - texture_cache.UnmapMemory(addr, size); -} - bool RasterizerOpenGL::MustFlushRegion(VAddr addr, u64 size) { if (!Settings::IsGPULevelHigh()) { return buffer_cache.MustFlushRegion(addr, size); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 9f07a5d68..82e03e677 100755 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -74,8 +74,6 @@ public: void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional timestamp) override; void FlushAll() override; void FlushRegion(VAddr addr, u64 size) override; - void InvalidateExceptTextureCache(VAddr addr, u64 size) override; - void InvalidateTextureCache(VAddr addr, u64 size) override; bool MustFlushRegion(VAddr addr, u64 size) override; void InvalidateRegion(VAddr addr, u64 size) override; void OnCPUWrite(VAddr addr, u64 size) override; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 893853487..f0a111829 100755 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -658,23 +658,6 @@ void RasterizerVulkan::FlushRegion(VAddr addr, u64 size) { query_cache.FlushRegion(addr, size); } -void Vulkan::RasterizerVulkan::InvalidateExceptTextureCache(VAddr addr, u64 size) { - if (addr == 0 || size == 0) { - return; - } - pipeline_cache.InvalidateRegion(addr, size); - buffer_cache.InvalidateRegion(addr, size); - query_cache.InvalidateRegion(addr, size); -} - -void Vulkan::RasterizerVulkan::InvalidateTextureCache(VAddr addr, u64 size) { - if (addr == 0 || size == 0) { - return; - } - auto lock = texture_cache.AcquireLock(); - texture_cache.UnmapMemory(addr, size); -} - bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size) { if (!Settings::IsGPULevelHigh()) { return buffer_cache.MustFlushRegion(addr, size); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 8fbc25fd4..8e261b9bd 100755 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -67,8 +67,6 @@ public: void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional timestamp) override; void FlushAll() override; void FlushRegion(VAddr addr, u64 size) override; - void InvalidateExceptTextureCache(VAddr addr, u64 size) override; - void InvalidateTextureCache(VAddr addr, u64 size) override; bool MustFlushRegion(VAddr addr, u64 size) override; void InvalidateRegion(VAddr addr, u64 size) override; void OnCPUWrite(VAddr addr, u64 size) override; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 6802be295..e1bab2112 100755 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -71,8 +71,6 @@ add_executable(yuzu configuration/configure_input_player.cpp configuration/configure_input_player.h configuration/configure_input_player.ui - configuration/configure_input_player_widget.cpp - configuration/configure_input_player_widget.h configuration/configure_input_profile_dialog.cpp configuration/configure_input_profile_dialog.h configuration/configure_input_profile_dialog.ui diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 4528eb196..e6c8f18af 100755 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -394,7 +394,7 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { input_subsystem->GetMouse()->PressButton(x, y, event->button()); if (event->button() == Qt::LeftButton) { - this->TouchPressed(x, y, 0); + this->TouchPressed(x, y); } emit MouseActivity(); @@ -409,7 +409,7 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { auto pos = event->pos(); const auto [x, y] = ScaleTouch(pos); input_subsystem->GetMouse()->MouseMove(x, y); - this->TouchMoved(x, y, 0); + this->TouchMoved(x, y); emit MouseActivity(); } @@ -423,72 +423,36 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { input_subsystem->GetMouse()->ReleaseButton(event->button()); if (event->button() == Qt::LeftButton) { - this->TouchReleased(0); + this->TouchReleased(); } } void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { - QList touch_points = event->touchPoints(); - for (const auto& touch_point : touch_points) { - if (!TouchUpdate(touch_point)) { - TouchStart(touch_point); - } - } + // TouchBegin always has exactly one touch point, so take the .first() + const auto [x, y] = ScaleTouch(event->touchPoints().first().pos()); + this->TouchPressed(x, y); } void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) { - QList touch_points = event->touchPoints(); - for (const auto& touch_point : touch_points) { - if (!TouchUpdate(touch_point)) { - TouchStart(touch_point); - } - } - // Release all inactive points - for (std::size_t id = 0; id < touch_ids.size(); ++id) { - if (!TouchExist(touch_ids[id], touch_points)) { - touch_ids[id] = 0; - this->TouchReleased(id + 1); + QPointF pos; + int active_points = 0; + + // average all active touch points + for (const auto& tp : event->touchPoints()) { + if (tp.state() & (Qt::TouchPointPressed | Qt::TouchPointMoved | Qt::TouchPointStationary)) { + active_points++; + pos += tp.pos(); } } + + pos /= active_points; + + const auto [x, y] = ScaleTouch(pos); + this->TouchMoved(x, y); } void GRenderWindow::TouchEndEvent() { - for (std::size_t id = 0; id < touch_ids.size(); ++id) { - if (touch_ids[id] != 0) { - touch_ids[id] = 0; - this->TouchReleased(id + 1); - } - } -} - -bool GRenderWindow::TouchStart(const QTouchEvent::TouchPoint& touch_point) { - for (std::size_t id = 0; id < touch_ids.size(); ++id) { - if (touch_ids[id] == 0) { - touch_ids[id] = touch_point.id() + 1; - const auto [x, y] = ScaleTouch(touch_point.pos()); - this->TouchPressed(x, y, id + 1); - return true; - } - } - return false; -} - -bool GRenderWindow::TouchUpdate(const QTouchEvent::TouchPoint& touch_point) { - for (std::size_t id = 0; id < touch_ids.size(); ++id) { - if (touch_ids[id] == static_cast(touch_point.id() + 1)) { - const auto [x, y] = ScaleTouch(touch_point.pos()); - this->TouchMoved(x, y, id + 1); - return true; - } - } - return false; -} - -bool GRenderWindow::TouchExist(std::size_t id, - const QList& touch_points) const { - return std::any_of(touch_points.begin(), touch_points.end(), [id](const auto& point) { - return id == static_cast(point.id() + 1); - }); + this->TouchReleased(); } bool GRenderWindow::event(QEvent* event) { diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index b5ec7de07..339095509 100755 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -22,6 +21,7 @@ class GRenderWindow; class GMainWindow; class QKeyEvent; +class QTouchEvent; class QStringList; namespace InputCommon { @@ -191,10 +191,6 @@ private: void TouchUpdateEvent(const QTouchEvent* event); void TouchEndEvent(); - bool TouchStart(const QTouchEvent::TouchPoint& touch_point); - bool TouchUpdate(const QTouchEvent::TouchPoint& touch_point); - bool TouchExist(std::size_t id, const QList& touch_points) const; - void OnMinimalClientAreaChangeRequest(std::pair minimal_size) override; bool InitializeOpenGL(); @@ -219,8 +215,6 @@ private: bool first_frame = false; - std::array touch_ids{}; - protected: void showEvent(QShowEvent* event) override; bool eventFilter(QObject* object, QEvent* event) override; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 5e4d22299..cda448718 100755 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -464,7 +464,13 @@ void Config::ReadMouseValues() { void Config::ReadTouchscreenValues() { Settings::values.touchscreen.enabled = ReadSetting(QStringLiteral("touchscreen_enabled"), true).toBool(); + Settings::values.touchscreen.device = + ReadSetting(QStringLiteral("touchscreen_device"), QStringLiteral("engine:emu_window")) + .toString() + .toStdString(); + Settings::values.touchscreen.finger = + ReadSetting(QStringLiteral("touchscreen_finger"), 0).toUInt(); Settings::values.touchscreen.rotation_angle = ReadSetting(QStringLiteral("touchscreen_angle"), 0).toUInt(); Settings::values.touchscreen.diameter_x = @@ -557,8 +563,7 @@ void Config::ReadMotionTouchValues() { .toString() .toStdString(); Settings::values.touch_device = - ReadSetting(QStringLiteral("touch_device"), - QStringLiteral("min_x:100,min_y:50,max_x:1800,max_y:850")) + ReadSetting(QStringLiteral("touch_device"), QStringLiteral("engine:emu_window")) .toString() .toStdString(); Settings::values.use_touch_from_button = @@ -1082,7 +1087,10 @@ void Config::SaveTouchscreenValues() { const auto& touchscreen = Settings::values.touchscreen; WriteSetting(QStringLiteral("touchscreen_enabled"), touchscreen.enabled, true); + WriteSetting(QStringLiteral("touchscreen_device"), QString::fromStdString(touchscreen.device), + QStringLiteral("engine:emu_window")); + WriteSetting(QStringLiteral("touchscreen_finger"), touchscreen.finger, 0); WriteSetting(QStringLiteral("touchscreen_angle"), touchscreen.rotation_angle, 0); WriteSetting(QStringLiteral("touchscreen_diameter_x"), touchscreen.diameter_x, 15); WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15); diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 0a79993eb..46ea026e4 100755 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -23,7 +23,6 @@ #include "ui_configure_input_player.h" #include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_input_player.h" -#include "yuzu/configuration/configure_input_player_widget.h" #include "yuzu/configuration/configure_vibration.h" #include "yuzu/configuration/input_profiles.h" #include "yuzu/util/limitable_input_dialog.h" @@ -255,12 +254,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup}; analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange}; - const auto ConfigureButtonClick = [&](QPushButton* button, std::size_t button_id, - Common::ParamPackage* param, int default_val, - InputCommon::Polling::DeviceType type) { + const auto ConfigureButtonClick = [&](QPushButton* button, Common::ParamPackage* param, + int default_val, InputCommon::Polling::DeviceType type) { connect(button, &QPushButton::clicked, [=, this] { HandleClick( - button, button_id, + button, [=, this](Common::ParamPackage params) { // Workaround for ZL & ZR for analog triggers like on XBOX // controllers. Analog triggers (from controllers like the XBOX @@ -288,11 +286,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i continue; } - ConfigureButtonClick(button_map[button_id], button_id, &buttons_param[button_id], + ConfigureButtonClick(button_map[button_id], &buttons_param[button_id], Config::default_buttons[button_id], InputCommon::Polling::DeviceType::Button); button->setContextMenuPolicy(Qt::CustomContextMenu); + connect(button, &QPushButton::customContextMenuRequested, [=, this](const QPoint& menu_location) { QMenu context_menu; @@ -301,7 +300,6 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i button_map[button_id]->setText(tr("[not set]")); }); context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); - ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); }); } @@ -311,7 +309,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i continue; } - ConfigureButtonClick(motion_map[motion_id], motion_id, &motions_param[motion_id], + ConfigureButtonClick(motion_map[motion_id], &motions_param[motion_id], Config::default_motions[motion_id], InputCommon::Polling::DeviceType::Motion); @@ -350,7 +348,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i } } HandleClick( - analog_map_buttons[analog_id][sub_button_id], analog_id, + analog_map_buttons[analog_id][sub_button_id], [=, this](const Common::ParamPackage& params) { SetAnalogParam(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]); @@ -360,43 +358,41 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i analog_button->setContextMenuPolicy(Qt::CustomContextMenu); - connect( - analog_button, &QPushButton::customContextMenuRequested, - [=, this](const QPoint& menu_location) { - QMenu context_menu; - context_menu.addAction(tr("Clear"), [&] { - analogs_param[analog_id].Clear(); - analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); + connect(analog_button, &QPushButton::customContextMenuRequested, + [=, this](const QPoint& menu_location) { + QMenu context_menu; + context_menu.addAction(tr("Clear"), [&] { + analogs_param[analog_id].Clear(); + analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); + }); + context_menu.addAction(tr("Invert axis"), [&] { + if (sub_button_id == 2 || sub_button_id == 3) { + const bool invert_value = + analogs_param[analog_id].Get("invert_x", "+") == "-"; + const std::string invert_str = invert_value ? "+" : "-"; + analogs_param[analog_id].Set("invert_x", invert_str); + } + if (sub_button_id == 0 || sub_button_id == 1) { + const bool invert_value = + analogs_param[analog_id].Get("invert_y", "+") == "-"; + const std::string invert_str = invert_value ? "+" : "-"; + analogs_param[analog_id].Set("invert_y", invert_str); + } + for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; + ++sub_button_id) { + analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText( + analogs_param[analog_id], analog_sub_buttons[sub_button_id])); + } + }); + context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal( + menu_location)); }); - context_menu.addAction(tr("Invert axis"), [&] { - if (sub_button_id == 2 || sub_button_id == 3) { - const bool invert_value = - analogs_param[analog_id].Get("invert_x", "+") == "-"; - const std::string invert_str = invert_value ? "+" : "-"; - analogs_param[analog_id].Set("invert_x", invert_str); - } - if (sub_button_id == 0 || sub_button_id == 1) { - const bool invert_value = - analogs_param[analog_id].Get("invert_y", "+") == "-"; - const std::string invert_str = invert_value ? "+" : "-"; - analogs_param[analog_id].Set("invert_y", invert_str); - } - for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; - ++sub_button_id) { - analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText( - analogs_param[analog_id], analog_sub_buttons[sub_button_id])); - } - }); - context_menu.exec( - analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(menu_location)); - ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); - }); } // Handle clicks for the modifier buttons as well. connect(analog_map_modifier_button[analog_id], &QPushButton::clicked, [=, this] { HandleClick( - analog_map_modifier_button[analog_id], analog_id, + analog_map_modifier_button[analog_id], [=, this](const Common::ParamPackage& params) { analogs_param[analog_id].Set("modifier", params.Serialize()); }, @@ -420,14 +416,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i [=, this] { const auto spinbox_value = analog_map_range_spinbox[analog_id]->value(); analogs_param[analog_id].Set("range", spinbox_value / 100.0f); - ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); }); connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] { const auto slider_value = analog_map_deadzone_slider[analog_id]->value(); analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value)); analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); - ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); }); connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] { @@ -439,10 +433,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i } // Player Connected checkbox - connect(ui->groupConnectedController, &QGroupBox::toggled, [this](bool checked) { - emit Connected(checked); - ui->controllerFrame->SetConnectedStatus(checked); - }); + connect(ui->groupConnectedController, &QGroupBox::toggled, + [this](bool checked) { emit Connected(checked); }); if (player_index == 0) { connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), @@ -561,8 +553,6 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i // TODO(wwylele): enable this when we actually emulate it ui->buttonHome->setEnabled(false); - ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); - ui->controllerFrame->SetConnectedStatus(ui->groupConnectedController->isChecked()); } ConfigureInputPlayer::~ConfigureInputPlayer() = default; @@ -859,7 +849,6 @@ void ConfigureInputPlayer::UpdateUI() { modifier_label->setVisible(!is_controller); modifier_slider->setVisible(!is_controller); range_groupbox->setVisible(is_controller); - ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); } } @@ -976,8 +965,8 @@ void ConfigureInputPlayer::UpdateControllerIcon() { return QString{}; } }(); - ui->controllerFrame->SetControllerType( - GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())); + + ui->controllerFrame->setStyleSheet(stylesheet.arg(theme)); } void ConfigureInputPlayer::UpdateControllerAvailableButtons() { @@ -1114,8 +1103,7 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { } void ConfigureInputPlayer::HandleClick( - QPushButton* button, std::size_t button_id, - std::function new_input_setter, + QPushButton* button, std::function new_input_setter, InputCommon::Polling::DeviceType type) { if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) { button->setText(tr("Shake!")); @@ -1159,12 +1147,6 @@ void ConfigureInputPlayer::HandleClick( input_subsystem->GetMouseTouch()->BeginConfiguration(); } - if (type == InputCommon::Polling::DeviceType::Button) { - ui->controllerFrame->BeginMappingButton(button_id); - } else if (type == InputCommon::Polling::DeviceType::AnalogPreferred) { - ui->controllerFrame->BeginMappingAnalog(button_id); - } - timeout_timer->start(2500); // Cancel after 2.5 seconds poll_timer->start(50); // Check for new inputs every 50ms } @@ -1195,7 +1177,6 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, UpdateUI(); UpdateInputDeviceCombobox(); - ui->controllerFrame->EndMapping(); input_setter = std::nullopt; } diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index da2b89136..c4ae50de7 100755 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h @@ -106,7 +106,7 @@ private: void LoadConfiguration(); /// Called when the button was pressed. - void HandleClick(QPushButton* button, std::size_t button_id, + void HandleClick(QPushButton* button, std::function new_input_setter, InputCommon::Polling::DeviceType type); diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index e76aa484f..1e78b4c10 100755 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui @@ -1964,39 +1964,39 @@ - - - - - 0 - 0 - - - - - 75 - true - - - - image: url(:/controller/pro); - - - - 0 - - - 0 - - - 0 - - - 0 - - - - + + + + + 0 + 0 + + + + + 75 + true + + + + image: url(:/controller/pro); + + + + 0 + + + 0 + + + 0 + + + 0 + + + + @@ -3087,14 +3087,6 @@ - - - PlayerControlPreview - QFrame -
yuzu/configuration/configure_input_player_widget.h
- 1 -
-
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp index 1f2b792e4..caaa85930 100755 --- a/src/yuzu/configuration/configure_motion_touch.cpp +++ b/src/yuzu/configuration/configure_motion_touch.cpp @@ -81,11 +81,19 @@ void CalibrationConfigurationDialog::UpdateButtonText(const QString& text) { cancel_button->setText(text); } +constexpr std::array, 2> TouchProviders = {{ + {"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")}, + {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")}, +}}; + ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_) : QDialog(parent), input_subsystem{input_subsystem_}, ui(std::make_unique()) { ui->setupUi(this); + for (const auto& [provider, name] : TouchProviders) { + ui->touch_provider->addItem(tr(name), QString::fromUtf8(provider)); + } ui->udp_learn_more->setOpenExternalLinks(true); ui->udp_learn_more->setText( @@ -104,7 +112,10 @@ ConfigureMotionTouch::~ConfigureMotionTouch() = default; void ConfigureMotionTouch::SetConfiguration() { const Common::ParamPackage motion_param(Settings::values.motion_device); const Common::ParamPackage touch_param(Settings::values.touch_device); + const std::string touch_engine = touch_param.Get("engine", "emu_window"); + ui->touch_provider->setCurrentIndex( + ui->touch_provider->findData(QString::fromStdString(touch_engine))); ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button); touch_from_button_maps = Settings::values.touch_from_button_maps; for (const auto& touch_map : touch_from_button_maps) { @@ -137,21 +148,30 @@ void ConfigureMotionTouch::SetConfiguration() { } void ConfigureMotionTouch::UpdateUiDisplay() { + const QString touch_engine = ui->touch_provider->currentData().toString(); const QString cemuhook_udp = QStringLiteral("cemuhookudp"); ui->motion_sensitivity_label->setVisible(true); ui->motion_sensitivity->setVisible(true); - ui->touch_calibration->setVisible(true); - ui->touch_calibration_config->setVisible(true); - ui->touch_calibration_label->setVisible(true); - ui->touch_calibration->setText( - QStringLiteral("(%1, %2) - (%3, %4)").arg(min_x).arg(min_y).arg(max_x).arg(max_y)); + if (touch_engine == cemuhook_udp) { + ui->touch_calibration->setVisible(true); + ui->touch_calibration_config->setVisible(true); + ui->touch_calibration_label->setVisible(true); + ui->touch_calibration->setText( + QStringLiteral("(%1, %2) - (%3, %4)").arg(min_x).arg(min_y).arg(max_x).arg(max_y)); + } else { + ui->touch_calibration->setVisible(false); + ui->touch_calibration_config->setVisible(false); + ui->touch_calibration_label->setVisible(false); + } ui->udp_config_group_box->setVisible(true); } void ConfigureMotionTouch::ConnectEvents() { + connect(ui->touch_provider, qOverload(&QComboBox::currentIndexChanged), this, + [this](int index) { UpdateUiDisplay(); }); connect(ui->udp_test, &QPushButton::clicked, this, &ConfigureMotionTouch::OnCemuhookUDPTest); connect(ui->udp_add, &QPushButton::clicked, this, &ConfigureMotionTouch::OnUDPAddServer); connect(ui->udp_remove, &QPushButton::clicked, this, &ConfigureMotionTouch::OnUDPDeleteServer); @@ -307,11 +327,16 @@ void ConfigureMotionTouch::ApplyConfiguration() { return; } + std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); + Common::ParamPackage touch_param{}; - touch_param.Set("min_x", min_x); - touch_param.Set("min_y", min_y); - touch_param.Set("max_x", max_x); - touch_param.Set("max_y", max_y); + if (touch_engine == "cemuhookudp") { + touch_param.Set("min_x", min_x); + touch_param.Set("min_y", min_y); + touch_param.Set("max_x", max_x); + touch_param.Set("max_y", max_y); + } + touch_param.Set("engine", std::move(touch_engine)); Settings::values.touch_device = touch_param.Serialize(); Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked(); diff --git a/src/yuzu/configuration/configure_motion_touch.ui b/src/yuzu/configuration/configure_motion_touch.ui index 1e35ea946..ebca835ac 100755 --- a/src/yuzu/configuration/configure_motion_touch.ui +++ b/src/yuzu/configuration/configure_motion_touch.ui @@ -65,12 +65,26 @@ Touch + + + + + + Touch Provider: + + + + + + + + - UDP Calibration: + Calibration: diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.cpp b/src/yuzu/configuration/configure_touchscreen_advanced.cpp index 29c86c7bc..7d7cc00b7 100755 --- a/src/yuzu/configuration/configure_touchscreen_advanced.cpp +++ b/src/yuzu/configuration/configure_touchscreen_advanced.cpp @@ -33,18 +33,21 @@ void ConfigureTouchscreenAdvanced::RetranslateUI() { } void ConfigureTouchscreenAdvanced::ApplyConfiguration() { + Settings::values.touchscreen.finger = ui->finger_box->value(); Settings::values.touchscreen.diameter_x = ui->diameter_x_box->value(); Settings::values.touchscreen.diameter_y = ui->diameter_y_box->value(); Settings::values.touchscreen.rotation_angle = ui->angle_box->value(); } void ConfigureTouchscreenAdvanced::LoadConfiguration() { + ui->finger_box->setValue(Settings::values.touchscreen.finger); ui->diameter_x_box->setValue(Settings::values.touchscreen.diameter_x); ui->diameter_y_box->setValue(Settings::values.touchscreen.diameter_y); ui->angle_box->setValue(Settings::values.touchscreen.rotation_angle); } void ConfigureTouchscreenAdvanced::RestoreDefaults() { + ui->finger_box->setValue(0); ui->diameter_x_box->setValue(15); ui->diameter_y_box->setValue(15); ui->angle_box->setValue(0); diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.ui b/src/yuzu/configuration/configure_touchscreen_advanced.ui index 88e7cf050..30ceccddb 100755 --- a/src/yuzu/configuration/configure_touchscreen_advanced.ui +++ b/src/yuzu/configuration/configure_touchscreen_advanced.ui @@ -65,13 +65,20 @@ - + Touch Diameter Y + + + + Finger + + + @@ -85,27 +92,37 @@ - + Touch Diameter X - + + + + + 80 + 0 + + + + + Rotational Angle - + - + - + diff --git a/src/yuzu/discord_impl.cpp b/src/yuzu/discord_impl.cpp index aad06ac2a..a93733b26 100755 --- a/src/yuzu/discord_impl.cpp +++ b/src/yuzu/discord_impl.cpp @@ -38,7 +38,7 @@ void DiscordImpl::Update() { if (Core::System::GetInstance().IsPoweredOn()) Core::System::GetInstance().GetAppLoader().ReadTitle(title); DiscordRichPresence presence{}; - presence.largeImageKey = "yuzu_logo_ea"; + presence.largeImageKey = "yuzu_logo"; presence.largeImageText = "yuzu is an emulator for the Nintendo Switch"; if (Core::System::GetInstance().IsPoweredOn()) { presence.state = title.c_str(); diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index f76102459..41ef6f6b8 100755 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -296,6 +296,10 @@ void Config::ReadValues() { sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true)); Settings::values.touchscreen.enabled = sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true); + Settings::values.touchscreen.device = + sdl2_config->Get("ControlsGeneral", "touch_device", "engine:emu_window"); + Settings::values.touchscreen.finger = + sdl2_config->GetInteger("ControlsGeneral", "touch_finger", 0); Settings::values.touchscreen.rotation_angle = sdl2_config->GetInteger("ControlsGeneral", "touch_angle", 0); Settings::values.touchscreen.diameter_x = diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 7843d5167..e32bed5e6 100755 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp @@ -29,16 +29,16 @@ EmuWindow_SDL2::~EmuWindow_SDL2() { } void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { - TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); + TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); input_subsystem->GetMouse()->MouseMove(x, y); } void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { if (button == SDL_BUTTON_LEFT) { if (state == SDL_PRESSED) { - TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); + TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); } else { - TouchReleased(0); + TouchReleased(); } } else if (button == SDL_BUTTON_RIGHT) { if (state == SDL_PRESSED) { @@ -66,16 +66,16 @@ void EmuWindow_SDL2::OnFingerDown(float x, float y) { // 3DS does const auto [px, py] = TouchToPixelPos(x, y); - TouchPressed(px, py, 0); + TouchPressed(px, py); } void EmuWindow_SDL2::OnFingerMotion(float x, float y) { const auto [px, py] = TouchToPixelPos(x, y); - TouchMoved(px, py, 0); + TouchMoved(px, py); } void EmuWindow_SDL2::OnFingerUp() { - TouchReleased(0); + TouchReleased(); } void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {