summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--dist/org.yuzu_emu.yuzu.metainfo.xml5
-rw-r--r--dist/qt_themes/default/icons/256x256/yuzu.pngbin10381 -> 6751 bytes
-rw-r--r--src/audio_core/command_generator.cpp16
-rw-r--r--src/common/fs/path_util.cpp4
-rw-r--r--src/common/input.h1
-rw-r--r--src/core/hid/emulated_console.cpp15
-rw-r--r--src/core/hid/emulated_controller.cpp34
-rw-r--r--src/core/hid/input_converter.cpp4
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp6
-rw-r--r--src/core/hle/service/time/time_zone_manager.cpp7
-rw-r--r--src/input_common/drivers/sdl_driver.cpp23
-rw-r--r--src/input_common/drivers/sdl_driver.h12
-rw-r--r--src/input_common/drivers/touch_screen.cpp89
-rw-r--r--src/input_common/drivers/touch_screen.h52
-rw-r--r--src/video_core/command_classes/codecs/vp9.cpp8
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp4
-rw-r--r--src/video_core/surface.h6
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp18
-rw-r--r--src/yuzu/CMakeLists.txt2
-rw-r--r--src/yuzu/about_dialog.cpp6
-rw-r--r--src/yuzu/aboutdialog.ui16
-rw-r--r--src/yuzu/bootmanager.cpp58
-rw-r--r--src/yuzu/bootmanager.h6
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp2
25 files changed, 268 insertions, 130 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fe12f3d23..8e3de90ff 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -218,8 +218,8 @@ if (Boost_FOUND)
218 list(APPEND Boost_LIBRARIES Boost::context) 218 list(APPEND Boost_LIBRARIES Boost::context)
219 endif() 219 endif()
220else() 220else()
221 message(STATUS "Boost 1.73.0 or newer not found, falling back to Conan") 221 message(STATUS "Boost 1.79.0 or newer not found, falling back to Conan")
222 list(APPEND CONAN_REQUIRED_LIBS "boost/1.78.0") 222 list(APPEND CONAN_REQUIRED_LIBS "boost/1.79.0")
223endif() 223endif()
224 224
225# Attempt to locate any packages that are required and report the missing ones in CONAN_REQUIRED_LIBS 225# Attempt to locate any packages that are required and report the missing ones in CONAN_REQUIRED_LIBS
diff --git a/dist/org.yuzu_emu.yuzu.metainfo.xml b/dist/org.yuzu_emu.yuzu.metainfo.xml
index 5f366137b..bcc5fc9a9 100644
--- a/dist/org.yuzu_emu.yuzu.metainfo.xml
+++ b/dist/org.yuzu_emu.yuzu.metainfo.xml
@@ -32,6 +32,11 @@
32 <binary>yuzu</binary> 32 <binary>yuzu</binary>
33 <binary>yuzu-cmd</binary> 33 <binary>yuzu-cmd</binary>
34 </provides> 34 </provides>
35 <supports>
36 <control>pointing</control>
37 <control>keyboard</control>
38 <control>gamepad</control>
39 </supports>
35 <requires> 40 <requires>
36 <memory>8192</memory> 41 <memory>8192</memory>
37 </requires> 42 </requires>
diff --git a/dist/qt_themes/default/icons/256x256/yuzu.png b/dist/qt_themes/default/icons/256x256/yuzu.png
index 1e501d8a6..bd5cf533f 100644
--- a/dist/qt_themes/default/icons/256x256/yuzu.png
+++ b/dist/qt_themes/default/icons/256x256/yuzu.png
Binary files differ
diff --git a/src/audio_core/command_generator.cpp b/src/audio_core/command_generator.cpp
index ae4efafb6..ff20ed00f 100644
--- a/src/audio_core/command_generator.cpp
+++ b/src/audio_core/command_generator.cpp
@@ -129,17 +129,17 @@ s32 ToS32(float sample) {
129 return static_cast<s32>(rescaled_sample); 129 return static_cast<s32>(rescaled_sample);
130} 130}
131 131
132constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_1CH{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132constexpr std::array<u8, 20> REVERB_TAP_INDEX_1CH{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
134 134
135constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_2CH{0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 135constexpr std::array<u8, 20> REVERB_TAP_INDEX_2CH{0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
136 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}; 136 1, 1, 1, 0, 0, 0, 0, 1, 1, 1};
137 137
138constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_4CH{0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 138constexpr std::array<u8, 20> REVERB_TAP_INDEX_4CH{0, 0, 0, 1, 1, 1, 1, 2, 2, 2,
139 1, 1, 1, 0, 0, 0, 0, 3, 3, 3}; 139 1, 1, 1, 0, 0, 0, 0, 3, 3, 3};
140 140
141constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_6CH{4, 0, 0, 1, 1, 1, 1, 2, 2, 2, 141constexpr std::array<u8, 20> REVERB_TAP_INDEX_6CH{4, 0, 0, 1, 1, 1, 1, 2, 2, 2,
142 1, 1, 1, 0, 0, 0, 0, 3, 3, 3}; 142 1, 1, 1, 0, 0, 0, 0, 3, 3, 3};
143 143
144template <std::size_t CHANNEL_COUNT> 144template <std::size_t CHANNEL_COUNT>
145void ApplyReverbGeneric( 145void ApplyReverbGeneric(
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp
index 62318e70c..1074f2421 100644
--- a/src/common/fs/path_util.cpp
+++ b/src/common/fs/path_util.cpp
@@ -232,9 +232,7 @@ void SetYuzuPath(YuzuPath yuzu_path, const fs::path& new_path) {
232fs::path GetExeDirectory() { 232fs::path GetExeDirectory() {
233 wchar_t exe_path[MAX_PATH]; 233 wchar_t exe_path[MAX_PATH];
234 234
235 GetModuleFileNameW(nullptr, exe_path, MAX_PATH); 235 if (GetModuleFileNameW(nullptr, exe_path, MAX_PATH) == 0) {
236
237 if (!exe_path) {
238 LOG_ERROR(Common_Filesystem, 236 LOG_ERROR(Common_Filesystem,
239 "Failed to get the path to the executable of the current process"); 237 "Failed to get the path to the executable of the current process");
240 } 238 }
diff --git a/src/common/input.h b/src/common/input.h
index 54fcb24b0..bb42aaacc 100644
--- a/src/common/input.h
+++ b/src/common/input.h
@@ -72,6 +72,7 @@ enum class PollingError {
72enum class VibrationAmplificationType { 72enum class VibrationAmplificationType {
73 Linear, 73 Linear,
74 Exponential, 74 Exponential,
75 Test,
75}; 76};
76 77
77// Analog properties for calibration 78// Analog properties for calibration
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp
index fd220ccb5..aac45907d 100644
--- a/src/core/hid/emulated_console.cpp
+++ b/src/core/hid/emulated_console.cpp
@@ -27,12 +27,19 @@ void EmulatedConsole::SetTouchParams() {
27 // We can't use mouse as touch if native mouse is enabled 27 // We can't use mouse as touch if native mouse is enabled
28 touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; 28 touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"};
29 } 29 }
30 touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"}; 30
31 touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"}; 31 touch_params[index++] =
32 Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0,touch_id:0"};
33 touch_params[index++] =
34 Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1,touch_id:1"};
35 touch_params[index++] =
36 Common::ParamPackage{"engine:touch,axis_x:4,axis_y:5,button:2,touch_id:2"};
37 touch_params[index++] =
38 Common::ParamPackage{"engine:touch,axis_x:6,axis_y:7,button:3,touch_id:3"};
32 touch_params[index++] = 39 touch_params[index++] =
33 Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"}; 40 Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536,touch_id:0"};
34 touch_params[index++] = 41 touch_params[index++] =
35 Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"}; 42 Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072,touch_id:1"};
36 43
37 const auto button_index = 44 const auto button_index =
38 static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue()); 45 static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index ba1dcd171..bd2384515 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -884,18 +884,42 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v
884} 884}
885 885
886bool EmulatedController::TestVibration(std::size_t device_index) { 886bool EmulatedController::TestVibration(std::size_t device_index) {
887 static constexpr VibrationValue test_vibration = { 887 if (device_index >= output_devices.size()) {
888 return false;
889 }
890 if (!output_devices[device_index]) {
891 return false;
892 }
893
894 const auto player_index = NpadIdTypeToIndex(npad_id_type);
895 const auto& player = Settings::values.players.GetValue()[player_index];
896
897 if (!player.vibration_enabled) {
898 return false;
899 }
900
901 const Common::Input::VibrationStatus test_vibration = {
888 .low_amplitude = 0.001f, 902 .low_amplitude = 0.001f,
889 .low_frequency = 160.0f, 903 .low_frequency = DEFAULT_VIBRATION_VALUE.low_frequency,
890 .high_amplitude = 0.001f, 904 .high_amplitude = 0.001f,
891 .high_frequency = 320.0f, 905 .high_frequency = DEFAULT_VIBRATION_VALUE.high_frequency,
906 .type = Common::Input::VibrationAmplificationType::Test,
907 };
908
909 const Common::Input::VibrationStatus zero_vibration = {
910 .low_amplitude = DEFAULT_VIBRATION_VALUE.low_amplitude,
911 .low_frequency = DEFAULT_VIBRATION_VALUE.low_frequency,
912 .high_amplitude = DEFAULT_VIBRATION_VALUE.high_amplitude,
913 .high_frequency = DEFAULT_VIBRATION_VALUE.high_frequency,
914 .type = Common::Input::VibrationAmplificationType::Test,
892 }; 915 };
893 916
894 // Send a slight vibration to test for rumble support 917 // Send a slight vibration to test for rumble support
895 SetVibration(device_index, test_vibration); 918 output_devices[device_index]->SetVibration(test_vibration);
896 919
897 // Stop any vibration and return the result 920 // Stop any vibration and return the result
898 return SetVibration(device_index, DEFAULT_VIBRATION_VALUE); 921 return output_devices[device_index]->SetVibration(zero_vibration) ==
922 Common::Input::VibrationError::None;
899} 923}
900 924
901bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) { 925bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) {
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp
index 3c26260f3..18d9f042d 100644
--- a/src/core/hid/input_converter.cpp
+++ b/src/core/hid/input_converter.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <algorithm>
4#include <random> 5#include <random>
5 6
6#include "common/input.h" 7#include "common/input.h"
@@ -196,6 +197,9 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus&
196 x = std::clamp(x, 0.0f, 1.0f); 197 x = std::clamp(x, 0.0f, 1.0f);
197 y = std::clamp(y, 0.0f, 1.0f); 198 y = std::clamp(y, 0.0f, 1.0f);
198 199
200 // Limit id to maximum number of fingers
201 status.id = std::clamp(status.id, 0, 16);
202
199 if (status.pressed.inverted) { 203 if (status.pressed.inverted) {
200 status.pressed.value = !status.pressed.value; 204 status.pressed.value = !status.pressed.value;
201 } 205 }
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index 108ce5a41..1da8d3eb0 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -44,7 +44,6 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
44 for (std::size_t id = 0; id < MAX_FINGERS; id++) { 44 for (std::size_t id = 0; id < MAX_FINGERS; id++) {
45 const auto& current_touch = touch_status[id]; 45 const auto& current_touch = touch_status[id];
46 auto& finger = fingers[id]; 46 auto& finger = fingers[id];
47 finger.position = current_touch.position;
48 finger.id = current_touch.id; 47 finger.id = current_touch.id;
49 48
50 if (finger.attribute.start_touch) { 49 if (finger.attribute.start_touch) {
@@ -61,13 +60,18 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
61 if (!finger.pressed && current_touch.pressed) { 60 if (!finger.pressed && current_touch.pressed) {
62 finger.attribute.start_touch.Assign(1); 61 finger.attribute.start_touch.Assign(1);
63 finger.pressed = true; 62 finger.pressed = true;
63 finger.position = current_touch.position;
64 continue; 64 continue;
65 } 65 }
66 66
67 if (finger.pressed && !current_touch.pressed) { 67 if (finger.pressed && !current_touch.pressed) {
68 finger.attribute.raw = 0; 68 finger.attribute.raw = 0;
69 finger.attribute.end_touch.Assign(1); 69 finger.attribute.end_touch.Assign(1);
70 continue;
70 } 71 }
72
73 // Only update position if touch is not on a special frame
74 finger.position = current_touch.position;
71 } 75 }
72 76
73 std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers; 77 std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers;
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp
index 449a5ac96..eeec34436 100644
--- a/src/core/hle/service/time/time_zone_manager.cpp
+++ b/src/core/hle/service/time/time_zone_manager.cpp
@@ -110,10 +110,9 @@ static constexpr s64 GetLeapDaysFromYear(s64 year) {
110 } 110 }
111} 111}
112 112
113static constexpr int GetMonthLength(bool is_leap_year, int month) { 113static constexpr s8 GetMonthLength(bool is_leap_year, int month) {
114 constexpr std::array<int, 12> month_lengths{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 114 constexpr std::array<s8, 12> month_lengths{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
115 constexpr std::array<int, 12> month_lengths_leap{31, 29, 31, 30, 31, 30, 115 constexpr std::array<s8, 12> month_lengths_leap{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
116 31, 31, 30, 31, 30, 31};
117 return is_leap_year ? month_lengths_leap[month] : month_lengths[month]; 116 return is_leap_year ? month_lengths_leap[month] : month_lengths[month];
118} 117}
119 118
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index a5c63e74a..1a14ef10b 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -434,6 +434,7 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
434 using namespace std::chrono_literals; 434 using namespace std::chrono_literals;
435 while (initialized) { 435 while (initialized) {
436 SDL_PumpEvents(); 436 SDL_PumpEvents();
437 SendVibrations();
437 std::this_thread::sleep_for(1ms); 438 std::this_thread::sleep_for(1ms);
438 } 439 }
439 }); 440 });
@@ -531,13 +532,31 @@ Common::Input::VibrationError SDLDriver::SetRumble(
531 .type = Common::Input::VibrationAmplificationType::Exponential, 532 .type = Common::Input::VibrationAmplificationType::Exponential,
532 }; 533 };
533 534
534 if (!joystick->RumblePlay(new_vibration)) { 535 if (vibration.type == Common::Input::VibrationAmplificationType::Test) {
535 return Common::Input::VibrationError::Unknown; 536 if (!joystick->RumblePlay(new_vibration)) {
537 return Common::Input::VibrationError::Unknown;
538 }
539 return Common::Input::VibrationError::None;
536 } 540 }
537 541
542 vibration_queue.Push(VibrationRequest{
543 .identifier = identifier,
544 .vibration = new_vibration,
545 });
546
538 return Common::Input::VibrationError::None; 547 return Common::Input::VibrationError::None;
539} 548}
540 549
550void SDLDriver::SendVibrations() {
551 while (!vibration_queue.Empty()) {
552 VibrationRequest request;
553 vibration_queue.Pop(request);
554 const auto joystick = GetSDLJoystickByGUID(request.identifier.guid.RawString(),
555 static_cast<int>(request.identifier.port));
556 joystick->RumblePlay(request.vibration);
557 }
558}
559
541Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, 560Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid,
542 s32 axis, float value) const { 561 s32 axis, float value) const {
543 Common::ParamPackage params{}; 562 Common::ParamPackage params{};
diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h
index dcd0d1e64..c82632506 100644
--- a/src/input_common/drivers/sdl_driver.h
+++ b/src/input_common/drivers/sdl_driver.h
@@ -12,6 +12,7 @@
12#include <SDL.h> 12#include <SDL.h>
13 13
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/threadsafe_queue.h"
15#include "input_common/input_engine.h" 16#include "input_common/input_engine.h"
16 17
17union SDL_Event; 18union SDL_Event;
@@ -64,12 +65,20 @@ public:
64 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; 65 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
65 66
66private: 67private:
68 struct VibrationRequest {
69 PadIdentifier identifier;
70 Common::Input::VibrationStatus vibration;
71 };
72
67 void InitJoystick(int joystick_index); 73 void InitJoystick(int joystick_index);
68 void CloseJoystick(SDL_Joystick* sdl_joystick); 74 void CloseJoystick(SDL_Joystick* sdl_joystick);
69 75
70 /// Needs to be called before SDL_QuitSubSystem. 76 /// Needs to be called before SDL_QuitSubSystem.
71 void CloseJoysticks(); 77 void CloseJoysticks();
72 78
79 /// Takes all vibrations from the queue and sends the command to the controller
80 void SendVibrations();
81
73 Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, 82 Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis,
74 float value = 0.1f) const; 83 float value = 0.1f) const;
75 Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, 84 Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid,
@@ -107,6 +116,9 @@ private:
107 /// Returns true if the button is on the left joycon 116 /// Returns true if the button is on the left joycon
108 bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const; 117 bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const;
109 118
119 /// Queue of vibration request to controllers
120 Common::SPSCQueue<VibrationRequest> vibration_queue;
121
110 /// Map of GUID of a list of corresponding virtual Joysticks 122 /// Map of GUID of a list of corresponding virtual Joysticks
111 std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map; 123 std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
112 std::mutex joystick_map_mutex; 124 std::mutex joystick_map_mutex;
diff --git a/src/input_common/drivers/touch_screen.cpp b/src/input_common/drivers/touch_screen.cpp
index 8acbe4584..1753e0893 100644
--- a/src/input_common/drivers/touch_screen.cpp
+++ b/src/input_common/drivers/touch_screen.cpp
@@ -14,38 +14,93 @@ constexpr PadIdentifier identifier = {
14 14
15TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) { 15TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
16 PreSetController(identifier); 16 PreSetController(identifier);
17 ReleaseAllTouch();
17} 18}
18 19
19void TouchScreen::TouchMoved(float x, float y, std::size_t finger) { 20void TouchScreen::TouchMoved(float x, float y, std::size_t finger_id) {
20 if (finger >= 16) { 21 const auto index = GetIndexFromFingerId(finger_id);
22 if (!index) {
23 // Touch doesn't exist handle it as a new one
24 TouchPressed(x, y, finger_id);
21 return; 25 return;
22 } 26 }
23 TouchPressed(x, y, finger); 27 const auto i = index.value();
28 fingers[i].is_active = true;
29 SetButton(identifier, static_cast<int>(i), true);
30 SetAxis(identifier, static_cast<int>(i * 2), x);
31 SetAxis(identifier, static_cast<int>(i * 2 + 1), y);
24} 32}
25 33
26void TouchScreen::TouchPressed(float x, float y, std::size_t finger) { 34void TouchScreen::TouchPressed(float x, float y, std::size_t finger_id) {
27 if (finger >= 16) { 35 if (GetIndexFromFingerId(finger_id)) {
36 // Touch already exist. Just update the data
37 TouchMoved(x, y, finger_id);
28 return; 38 return;
29 } 39 }
30 SetButton(identifier, static_cast<int>(finger), true); 40 const auto index = GetNextFreeIndex();
31 SetAxis(identifier, static_cast<int>(finger * 2), x); 41 if (!index) {
32 SetAxis(identifier, static_cast<int>(finger * 2 + 1), y); 42 // No free entries. Ignore input
43 return;
44 }
45 const auto i = index.value();
46 fingers[i].is_enabled = true;
47 fingers[i].finger_id = finger_id;
48 TouchMoved(x, y, finger_id);
33} 49}
34 50
35void TouchScreen::TouchReleased(std::size_t finger) { 51void TouchScreen::TouchReleased(std::size_t finger_id) {
36 if (finger >= 16) { 52 const auto index = GetIndexFromFingerId(finger_id);
53 if (!index) {
37 return; 54 return;
38 } 55 }
39 SetButton(identifier, static_cast<int>(finger), false); 56 const auto i = index.value();
40 SetAxis(identifier, static_cast<int>(finger * 2), 0.0f); 57 fingers[i].is_enabled = false;
41 SetAxis(identifier, static_cast<int>(finger * 2 + 1), 0.0f); 58 SetButton(identifier, static_cast<int>(i), false);
59 SetAxis(identifier, static_cast<int>(i * 2), 0.0f);
60 SetAxis(identifier, static_cast<int>(i * 2 + 1), 0.0f);
61}
62
63std::optional<std::size_t> TouchScreen::GetIndexFromFingerId(std::size_t finger_id) const {
64 for (std::size_t index = 0; index < MAX_FINGER_COUNT; ++index) {
65 const auto& finger = fingers[index];
66 if (!finger.is_enabled) {
67 continue;
68 }
69 if (finger.finger_id == finger_id) {
70 return index;
71 }
72 }
73 return std::nullopt;
74}
75
76std::optional<std::size_t> TouchScreen::GetNextFreeIndex() const {
77 for (std::size_t index = 0; index < MAX_FINGER_COUNT; ++index) {
78 if (!fingers[index].is_enabled) {
79 return index;
80 }
81 }
82 return std::nullopt;
83}
84
85void TouchScreen::ClearActiveFlag() {
86 for (auto& finger : fingers) {
87 finger.is_active = false;
88 }
89}
90
91void TouchScreen::ReleaseInactiveTouch() {
92 for (const auto& finger : fingers) {
93 if (!finger.is_active) {
94 TouchReleased(finger.finger_id);
95 }
96 }
42} 97}
43 98
44void TouchScreen::ReleaseAllTouch() { 99void TouchScreen::ReleaseAllTouch() {
45 for (int index = 0; index < 16; ++index) { 100 for (const auto& finger : fingers) {
46 SetButton(identifier, index, false); 101 if (finger.is_enabled) {
47 SetAxis(identifier, index * 2, 0.0f); 102 TouchReleased(finger.finger_id);
48 SetAxis(identifier, index * 2 + 1, 0.0f); 103 }
49 } 104 }
50} 105}
51 106
diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h
index 193478ead..f46036ffd 100644
--- a/src/input_common/drivers/touch_screen.h
+++ b/src/input_common/drivers/touch_screen.h
@@ -3,41 +3,65 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <optional>
7
6#include "input_common/input_engine.h" 8#include "input_common/input_engine.h"
7 9
8namespace InputCommon { 10namespace InputCommon {
9 11
10/** 12/**
11 * A button device factory representing a keyboard. It receives keyboard events and forward them 13 * A touch device factory representing a touch screen. It receives touch events and forward them
12 * to all button devices it created. 14 * to all touch devices it created.
13 */ 15 */
14class TouchScreen final : public InputEngine { 16class TouchScreen final : public InputEngine {
15public: 17public:
16 explicit TouchScreen(std::string input_engine_); 18 explicit TouchScreen(std::string input_engine_);
17 19
18 /** 20 /**
19 * Signals that mouse has moved. 21 * Signals that touch has moved and marks this touch point as active
20 * @param x the x-coordinate of the cursor 22 * @param x new horizontal position
21 * @param y the y-coordinate of the cursor 23 * @param y new vertical position
22 * @param center_x the x-coordinate of the middle of the screen 24 * @param finger_id of the touch point to be updated
23 * @param center_y the y-coordinate of the middle of the screen
24 */ 25 */
25 void TouchMoved(float x, float y, std::size_t finger); 26 void TouchMoved(float x, float y, std::size_t finger_id);
26 27
27 /** 28 /**
28 * Sets the status of all buttons bound with the key to pressed 29 * Signals and creates a new touch point with this finger id
29 * @param key_code the code of the key to press 30 * @param x starting horizontal position
31 * @param y starting vertical position
32 * @param finger_id to be assigned to the new touch point
30 */ 33 */
31 void TouchPressed(float x, float y, std::size_t finger); 34 void TouchPressed(float x, float y, std::size_t finger_id);
32 35
33 /** 36 /**
34 * Sets the status of all buttons bound with the key to released 37 * Signals and resets the touch point related to the this finger id
35 * @param key_code the code of the key to release 38 * @param finger_id to be released
36 */ 39 */
37 void TouchReleased(std::size_t finger); 40 void TouchReleased(std::size_t finger_id);
41
42 /// Resets the active flag for each touch point
43 void ClearActiveFlag();
44
45 /// Releases all touch that haven't been marked as active
46 void ReleaseInactiveTouch();
38 47
39 /// Resets all inputs to their initial value 48 /// Resets all inputs to their initial value
40 void ReleaseAllTouch(); 49 void ReleaseAllTouch();
50
51private:
52 static constexpr std::size_t MAX_FINGER_COUNT = 16;
53
54 struct TouchStatus {
55 std::size_t finger_id{};
56 bool is_enabled{};
57 bool is_active{};
58 };
59
60 std::optional<std::size_t> GetIndexFromFingerId(std::size_t finger_id) const;
61
62 std::optional<std::size_t> GetNextFreeIndex() const;
63
64 std::array<TouchStatus, MAX_FINGER_COUNT> fingers{};
41}; 65};
42 66
43} // namespace InputCommon 67} // namespace InputCommon
diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp
index a95618913..c01431441 100644
--- a/src/video_core/command_classes/codecs/vp9.cpp
+++ b/src/video_core/command_classes/codecs/vp9.cpp
@@ -153,7 +153,7 @@ constexpr Vp9EntropyProbs default_probs{
153 .high_precision{128, 128}, 153 .high_precision{128, 128},
154}; 154};
155 155
156constexpr std::array<s32, 256> norm_lut{ 156constexpr std::array<u8, 256> norm_lut{
157 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 157 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
158 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 158 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
159 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 159 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -164,7 +164,7 @@ constexpr std::array<s32, 256> norm_lut{
164 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
165}; 165};
166 166
167constexpr std::array<s32, 254> map_lut{ 167constexpr std::array<u8, 254> map_lut{
168 20, 21, 22, 23, 24, 25, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 168 20, 21, 22, 23, 24, 25, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
169 1, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 2, 50, 51, 52, 53, 54, 169 1, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 2, 50, 51, 52, 53, 54,
170 55, 56, 57, 58, 59, 60, 61, 3, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 170 55, 56, 57, 58, 59, 60, 61, 3, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
@@ -232,7 +232,7 @@ constexpr std::array<s32, 254> map_lut{
232 std::max(0, RecenterNonNeg(0xff - 1 - new_prob, 0xff - 1 - old_prob) - 1)); 232 std::max(0, RecenterNonNeg(0xff - 1 - new_prob, 0xff - 1 - old_prob) - 1));
233 } 233 }
234 234
235 return map_lut[index]; 235 return static_cast<s32>(map_lut[index]);
236} 236}
237} // Anonymous namespace 237} // Anonymous namespace
238 238
@@ -819,7 +819,7 @@ void VpxRangeEncoder::Write(bool bit, s32 probability) {
819 local_range = range - split; 819 local_range = range - split;
820 } 820 }
821 821
822 s32 shift = norm_lut[local_range]; 822 s32 shift = static_cast<s32>(norm_lut[local_range]);
823 local_range <<= shift; 823 local_range <<= shift;
824 count += shift; 824 count += shift;
825 825
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index fd27581ce..ce6c853c1 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -784,8 +784,8 @@ void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs)
784 }); 784 });
785 } else { 785 } else {
786 // Front face defines both faces 786 // Front face defines both faces
787 scheduler.Record([ref = regs.stencil_back_func_ref, write_mask = regs.stencil_back_mask, 787 scheduler.Record([ref = regs.stencil_front_func_ref, write_mask = regs.stencil_front_mask,
788 test_mask = regs.stencil_back_func_mask](vk::CommandBuffer cmdbuf) { 788 test_mask = regs.stencil_front_func_mask](vk::CommandBuffer cmdbuf) {
789 cmdbuf.SetStencilReference(VK_STENCIL_FACE_FRONT_AND_BACK, ref); 789 cmdbuf.SetStencilReference(VK_STENCIL_FACE_FRONT_AND_BACK, ref);
790 cmdbuf.SetStencilWriteMask(VK_STENCIL_FACE_FRONT_AND_BACK, write_mask); 790 cmdbuf.SetStencilWriteMask(VK_STENCIL_FACE_FRONT_AND_BACK, write_mask);
791 cmdbuf.SetStencilCompareMask(VK_STENCIL_FACE_FRONT_AND_BACK, test_mask); 791 cmdbuf.SetStencilCompareMask(VK_STENCIL_FACE_FRONT_AND_BACK, test_mask);
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 86fea61ae..75e055592 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -147,7 +147,7 @@ enum class SurfaceTarget {
147 TextureCubeArray, 147 TextureCubeArray,
148}; 148};
149 149
150constexpr std::array<u32, MaxPixelFormat> BLOCK_WIDTH_TABLE = {{ 150constexpr std::array<u8, MaxPixelFormat> BLOCK_WIDTH_TABLE = {{
151 1, // A8B8G8R8_UNORM 151 1, // A8B8G8R8_UNORM
152 1, // A8B8G8R8_SNORM 152 1, // A8B8G8R8_SNORM
153 1, // A8B8G8R8_SINT 153 1, // A8B8G8R8_SINT
@@ -249,7 +249,7 @@ constexpr u32 DefaultBlockWidth(PixelFormat format) {
249 return BLOCK_WIDTH_TABLE[static_cast<std::size_t>(format)]; 249 return BLOCK_WIDTH_TABLE[static_cast<std::size_t>(format)];
250} 250}
251 251
252constexpr std::array<u32, MaxPixelFormat> BLOCK_HEIGHT_TABLE = {{ 252constexpr std::array<u8, MaxPixelFormat> BLOCK_HEIGHT_TABLE = {{
253 1, // A8B8G8R8_UNORM 253 1, // A8B8G8R8_UNORM
254 1, // A8B8G8R8_SNORM 254 1, // A8B8G8R8_SNORM
255 1, // A8B8G8R8_SINT 255 1, // A8B8G8R8_SINT
@@ -351,7 +351,7 @@ constexpr u32 DefaultBlockHeight(PixelFormat format) {
351 return BLOCK_HEIGHT_TABLE[static_cast<std::size_t>(format)]; 351 return BLOCK_HEIGHT_TABLE[static_cast<std::size_t>(format)];
352} 352}
353 353
354constexpr std::array<u32, MaxPixelFormat> BITS_PER_BLOCK_TABLE = {{ 354constexpr std::array<u8, MaxPixelFormat> BITS_PER_BLOCK_TABLE = {{
355 32, // A8B8G8R8_UNORM 355 32, // A8B8G8R8_UNORM
356 32, // A8B8G8R8_SNORM 356 32, // A8B8G8R8_SNORM
357 32, // A8B8G8R8_SINT 357 32, // A8B8G8R8_SINT
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 7b2ca8046..b3a77e07f 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -566,7 +566,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
566 } 566 }
567 567
568 VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR workgroup_layout; 568 VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR workgroup_layout;
569 if (khr_workgroup_memory_explicit_layout) { 569 if (khr_workgroup_memory_explicit_layout && is_shader_int16_supported) {
570 workgroup_layout = { 570 workgroup_layout = {
571 .sType = 571 .sType =
572 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR, 572 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR,
@@ -577,6 +577,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
577 .workgroupMemoryExplicitLayout16BitAccess = VK_TRUE, 577 .workgroupMemoryExplicitLayout16BitAccess = VK_TRUE,
578 }; 578 };
579 SetNext(next, workgroup_layout); 579 SetNext(next, workgroup_layout);
580 } else if (khr_workgroup_memory_explicit_layout) {
581 // TODO(lat9nq): Find a proper fix for this
582 LOG_WARNING(Render_Vulkan, "Disabling VK_KHR_workgroup_memory_explicit_layout due to a "
583 "yuzu bug when host driver does not support 16-bit integers");
584 khr_workgroup_memory_explicit_layout = false;
580 } 585 }
581 586
582 VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR executable_properties; 587 VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR executable_properties;
@@ -664,6 +669,17 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
664 const bool is_amd = 669 const bool is_amd =
665 driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE; 670 driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE;
666 if (is_amd) { 671 if (is_amd) {
672 // TODO(lat9nq): Add an upper bound when AMD fixes their VK_KHR_push_descriptor
673 const bool has_broken_push_descriptor = VK_VERSION_MAJOR(properties.driverVersion) == 2 &&
674 VK_VERSION_MINOR(properties.driverVersion) == 0 &&
675 VK_VERSION_PATCH(properties.driverVersion) >= 226;
676 if (khr_push_descriptor && has_broken_push_descriptor) {
677 LOG_WARNING(
678 Render_Vulkan,
679 "Disabling AMD driver 2.0.226 and later from broken VK_KHR_push_descriptor");
680 khr_push_descriptor = false;
681 }
682
667 // AMD drivers need a higher amount of Sets per Pool in certain circunstances like in XC2. 683 // AMD drivers need a higher amount of Sets per Pool in certain circunstances like in XC2.
668 sets_per_pool = 96; 684 sets_per_pool = 96;
669 // Disable VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT on AMD GCN4 and lower as it is broken. 685 // Disable VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT on AMD GCN4 and lower as it is broken.
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 2ee21f751..404acdd05 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -240,7 +240,7 @@ elseif(WIN32)
240 if(MSVC) 240 if(MSVC)
241 set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") 241 set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
242 elseif(MINGW) 242 elseif(MINGW)
243 set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "-mwindows") 243 set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "-Wl,--subsystem,windows")
244 endif() 244 endif()
245endif() 245endif()
246 246
diff --git a/src/yuzu/about_dialog.cpp b/src/yuzu/about_dialog.cpp
index cbcef7b45..eeff54359 100644
--- a/src/yuzu/about_dialog.cpp
+++ b/src/yuzu/about_dialog.cpp
@@ -19,7 +19,11 @@ AboutDialog::AboutDialog(QWidget* parent)
19 const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build; 19 const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build;
20 20
21 ui->setupUi(this); 21 ui->setupUi(this);
22 ui->labelLogo->setPixmap(QIcon::fromTheme(QStringLiteral("yuzu")).pixmap(200)); 22 // Try and request the icon from Qt theme (Linux?)
23 const QIcon yuzu_logo = QIcon::fromTheme(QStringLiteral("org.yuzu_emu.yuzu"));
24 if (!yuzu_logo.isNull()) {
25 ui->labelLogo->setPixmap(yuzu_logo.pixmap(200));
26 }
23 ui->labelBuildInfo->setText( 27 ui->labelBuildInfo->setText(
24 ui->labelBuildInfo->text().arg(QString::fromStdString(yuzu_build_version), 28 ui->labelBuildInfo->text().arg(QString::fromStdString(yuzu_build_version),
25 QString::fromUtf8(Common::g_build_date).left(10))); 29 QString::fromUtf8(Common::g_build_date).left(10)));
diff --git a/src/yuzu/aboutdialog.ui b/src/yuzu/aboutdialog.ui
index 2f7ddc7f3..1dd7b74bf 100644
--- a/src/yuzu/aboutdialog.ui
+++ b/src/yuzu/aboutdialog.ui
@@ -26,8 +26,20 @@
26 <verstretch>0</verstretch> 26 <verstretch>0</verstretch>
27 </sizepolicy> 27 </sizepolicy>
28 </property> 28 </property>
29 <property name="maximumSize">
30 <size>
31 <width>200</width>
32 <height>200</height>
33 </size>
34 </property>
29 <property name="text"> 35 <property name="text">
30 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/yuzu.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 36 <string/>
37 </property>
38 <property name="pixmap">
39 <pixmap resource="../../dist/qt_themes/default/default.qrc">:/icons/default/256x256/yuzu.png</pixmap>
40 </property>
41 <property name="scaledContents">
42 <bool>true</bool>
31 </property> 43 </property>
32 </widget> 44 </widget>
33 </item> 45 </item>
@@ -152,7 +164,7 @@ p, li { white-space: pre-wrap; }
152 </layout> 164 </layout>
153 </widget> 165 </widget>
154 <resources> 166 <resources>
155 <include location="../../dist/icons/icons.qrc"/> 167 <include location="../../dist/qt_themes_default/default/default.qrc"/>
156 </resources> 168 </resources>
157 <connections> 169 <connections>
158 <connection> 170 <connection>
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index a1b819ae0..8f0a6bbb8 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -772,65 +772,25 @@ void GRenderWindow::wheelEvent(QWheelEvent* event) {
772void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { 772void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) {
773 QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints(); 773 QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints();
774 for (const auto& touch_point : touch_points) { 774 for (const auto& touch_point : touch_points) {
775 if (!TouchUpdate(touch_point)) { 775 const auto [x, y] = ScaleTouch(touch_point.pos());
776 TouchStart(touch_point); 776 const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
777 } 777 input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, touch_point.id());
778 } 778 }
779} 779}
780 780
781void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) { 781void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) {
782 QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints(); 782 QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints();
783 input_subsystem->GetTouchScreen()->ClearActiveFlag();
783 for (const auto& touch_point : touch_points) { 784 for (const auto& touch_point : touch_points) {
784 if (!TouchUpdate(touch_point)) { 785 const auto [x, y] = ScaleTouch(touch_point.pos());
785 TouchStart(touch_point); 786 const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
786 } 787 input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, touch_point.id());
787 }
788 // Release all inactive points
789 for (std::size_t id = 0; id < touch_ids.size(); ++id) {
790 if (!TouchExist(touch_ids[id], touch_points)) {
791 touch_ids[id] = 0;
792 input_subsystem->GetTouchScreen()->TouchReleased(id);
793 }
794 } 788 }
789 input_subsystem->GetTouchScreen()->ReleaseInactiveTouch();
795} 790}
796 791
797void GRenderWindow::TouchEndEvent() { 792void GRenderWindow::TouchEndEvent() {
798 for (std::size_t id = 0; id < touch_ids.size(); ++id) { 793 input_subsystem->GetTouchScreen()->ReleaseAllTouch();
799 if (touch_ids[id] != 0) {
800 touch_ids[id] = 0;
801 input_subsystem->GetTouchScreen()->TouchReleased(id);
802 }
803 }
804}
805
806void GRenderWindow::TouchStart(const QTouchEvent::TouchPoint& touch_point) {
807 for (std::size_t id = 0; id < touch_ids.size(); ++id) {
808 if (touch_ids[id] == 0) {
809 touch_ids[id] = touch_point.id() + 1;
810 const auto [x, y] = ScaleTouch(touch_point.pos());
811 const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
812 input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, id);
813 }
814 }
815}
816
817bool GRenderWindow::TouchUpdate(const QTouchEvent::TouchPoint& touch_point) {
818 for (std::size_t id = 0; id < touch_ids.size(); ++id) {
819 if (touch_ids[id] == static_cast<std::size_t>(touch_point.id() + 1)) {
820 const auto [x, y] = ScaleTouch(touch_point.pos());
821 const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
822 input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, id);
823 return true;
824 }
825 }
826 return false;
827}
828
829bool GRenderWindow::TouchExist(std::size_t id,
830 const QList<QTouchEvent::TouchPoint>& touch_points) const {
831 return std::any_of(touch_points.begin(), touch_points.end(), [id](const auto& point) {
832 return id == static_cast<std::size_t>(point.id() + 1);
833 });
834} 794}
835 795
836bool GRenderWindow::event(QEvent* event) { 796bool GRenderWindow::event(QEvent* event) {
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index 4b0ce0293..841816564 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -217,10 +217,6 @@ private:
217 void TouchUpdateEvent(const QTouchEvent* event); 217 void TouchUpdateEvent(const QTouchEvent* event);
218 void TouchEndEvent(); 218 void TouchEndEvent();
219 219
220 void TouchStart(const QTouchEvent::TouchPoint& touch_point);
221 bool TouchUpdate(const QTouchEvent::TouchPoint& touch_point);
222 bool TouchExist(std::size_t id, const QList<QTouchEvent::TouchPoint>& touch_points) const;
223
224 void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override; 220 void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
225 221
226 bool InitializeOpenGL(); 222 bool InitializeOpenGL();
@@ -246,8 +242,6 @@ private:
246 bool first_frame = false; 242 bool first_frame = false;
247 InputCommon::TasInput::TasState last_tas_state; 243 InputCommon::TasInput::TasState last_tas_state;
248 244
249 std::array<std::size_t, 16> touch_ids{};
250
251 Core::System& system; 245 Core::System& system;
252 246
253protected: 247protected:
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index ae2e62dc5..71c413e64 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -93,7 +93,7 @@ void EmuWindow_SDL2::OnFingerMotion(float x, float y, std::size_t id) {
93} 93}
94 94
95void EmuWindow_SDL2::OnFingerUp() { 95void EmuWindow_SDL2::OnFingerUp() {
96 input_subsystem->GetTouchScreen()->TouchReleased(0); 96 input_subsystem->GetTouchScreen()->ReleaseAllTouch();
97} 97}
98 98
99void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { 99void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {