diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/hid/controllers/gesture.cpp | 347 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/gesture.h | 69 | ||||
| -rw-r--r-- | src/core/hle/service/ssl/ssl.cpp | 42 | ||||
| -rw-r--r-- | src/input_common/main.cpp | 5 | ||||
| -rw-r--r-- | src/input_common/sdl/sdl.h | 3 | ||||
| -rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 153 | ||||
| -rw-r--r-- | src/input_common/sdl/sdl_impl.h | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.cpp | 9 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.h | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/blit_image.cpp | 26 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/blit_image.h | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.cpp | 38 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.h | 5 | ||||
| -rw-r--r-- | src/video_core/texture_cache/texture_cache.h | 57 | ||||
| -rw-r--r-- | src/video_core/texture_cache/types.h | 7 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input_player.cpp | 8 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_ui.cpp | 1 |
17 files changed, 647 insertions, 142 deletions
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index bb77d8959..9e5df3bb7 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp | |||
| @@ -1,10 +1,9 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | 1 | // Copyright 2021 yuzu Emulator Project |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cstring> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "common/math_util.h" | ||
| 8 | #include "common/settings.h" | 7 | #include "common/settings.h" |
| 9 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| 10 | #include "core/frontend/emu_window.h" | 9 | #include "core/frontend/emu_window.h" |
| @@ -12,10 +11,19 @@ | |||
| 12 | 11 | ||
| 13 | namespace Service::HID { | 12 | namespace Service::HID { |
| 14 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; | 13 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; |
| 15 | constexpr f32 angle_threshold = 0.08f; | ||
| 16 | constexpr f32 pinch_threshold = 100.0f; | ||
| 17 | 14 | ||
| 18 | Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase{system_} {} | 15 | // HW is around 700, value is set to 400 to make it easier to trigger with mouse |
| 16 | constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s | ||
| 17 | constexpr f32 angle_threshold = 0.015f; // Threshold in radians | ||
| 18 | constexpr f32 pinch_threshold = 0.5f; // Threshold in pixels | ||
| 19 | constexpr f32 press_delay = 0.5f; // Time in seconds | ||
| 20 | constexpr f32 double_tap_delay = 0.35f; // Time in seconds | ||
| 21 | |||
| 22 | constexpr f32 Square(s32 num) { | ||
| 23 | return static_cast<f32>(num * num); | ||
| 24 | } | ||
| 25 | |||
| 26 | Controller_Gesture::Controller_Gesture(Core::System& system) : ControllerBase(system) {} | ||
| 19 | Controller_Gesture::~Controller_Gesture() = default; | 27 | Controller_Gesture::~Controller_Gesture() = default; |
| 20 | 28 | ||
| 21 | void Controller_Gesture::OnInit() { | 29 | void Controller_Gesture::OnInit() { |
| @@ -24,6 +32,8 @@ void Controller_Gesture::OnInit() { | |||
| 24 | keyboard_finger_id[id] = MAX_POINTS; | 32 | keyboard_finger_id[id] = MAX_POINTS; |
| 25 | udp_finger_id[id] = MAX_POINTS; | 33 | udp_finger_id[id] = MAX_POINTS; |
| 26 | } | 34 | } |
| 35 | shared_memory.header.entry_count = 0; | ||
| 36 | force_update = true; | ||
| 27 | } | 37 | } |
| 28 | 38 | ||
| 29 | void Controller_Gesture::OnRelease() {} | 39 | void Controller_Gesture::OnRelease() {} |
| @@ -38,17 +48,23 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u | |||
| 38 | shared_memory.header.last_entry_index = 0; | 48 | shared_memory.header.last_entry_index = 0; |
| 39 | return; | 49 | return; |
| 40 | } | 50 | } |
| 41 | shared_memory.header.entry_count = 16; | ||
| 42 | 51 | ||
| 43 | const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | 52 | ReadTouchInput(); |
| 44 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | ||
| 45 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 46 | 53 | ||
| 47 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 54 | GestureProperties gesture = GetGestureProperties(); |
| 48 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 55 | f32 time_difference = static_cast<f32>(shared_memory.header.timestamp - last_update_timestamp) / |
| 56 | (1000 * 1000 * 1000); | ||
| 49 | 57 | ||
| 50 | // TODO(german77): Implement all gesture types | 58 | // Only update if necesary |
| 59 | if (!ShouldUpdateGesture(gesture, time_difference)) { | ||
| 60 | return; | ||
| 61 | } | ||
| 51 | 62 | ||
| 63 | last_update_timestamp = shared_memory.header.timestamp; | ||
| 64 | UpdateGestureSharedMemory(data, size, gesture, time_difference); | ||
| 65 | } | ||
| 66 | |||
| 67 | void Controller_Gesture::ReadTouchInput() { | ||
| 52 | const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); | 68 | const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); |
| 53 | const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); | 69 | const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); |
| 54 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { | 70 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { |
| @@ -63,50 +79,71 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u | |||
| 63 | UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); | 79 | UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); |
| 64 | } | 80 | } |
| 65 | } | 81 | } |
| 82 | } | ||
| 66 | 83 | ||
| 67 | TouchType type = TouchType::Idle; | 84 | bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, |
| 68 | Attribute attributes{}; | 85 | f32 time_difference) { |
| 69 | GestureProperties gesture = GetGestureProperties(); | 86 | const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; |
| 70 | if (last_gesture.active_points != gesture.active_points) { | 87 | if (force_update) { |
| 71 | ++last_gesture.detection_count; | 88 | force_update = false; |
| 89 | return true; | ||
| 72 | } | 90 | } |
| 73 | if (gesture.active_points > 0) { | ||
| 74 | if (last_gesture.active_points == 0) { | ||
| 75 | attributes.is_new_touch.Assign(true); | ||
| 76 | last_gesture.average_distance = gesture.average_distance; | ||
| 77 | last_gesture.angle = gesture.angle; | ||
| 78 | } | ||
| 79 | 91 | ||
| 80 | type = TouchType::Touch; | 92 | // Update if coordinates change |
| 81 | if (gesture.mid_point.x != last_entry.x || gesture.mid_point.y != last_entry.y) { | 93 | for (size_t id = 0; id < MAX_POINTS; id++) { |
| 82 | type = TouchType::Pan; | 94 | if (gesture.points[id].x != last_gesture.points[id].x || |
| 83 | } | 95 | gesture.points[id].y != last_gesture.points[id].y) { |
| 84 | if (std::abs(gesture.average_distance - last_gesture.average_distance) > pinch_threshold) { | 96 | return true; |
| 85 | type = TouchType::Pinch; | ||
| 86 | } | ||
| 87 | if (std::abs(gesture.angle - last_gesture.angle) > angle_threshold) { | ||
| 88 | type = TouchType::Rotate; | ||
| 89 | } | 97 | } |
| 98 | } | ||
| 99 | |||
| 100 | // Update on press and hold event after 0.5 seconds | ||
| 101 | if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 && | ||
| 102 | time_difference > press_delay) { | ||
| 103 | return enable_press_and_tap; | ||
| 104 | } | ||
| 105 | |||
| 106 | return false; | ||
| 107 | } | ||
| 108 | |||
| 109 | void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, | ||
| 110 | GestureProperties& gesture, | ||
| 111 | f32 time_difference) { | ||
| 112 | TouchType type = TouchType::Idle; | ||
| 113 | Attribute attributes{}; | ||
| 114 | |||
| 115 | const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 116 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | ||
| 117 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 90 | 118 | ||
| 91 | cur_entry.delta_x = gesture.mid_point.x - last_entry.x; | 119 | if (shared_memory.header.entry_count < 16) { |
| 92 | cur_entry.delta_y = gesture.mid_point.y - last_entry.y; | 120 | shared_memory.header.entry_count++; |
| 93 | // TODO: Find how velocities are calculated | 121 | } |
| 94 | cur_entry.vel_x = static_cast<float>(cur_entry.delta_x) * 150.1f; | ||
| 95 | cur_entry.vel_y = static_cast<float>(cur_entry.delta_y) * 150.1f; | ||
| 96 | 122 | ||
| 97 | // Slowdown the rate of change for less flapping | 123 | cur_entry.sampling_number = last_entry.sampling_number + 1; |
| 98 | last_gesture.average_distance = | 124 | cur_entry.sampling_number2 = cur_entry.sampling_number; |
| 99 | (last_gesture.average_distance * 0.9f) + (gesture.average_distance * 0.1f); | ||
| 100 | last_gesture.angle = (last_gesture.angle * 0.9f) + (gesture.angle * 0.1f); | ||
| 101 | 125 | ||
| 126 | // Reset values to default | ||
| 127 | cur_entry.delta_x = 0; | ||
| 128 | cur_entry.delta_y = 0; | ||
| 129 | cur_entry.vel_x = 0; | ||
| 130 | cur_entry.vel_y = 0; | ||
| 131 | cur_entry.direction = Direction::None; | ||
| 132 | cur_entry.rotation_angle = 0; | ||
| 133 | cur_entry.scale = 0; | ||
| 134 | |||
| 135 | if (gesture.active_points > 0) { | ||
| 136 | if (last_gesture.active_points == 0) { | ||
| 137 | NewGesture(gesture, type, attributes); | ||
| 138 | } else { | ||
| 139 | UpdateExistingGesture(gesture, type, time_difference); | ||
| 140 | } | ||
| 102 | } else { | 141 | } else { |
| 103 | cur_entry.delta_x = 0; | 142 | EndGesture(gesture, last_gesture, type, attributes, time_difference); |
| 104 | cur_entry.delta_y = 0; | ||
| 105 | cur_entry.vel_x = 0; | ||
| 106 | cur_entry.vel_y = 0; | ||
| 107 | } | 143 | } |
| 108 | last_gesture.active_points = gesture.active_points; | 144 | |
| 109 | cur_entry.detection_count = last_gesture.detection_count; | 145 | // Apply attributes |
| 146 | cur_entry.detection_count = gesture.detection_count; | ||
| 110 | cur_entry.type = type; | 147 | cur_entry.type = type; |
| 111 | cur_entry.attributes = attributes; | 148 | cur_entry.attributes = attributes; |
| 112 | cur_entry.x = gesture.mid_point.x; | 149 | cur_entry.x = gesture.mid_point.x; |
| @@ -116,12 +153,190 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u | |||
| 116 | cur_entry.points[id].x = gesture.points[id].x; | 153 | cur_entry.points[id].x = gesture.points[id].x; |
| 117 | cur_entry.points[id].y = gesture.points[id].y; | 154 | cur_entry.points[id].y = gesture.points[id].y; |
| 118 | } | 155 | } |
| 119 | cur_entry.rotation_angle = 0; | 156 | last_gesture = gesture; |
| 120 | cur_entry.scale = 0; | ||
| 121 | 157 | ||
| 122 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | 158 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); |
| 123 | } | 159 | } |
| 124 | 160 | ||
| 161 | void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type, | ||
| 162 | Attribute& attributes) { | ||
| 163 | const auto& last_entry = | ||
| 164 | shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 165 | gesture.detection_count++; | ||
| 166 | type = TouchType::Touch; | ||
| 167 | |||
| 168 | // New touch after cancel is not considered new | ||
| 169 | if (last_entry.type != TouchType::Cancel) { | ||
| 170 | attributes.is_new_touch.Assign(1); | ||
| 171 | enable_press_and_tap = true; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type, | ||
| 176 | f32 time_difference) { | ||
| 177 | const auto& last_entry = | ||
| 178 | shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 179 | |||
| 180 | // Promote to pan type if touch moved | ||
| 181 | for (size_t id = 0; id < MAX_POINTS; id++) { | ||
| 182 | if (gesture.points[id].x != last_gesture.points[id].x || | ||
| 183 | gesture.points[id].y != last_gesture.points[id].y) { | ||
| 184 | type = TouchType::Pan; | ||
| 185 | break; | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | // Number of fingers changed cancel the last event and clear data | ||
| 190 | if (gesture.active_points != last_gesture.active_points) { | ||
| 191 | type = TouchType::Cancel; | ||
| 192 | enable_press_and_tap = false; | ||
| 193 | gesture.active_points = 0; | ||
| 194 | gesture.mid_point = {}; | ||
| 195 | for (size_t id = 0; id < MAX_POINTS; id++) { | ||
| 196 | gesture.points[id].x = 0; | ||
| 197 | gesture.points[id].y = 0; | ||
| 198 | } | ||
| 199 | return; | ||
| 200 | } | ||
| 201 | |||
| 202 | // Calculate extra parameters of panning | ||
| 203 | if (type == TouchType::Pan) { | ||
| 204 | UpdatePanEvent(gesture, last_gesture, type, time_difference); | ||
| 205 | return; | ||
| 206 | } | ||
| 207 | |||
| 208 | // Promote to press type | ||
| 209 | if (last_entry.type == TouchType::Touch) { | ||
| 210 | type = TouchType::Press; | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | void Controller_Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 215 | TouchType& type, Attribute& attributes, f32 time_difference) { | ||
| 216 | const auto& last_entry = | ||
| 217 | shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 218 | if (last_gesture.active_points != 0) { | ||
| 219 | switch (last_entry.type) { | ||
| 220 | case TouchType::Touch: | ||
| 221 | if (enable_press_and_tap) { | ||
| 222 | SetTapEvent(gesture, last_gesture, type, attributes); | ||
| 223 | return; | ||
| 224 | } | ||
| 225 | type = TouchType::Cancel; | ||
| 226 | force_update = true; | ||
| 227 | break; | ||
| 228 | case TouchType::Press: | ||
| 229 | case TouchType::Tap: | ||
| 230 | case TouchType::Swipe: | ||
| 231 | case TouchType::Pinch: | ||
| 232 | case TouchType::Rotate: | ||
| 233 | type = TouchType::Complete; | ||
| 234 | force_update = true; | ||
| 235 | break; | ||
| 236 | case TouchType::Pan: | ||
| 237 | EndPanEvent(gesture, last_gesture, type, time_difference); | ||
| 238 | break; | ||
| 239 | default: | ||
| 240 | break; | ||
| 241 | } | ||
| 242 | return; | ||
| 243 | } | ||
| 244 | if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) { | ||
| 245 | gesture.detection_count++; | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | void Controller_Gesture::SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 250 | TouchType& type, Attribute& attributes) { | ||
| 251 | type = TouchType::Tap; | ||
| 252 | gesture = last_gesture; | ||
| 253 | force_update = true; | ||
| 254 | f32 tap_time_difference = | ||
| 255 | static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000); | ||
| 256 | last_tap_timestamp = last_update_timestamp; | ||
| 257 | if (tap_time_difference < double_tap_delay) { | ||
| 258 | attributes.is_double_tap.Assign(1); | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 263 | TouchType& type, f32 time_difference) { | ||
| 264 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 265 | const auto& last_entry = | ||
| 266 | shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 267 | cur_entry.delta_x = gesture.mid_point.x - last_entry.x; | ||
| 268 | cur_entry.delta_y = gesture.mid_point.y - last_entry.y; | ||
| 269 | |||
| 270 | cur_entry.vel_x = static_cast<f32>(cur_entry.delta_x) / time_difference; | ||
| 271 | cur_entry.vel_y = static_cast<f32>(cur_entry.delta_y) / time_difference; | ||
| 272 | last_pan_time_difference = time_difference; | ||
| 273 | |||
| 274 | // Promote to pinch type | ||
| 275 | if (std::abs(gesture.average_distance - last_gesture.average_distance) > pinch_threshold) { | ||
| 276 | type = TouchType::Pinch; | ||
| 277 | cur_entry.scale = gesture.average_distance / last_gesture.average_distance; | ||
| 278 | } | ||
| 279 | |||
| 280 | const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture.angle) / | ||
| 281 | (1 + (gesture.angle * last_gesture.angle))); | ||
| 282 | // Promote to rotate type | ||
| 283 | if (std::abs(angle_between_two_lines) > angle_threshold) { | ||
| 284 | type = TouchType::Rotate; | ||
| 285 | cur_entry.scale = 0; | ||
| 286 | cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | void Controller_Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 291 | TouchType& type, f32 time_difference) { | ||
| 292 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 293 | const auto& last_entry = | ||
| 294 | shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 295 | cur_entry.vel_x = | ||
| 296 | static_cast<f32>(last_entry.delta_x) / (last_pan_time_difference + time_difference); | ||
| 297 | cur_entry.vel_y = | ||
| 298 | static_cast<f32>(last_entry.delta_y) / (last_pan_time_difference + time_difference); | ||
| 299 | const f32 curr_vel = | ||
| 300 | std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y)); | ||
| 301 | |||
| 302 | // Set swipe event with parameters | ||
| 303 | if (curr_vel > swipe_threshold) { | ||
| 304 | SetSwipeEvent(gesture, last_gesture, type); | ||
| 305 | return; | ||
| 306 | } | ||
| 307 | |||
| 308 | // End panning without swipe | ||
| 309 | type = TouchType::Complete; | ||
| 310 | cur_entry.vel_x = 0; | ||
| 311 | cur_entry.vel_y = 0; | ||
| 312 | force_update = true; | ||
| 313 | } | ||
| 314 | |||
| 315 | void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 316 | TouchType& type) { | ||
| 317 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 318 | const auto& last_entry = | ||
| 319 | shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 320 | type = TouchType::Swipe; | ||
| 321 | gesture = last_gesture; | ||
| 322 | force_update = true; | ||
| 323 | cur_entry.delta_x = last_entry.delta_x; | ||
| 324 | cur_entry.delta_y = last_entry.delta_y; | ||
| 325 | if (std::abs(cur_entry.delta_x) > std::abs(cur_entry.delta_y)) { | ||
| 326 | if (cur_entry.delta_x > 0) { | ||
| 327 | cur_entry.direction = Direction::Right; | ||
| 328 | return; | ||
| 329 | } | ||
| 330 | cur_entry.direction = Direction::Left; | ||
| 331 | return; | ||
| 332 | } | ||
| 333 | if (cur_entry.delta_y > 0) { | ||
| 334 | cur_entry.direction = Direction::Down; | ||
| 335 | return; | ||
| 336 | } | ||
| 337 | cur_entry.direction = Direction::Up; | ||
| 338 | } | ||
| 339 | |||
| 125 | void Controller_Gesture::OnLoadInputDevices() { | 340 | void Controller_Gesture::OnLoadInputDevices() { |
| 126 | touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); | 341 | touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); |
| 127 | touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); | 342 | touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); |
| @@ -183,23 +398,33 @@ Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() | |||
| 183 | 398 | ||
| 184 | for (size_t id = 0; id < gesture.active_points; ++id) { | 399 | for (size_t id = 0; id < gesture.active_points; ++id) { |
| 185 | gesture.points[id].x = | 400 | gesture.points[id].x = |
| 186 | static_cast<int>(active_fingers[id].x * Layout::ScreenUndocked::Width); | 401 | static_cast<s32>(active_fingers[id].x * Layout::ScreenUndocked::Width); |
| 187 | gesture.points[id].y = | 402 | gesture.points[id].y = |
| 188 | static_cast<int>(active_fingers[id].y * Layout::ScreenUndocked::Height); | 403 | static_cast<s32>(active_fingers[id].y * Layout::ScreenUndocked::Height); |
| 189 | gesture.mid_point.x += static_cast<int>(gesture.points[id].x / gesture.active_points); | 404 | |
| 190 | gesture.mid_point.y += static_cast<int>(gesture.points[id].y / gesture.active_points); | 405 | // Hack: There is no touch in docked but games still allow it |
| 406 | if (Settings::values.use_docked_mode.GetValue()) { | ||
| 407 | gesture.points[id].x = | ||
| 408 | static_cast<s32>(active_fingers[id].x * Layout::ScreenDocked::Width); | ||
| 409 | gesture.points[id].y = | ||
| 410 | static_cast<s32>(active_fingers[id].y * Layout::ScreenDocked::Height); | ||
| 411 | } | ||
| 412 | |||
| 413 | gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points); | ||
| 414 | gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points); | ||
| 191 | } | 415 | } |
| 192 | 416 | ||
| 193 | for (size_t id = 0; id < gesture.active_points; ++id) { | 417 | for (size_t id = 0; id < gesture.active_points; ++id) { |
| 194 | const double distance = | 418 | const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) + |
| 195 | std::pow(static_cast<float>(gesture.mid_point.x - gesture.points[id].x), 2) + | 419 | Square(gesture.mid_point.y - gesture.points[id].y)); |
| 196 | std::pow(static_cast<float>(gesture.mid_point.y - gesture.points[id].y), 2); | 420 | gesture.average_distance += distance / static_cast<f32>(gesture.active_points); |
| 197 | gesture.average_distance += | ||
| 198 | static_cast<float>(distance) / static_cast<float>(gesture.active_points); | ||
| 199 | } | 421 | } |
| 200 | 422 | ||
| 201 | gesture.angle = std::atan2(static_cast<float>(gesture.mid_point.y - gesture.points[0].y), | 423 | gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y), |
| 202 | static_cast<float>(gesture.mid_point.x - gesture.points[0].x)); | 424 | static_cast<f32>(gesture.mid_point.x - gesture.points[0].x)); |
| 425 | |||
| 426 | gesture.detection_count = last_gesture.detection_count; | ||
| 427 | |||
| 203 | return gesture; | 428 | return gesture; |
| 204 | } | 429 | } |
| 205 | 430 | ||
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 7c357b977..18110a6ad 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | 1 | // Copyright 2021 yuzu Emulator Project |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| @@ -7,7 +7,6 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include "common/bit_field.h" | 8 | #include "common/bit_field.h" |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/swap.h" | ||
| 11 | #include "core/frontend/input.h" | 10 | #include "core/frontend/input.h" |
| 12 | #include "core/hle/service/hid/controllers/controller_base.h" | 11 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 13 | 12 | ||
| @@ -35,10 +34,10 @@ private: | |||
| 35 | 34 | ||
| 36 | enum class TouchType : u32 { | 35 | enum class TouchType : u32 { |
| 37 | Idle, // Nothing touching the screen | 36 | Idle, // Nothing touching the screen |
| 38 | Complete, // Unknown. End of touch? | 37 | Complete, // Set at the end of a touch event |
| 39 | Cancel, // Never triggered | 38 | Cancel, // Set when the number of fingers change |
| 40 | Touch, // Pressing without movement | 39 | Touch, // A finger just touched the screen |
| 41 | Press, // Never triggered | 40 | Press, // Set if last type is touch and the finger hasn't moved |
| 42 | Tap, // Fast press then release | 41 | Tap, // Fast press then release |
| 43 | Pan, // All points moving together across the screen | 42 | Pan, // All points moving together across the screen |
| 44 | Swipe, // Fast press movement and release of a single point | 43 | Swipe, // Fast press movement and release of a single point |
| @@ -58,8 +57,8 @@ private: | |||
| 58 | union { | 57 | union { |
| 59 | u32_le raw{}; | 58 | u32_le raw{}; |
| 60 | 59 | ||
| 61 | BitField<0, 1, u32> is_new_touch; | 60 | BitField<4, 1, u32> is_new_touch; |
| 62 | BitField<1, 1, u32> is_double_tap; | 61 | BitField<8, 1, u32> is_double_tap; |
| 63 | }; | 62 | }; |
| 64 | }; | 63 | }; |
| 65 | static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); | 64 | static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); |
| @@ -73,10 +72,9 @@ private: | |||
| 73 | struct GestureState { | 72 | struct GestureState { |
| 74 | s64_le sampling_number; | 73 | s64_le sampling_number; |
| 75 | s64_le sampling_number2; | 74 | s64_le sampling_number2; |
| 76 | |||
| 77 | s64_le detection_count; | 75 | s64_le detection_count; |
| 78 | TouchType type; | 76 | TouchType type; |
| 79 | Direction dir; | 77 | Direction direction; |
| 80 | s32_le x; | 78 | s32_le x; |
| 81 | s32_le y; | 79 | s32_le y; |
| 82 | s32_le delta_x; | 80 | s32_le delta_x; |
| @@ -84,8 +82,8 @@ private: | |||
| 84 | f32 vel_x; | 82 | f32 vel_x; |
| 85 | f32 vel_y; | 83 | f32 vel_y; |
| 86 | Attribute attributes; | 84 | Attribute attributes; |
| 87 | u32 scale; | 85 | f32 scale; |
| 88 | u32 rotation_angle; | 86 | f32 rotation_angle; |
| 89 | s32_le point_count; | 87 | s32_le point_count; |
| 90 | std::array<Points, 4> points; | 88 | std::array<Points, 4> points; |
| 91 | }; | 89 | }; |
| @@ -109,10 +107,46 @@ private: | |||
| 109 | Points mid_point{}; | 107 | Points mid_point{}; |
| 110 | s64_le detection_count{}; | 108 | s64_le detection_count{}; |
| 111 | u64_le delta_time{}; | 109 | u64_le delta_time{}; |
| 112 | float average_distance{}; | 110 | f32 average_distance{}; |
| 113 | float angle{}; | 111 | f32 angle{}; |
| 114 | }; | 112 | }; |
| 115 | 113 | ||
| 114 | // Reads input from all available input engines | ||
| 115 | void ReadTouchInput(); | ||
| 116 | |||
| 117 | // Returns true if gesture state needs to be updated | ||
| 118 | bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference); | ||
| 119 | |||
| 120 | // Updates the shared memory to the next state | ||
| 121 | void UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture, | ||
| 122 | f32 time_difference); | ||
| 123 | |||
| 124 | // Initializes new gesture | ||
| 125 | void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes); | ||
| 126 | |||
| 127 | // Updates existing gesture state | ||
| 128 | void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference); | ||
| 129 | |||
| 130 | // Terminates exiting gesture | ||
| 131 | void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, | ||
| 132 | Attribute& attributes, f32 time_difference); | ||
| 133 | |||
| 134 | // Set current event to a tap event | ||
| 135 | void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, | ||
| 136 | Attribute& attributes); | ||
| 137 | |||
| 138 | // Calculates and set the extra parameters related to a pan event | ||
| 139 | void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 140 | TouchType& type, f32 time_difference); | ||
| 141 | |||
| 142 | // Terminates the pan event | ||
| 143 | void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, | ||
| 144 | f32 time_difference); | ||
| 145 | |||
| 146 | // Set current event to a swipe event | ||
| 147 | void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 148 | TouchType& type); | ||
| 149 | |||
| 116 | // Returns an unused finger id, if there is no fingers avaliable MAX_FINGERS will be returned | 150 | // Returns an unused finger id, if there is no fingers avaliable MAX_FINGERS will be returned |
| 117 | std::optional<size_t> GetUnusedFingerID() const; | 151 | std::optional<size_t> GetUnusedFingerID() const; |
| 118 | 152 | ||
| @@ -134,6 +168,11 @@ private: | |||
| 134 | std::array<size_t, MAX_FINGERS> keyboard_finger_id; | 168 | std::array<size_t, MAX_FINGERS> keyboard_finger_id; |
| 135 | std::array<size_t, MAX_FINGERS> udp_finger_id; | 169 | std::array<size_t, MAX_FINGERS> udp_finger_id; |
| 136 | std::array<Finger, MAX_POINTS> fingers; | 170 | std::array<Finger, MAX_POINTS> fingers; |
| 137 | GestureProperties last_gesture; | 171 | GestureProperties last_gesture{}; |
| 172 | s64_le last_update_timestamp{}; | ||
| 173 | s64_le last_tap_timestamp{}; | ||
| 174 | f32 last_pan_time_difference{}; | ||
| 175 | bool force_update{false}; | ||
| 176 | bool enable_press_and_tap{false}; | ||
| 138 | }; | 177 | }; |
| 139 | } // namespace Service::HID | 178 | } // namespace Service::HID |
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index dc2baca4a..2c8899ae0 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp | |||
| @@ -10,6 +10,11 @@ | |||
| 10 | 10 | ||
| 11 | namespace Service::SSL { | 11 | namespace Service::SSL { |
| 12 | 12 | ||
| 13 | enum class CertificateFormat : u32 { | ||
| 14 | Pem = 1, | ||
| 15 | Der = 2, | ||
| 16 | }; | ||
| 17 | |||
| 13 | class ISslConnection final : public ServiceFramework<ISslConnection> { | 18 | class ISslConnection final : public ServiceFramework<ISslConnection> { |
| 14 | public: | 19 | public: |
| 15 | explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} { | 20 | explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} { |
| @@ -58,8 +63,8 @@ public: | |||
| 58 | {1, nullptr, "GetOption"}, | 63 | {1, nullptr, "GetOption"}, |
| 59 | {2, &ISslContext::CreateConnection, "CreateConnection"}, | 64 | {2, &ISslContext::CreateConnection, "CreateConnection"}, |
| 60 | {3, nullptr, "GetConnectionCount"}, | 65 | {3, nullptr, "GetConnectionCount"}, |
| 61 | {4, nullptr, "ImportServerPki"}, | 66 | {4, &ISslContext::ImportServerPki, "ImportServerPki"}, |
| 62 | {5, nullptr, "ImportClientPki"}, | 67 | {5, &ISslContext::ImportClientPki, "ImportClientPki"}, |
| 63 | {6, nullptr, "RemoveServerPki"}, | 68 | {6, nullptr, "RemoveServerPki"}, |
| 64 | {7, nullptr, "RemoveClientPki"}, | 69 | {7, nullptr, "RemoveClientPki"}, |
| 65 | {8, nullptr, "RegisterInternalPki"}, | 70 | {8, nullptr, "RegisterInternalPki"}, |
| @@ -94,6 +99,39 @@ private: | |||
| 94 | rb.Push(RESULT_SUCCESS); | 99 | rb.Push(RESULT_SUCCESS); |
| 95 | rb.PushIpcInterface<ISslConnection>(system); | 100 | rb.PushIpcInterface<ISslConnection>(system); |
| 96 | } | 101 | } |
| 102 | |||
| 103 | void ImportServerPki(Kernel::HLERequestContext& ctx) { | ||
| 104 | IPC::RequestParser rp{ctx}; | ||
| 105 | const auto certificate_format = rp.PopEnum<CertificateFormat>(); | ||
| 106 | const auto pkcs_12_certificates = ctx.ReadBuffer(0); | ||
| 107 | |||
| 108 | constexpr u64 server_id = 0; | ||
| 109 | |||
| 110 | LOG_WARNING(Service_SSL, "(STUBBED) called, certificate_format={}", certificate_format); | ||
| 111 | |||
| 112 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 113 | rb.Push(RESULT_SUCCESS); | ||
| 114 | rb.Push(server_id); | ||
| 115 | } | ||
| 116 | |||
| 117 | void ImportClientPki(Kernel::HLERequestContext& ctx) { | ||
| 118 | const auto pkcs_12_certificate = ctx.ReadBuffer(0); | ||
| 119 | const auto ascii_password = [&ctx] { | ||
| 120 | if (ctx.CanReadBuffer(1)) { | ||
| 121 | return ctx.ReadBuffer(1); | ||
| 122 | } | ||
| 123 | |||
| 124 | return std::vector<u8>{}; | ||
| 125 | }(); | ||
| 126 | |||
| 127 | constexpr u64 client_id = 0; | ||
| 128 | |||
| 129 | LOG_WARNING(Service_SSL, "(STUBBED) called"); | ||
| 130 | |||
| 131 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 132 | rb.Push(RESULT_SUCCESS); | ||
| 133 | rb.Push(client_id); | ||
| 134 | } | ||
| 97 | }; | 135 | }; |
| 98 | 136 | ||
| 99 | class SSL final : public ServiceFramework<SSL> { | 137 | class SSL final : public ServiceFramework<SSL> { |
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 7c4e7dd3b..7399c3648 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp | |||
| @@ -153,6 +153,11 @@ struct InputSubsystem::Impl { | |||
| 153 | // TODO return the correct motion device | 153 | // TODO return the correct motion device |
| 154 | return {}; | 154 | return {}; |
| 155 | } | 155 | } |
| 156 | #ifdef HAVE_SDL2 | ||
| 157 | if (params.Get("class", "") == "sdl") { | ||
| 158 | return sdl->GetMotionMappingForDevice(params); | ||
| 159 | } | ||
| 160 | #endif | ||
| 156 | return {}; | 161 | return {}; |
| 157 | } | 162 | } |
| 158 | 163 | ||
diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h index 42bbf14d4..b5d41bba4 100644 --- a/src/input_common/sdl/sdl.h +++ b/src/input_common/sdl/sdl.h | |||
| @@ -37,6 +37,9 @@ public: | |||
| 37 | virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) { | 37 | virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) { |
| 38 | return {}; | 38 | return {}; |
| 39 | } | 39 | } |
| 40 | virtual MotionMapping GetMotionMappingForDevice(const Common::ParamPackage&) { | ||
| 41 | return {}; | ||
| 42 | } | ||
| 40 | }; | 43 | }; |
| 41 | 44 | ||
| 42 | class NullState : public State { | 45 | class NullState : public State { |
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index f682a6db4..822d0b555 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #endif | 29 | #endif |
| 30 | 30 | ||
| 31 | #include "common/logging/log.h" | 31 | #include "common/logging/log.h" |
| 32 | #include "common/math_util.h" | ||
| 32 | #include "common/param_package.h" | 33 | #include "common/param_package.h" |
| 33 | #include "common/settings_input.h" | 34 | #include "common/settings_input.h" |
| 34 | #include "common/threadsafe_queue.h" | 35 | #include "common/threadsafe_queue.h" |
| @@ -68,13 +69,57 @@ public: | |||
| 68 | SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, | 69 | SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, |
| 69 | SDL_GameController* game_controller) | 70 | SDL_GameController* game_controller) |
| 70 | : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, | 71 | : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, |
| 71 | sdl_controller{game_controller, &SDL_GameControllerClose} {} | 72 | sdl_controller{game_controller, &SDL_GameControllerClose} { |
| 73 | EnableMotion(); | ||
| 74 | } | ||
| 75 | |||
| 76 | void EnableMotion() { | ||
| 77 | if (sdl_controller) { | ||
| 78 | SDL_GameController* controller = sdl_controller.get(); | ||
| 79 | if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) { | ||
| 80 | SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); | ||
| 81 | has_accel = true; | ||
| 82 | } | ||
| 83 | if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) { | ||
| 84 | SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); | ||
| 85 | has_gyro = true; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | } | ||
| 72 | 89 | ||
| 73 | void SetButton(int button, bool value) { | 90 | void SetButton(int button, bool value) { |
| 74 | std::lock_guard lock{mutex}; | 91 | std::lock_guard lock{mutex}; |
| 75 | state.buttons.insert_or_assign(button, value); | 92 | state.buttons.insert_or_assign(button, value); |
| 76 | } | 93 | } |
| 77 | 94 | ||
| 95 | void SetMotion(SDL_ControllerSensorEvent event) { | ||
| 96 | constexpr float gravity_constant = 9.80665f; | ||
| 97 | std::lock_guard lock{mutex}; | ||
| 98 | u64 time_difference = event.timestamp - last_motion_update; | ||
| 99 | last_motion_update = event.timestamp; | ||
| 100 | switch (event.sensor) { | ||
| 101 | case SDL_SENSOR_ACCEL: { | ||
| 102 | const Common::Vec3f acceleration = {-event.data[0], event.data[2], -event.data[1]}; | ||
| 103 | motion.SetAcceleration(acceleration / gravity_constant); | ||
| 104 | break; | ||
| 105 | } | ||
| 106 | case SDL_SENSOR_GYRO: { | ||
| 107 | const Common::Vec3f gyroscope = {event.data[0], -event.data[2], event.data[1]}; | ||
| 108 | motion.SetGyroscope(gyroscope / (Common::PI * 2)); | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | // Ignore duplicated timestamps | ||
| 114 | if (time_difference == 0) { | ||
| 115 | return; | ||
| 116 | } | ||
| 117 | |||
| 118 | motion.SetGyroThreshold(0.0001f); | ||
| 119 | motion.UpdateRotation(time_difference * 1000); | ||
| 120 | motion.UpdateOrientation(time_difference * 1000); | ||
| 121 | } | ||
| 122 | |||
| 78 | bool GetButton(int button) const { | 123 | bool GetButton(int button) const { |
| 79 | std::lock_guard lock{mutex}; | 124 | std::lock_guard lock{mutex}; |
| 80 | return state.buttons.at(button); | 125 | return state.buttons.at(button); |
| @@ -121,6 +166,14 @@ public: | |||
| 121 | return std::make_tuple(x, y); | 166 | return std::make_tuple(x, y); |
| 122 | } | 167 | } |
| 123 | 168 | ||
| 169 | bool HasGyro() const { | ||
| 170 | return has_gyro; | ||
| 171 | } | ||
| 172 | |||
| 173 | bool HasAccel() const { | ||
| 174 | return has_accel; | ||
| 175 | } | ||
| 176 | |||
| 124 | const MotionInput& GetMotion() const { | 177 | const MotionInput& GetMotion() const { |
| 125 | return motion; | 178 | return motion; |
| 126 | } | 179 | } |
| @@ -173,8 +226,11 @@ private: | |||
| 173 | std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; | 226 | std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; |
| 174 | mutable std::mutex mutex; | 227 | mutable std::mutex mutex; |
| 175 | 228 | ||
| 176 | // Motion is initialized without PID values as motion input is not aviable for SDL2 | 229 | // Motion is initialized with the PID values |
| 177 | MotionInput motion{0.0f, 0.0f, 0.0f}; | 230 | MotionInput motion{0.3f, 0.005f, 0.0f}; |
| 231 | u64 last_motion_update{}; | ||
| 232 | bool has_gyro{false}; | ||
| 233 | bool has_accel{false}; | ||
| 178 | }; | 234 | }; |
| 179 | 235 | ||
| 180 | std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { | 236 | std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { |
| @@ -296,6 +352,12 @@ void SDLState::HandleGameControllerEvent(const SDL_Event& event) { | |||
| 296 | } | 352 | } |
| 297 | break; | 353 | break; |
| 298 | } | 354 | } |
| 355 | case SDL_CONTROLLERSENSORUPDATE: { | ||
| 356 | if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) { | ||
| 357 | joystick->SetMotion(event.csensor); | ||
| 358 | } | ||
| 359 | break; | ||
| 360 | } | ||
| 299 | case SDL_JOYDEVICEREMOVED: | 361 | case SDL_JOYDEVICEREMOVED: |
| 300 | LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); | 362 | LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); |
| 301 | CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); | 363 | CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); |
| @@ -449,6 +511,18 @@ private: | |||
| 449 | std::shared_ptr<SDLJoystick> joystick; | 511 | std::shared_ptr<SDLJoystick> joystick; |
| 450 | }; | 512 | }; |
| 451 | 513 | ||
| 514 | class SDLMotion final : public Input::MotionDevice { | ||
| 515 | public: | ||
| 516 | explicit SDLMotion(std::shared_ptr<SDLJoystick> joystick_) : joystick(std::move(joystick_)) {} | ||
| 517 | |||
| 518 | Input::MotionStatus GetStatus() const override { | ||
| 519 | return joystick->GetMotion().GetMotion(); | ||
| 520 | } | ||
| 521 | |||
| 522 | private: | ||
| 523 | std::shared_ptr<SDLJoystick> joystick; | ||
| 524 | }; | ||
| 525 | |||
| 452 | class SDLDirectionMotion final : public Input::MotionDevice { | 526 | class SDLDirectionMotion final : public Input::MotionDevice { |
| 453 | public: | 527 | public: |
| 454 | explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) | 528 | explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) |
| @@ -658,6 +732,10 @@ public: | |||
| 658 | 732 | ||
| 659 | auto joystick = state.GetSDLJoystickByGUID(guid, port); | 733 | auto joystick = state.GetSDLJoystickByGUID(guid, port); |
| 660 | 734 | ||
| 735 | if (params.Has("motion")) { | ||
| 736 | return std::make_unique<SDLMotion>(joystick); | ||
| 737 | } | ||
| 738 | |||
| 661 | if (params.Has("hat")) { | 739 | if (params.Has("hat")) { |
| 662 | const int hat = params.Get("hat", 0); | 740 | const int hat = params.Get("hat", 0); |
| 663 | const std::string direction_name = params.Get("direction", ""); | 741 | const std::string direction_name = params.Get("direction", ""); |
| @@ -717,6 +795,17 @@ SDLState::SDLState() { | |||
| 717 | RegisterFactory<VibrationDevice>("sdl", vibration_factory); | 795 | RegisterFactory<VibrationDevice>("sdl", vibration_factory); |
| 718 | RegisterFactory<MotionDevice>("sdl", motion_factory); | 796 | RegisterFactory<MotionDevice>("sdl", motion_factory); |
| 719 | 797 | ||
| 798 | // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers | ||
| 799 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); | ||
| 800 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); | ||
| 801 | |||
| 802 | // Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a | ||
| 803 | // GameController and not a generic one | ||
| 804 | SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1"); | ||
| 805 | |||
| 806 | // Turn off Pro controller home led | ||
| 807 | SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0"); | ||
| 808 | |||
| 720 | // If the frontend is going to manage the event loop, then we don't start one here | 809 | // If the frontend is going to manage the event loop, then we don't start one here |
| 721 | start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; | 810 | start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; |
| 722 | if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { | 811 | if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { |
| @@ -853,6 +942,13 @@ Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s | |||
| 853 | return params; | 942 | return params; |
| 854 | } | 943 | } |
| 855 | 944 | ||
| 945 | Common::ParamPackage BuildMotionParam(int port, std::string guid) { | ||
| 946 | Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}}); | ||
| 947 | params.Set("port", port); | ||
| 948 | params.Set("guid", std::move(guid)); | ||
| 949 | return params; | ||
| 950 | } | ||
| 951 | |||
| 856 | Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { | 952 | Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { |
| 857 | switch (event.type) { | 953 | switch (event.type) { |
| 858 | case SDL_JOYAXISMOTION: { | 954 | case SDL_JOYAXISMOTION: { |
| @@ -907,6 +1003,35 @@ Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Eve | |||
| 907 | } | 1003 | } |
| 908 | break; | 1004 | break; |
| 909 | } | 1005 | } |
| 1006 | case SDL_CONTROLLERSENSORUPDATE: { | ||
| 1007 | bool is_motion_shaking = false; | ||
| 1008 | constexpr float gyro_threshold = 5.0f; | ||
| 1009 | constexpr float accel_threshold = 11.0f; | ||
| 1010 | if (event.csensor.sensor == SDL_SENSOR_ACCEL) { | ||
| 1011 | const Common::Vec3f acceleration = {-event.csensor.data[0], event.csensor.data[2], | ||
| 1012 | -event.csensor.data[1]}; | ||
| 1013 | if (acceleration.Length() > accel_threshold) { | ||
| 1014 | is_motion_shaking = true; | ||
| 1015 | } | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | if (event.csensor.sensor == SDL_SENSOR_GYRO) { | ||
| 1019 | const Common::Vec3f gyroscope = {event.csensor.data[0], -event.csensor.data[2], | ||
| 1020 | event.csensor.data[1]}; | ||
| 1021 | if (gyroscope.Length() > gyro_threshold) { | ||
| 1022 | is_motion_shaking = true; | ||
| 1023 | } | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | if (!is_motion_shaking) { | ||
| 1027 | break; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | if (const auto joystick = state.GetSDLJoystickBySDLID(event.csensor.which)) { | ||
| 1031 | return BuildMotionParam(joystick->GetPort(), joystick->GetGUID()); | ||
| 1032 | } | ||
| 1033 | break; | ||
| 1034 | } | ||
| 910 | } | 1035 | } |
| 911 | return {}; | 1036 | return {}; |
| 912 | } | 1037 | } |
| @@ -1036,6 +1161,27 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa | |||
| 1036 | return mapping; | 1161 | return mapping; |
| 1037 | } | 1162 | } |
| 1038 | 1163 | ||
| 1164 | MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& params) { | ||
| 1165 | if (!params.Has("guid") || !params.Has("port")) { | ||
| 1166 | return {}; | ||
| 1167 | } | ||
| 1168 | const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); | ||
| 1169 | auto* controller = joystick->GetSDLGameController(); | ||
| 1170 | if (controller == nullptr) { | ||
| 1171 | return {}; | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | joystick->EnableMotion(); | ||
| 1175 | |||
| 1176 | if (!joystick->HasGyro() && !joystick->HasAccel()) { | ||
| 1177 | return {}; | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | MotionMapping mapping = {}; | ||
| 1181 | mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, | ||
| 1182 | BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); | ||
| 1183 | return mapping; | ||
| 1184 | } | ||
| 1039 | namespace Polling { | 1185 | namespace Polling { |
| 1040 | class SDLPoller : public InputCommon::Polling::DevicePoller { | 1186 | class SDLPoller : public InputCommon::Polling::DevicePoller { |
| 1041 | public: | 1187 | public: |
| @@ -1149,6 +1295,7 @@ public: | |||
| 1149 | [[fallthrough]]; | 1295 | [[fallthrough]]; |
| 1150 | case SDL_JOYBUTTONUP: | 1296 | case SDL_JOYBUTTONUP: |
| 1151 | case SDL_JOYHATMOTION: | 1297 | case SDL_JOYHATMOTION: |
| 1298 | case SDL_CONTROLLERSENSORUPDATE: | ||
| 1152 | return {SDLEventToMotionParamPackage(state, event)}; | 1299 | return {SDLEventToMotionParamPackage(state, event)}; |
| 1153 | } | 1300 | } |
| 1154 | return std::nullopt; | 1301 | return std::nullopt; |
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h index 8b7363f56..121e01913 100644 --- a/src/input_common/sdl/sdl_impl.h +++ b/src/input_common/sdl/sdl_impl.h | |||
| @@ -57,6 +57,7 @@ public: | |||
| 57 | 57 | ||
| 58 | ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; | 58 | ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; |
| 59 | AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; | 59 | AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; |
| 60 | MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override; | ||
| 60 | 61 | ||
| 61 | private: | 62 | private: |
| 62 | void InitJoystick(int joystick_index); | 63 | void InitJoystick(int joystick_index); |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 623b43d8a..ffe9edc1b 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -543,8 +543,7 @@ void TextureCacheRuntime::EmulateCopyImage(Image& dst, Image& src, | |||
| 543 | } | 543 | } |
| 544 | 544 | ||
| 545 | void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src, | 545 | void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src, |
| 546 | const std::array<Offset2D, 2>& dst_region, | 546 | const Region2D& dst_region, const Region2D& src_region, |
| 547 | const std::array<Offset2D, 2>& src_region, | ||
| 548 | Tegra::Engines::Fermi2D::Filter filter, | 547 | Tegra::Engines::Fermi2D::Filter filter, |
| 549 | Tegra::Engines::Fermi2D::Operation operation) { | 548 | Tegra::Engines::Fermi2D::Operation operation) { |
| 550 | state_tracker.NotifyScissor0(); | 549 | state_tracker.NotifyScissor0(); |
| @@ -560,9 +559,9 @@ void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src, | |||
| 560 | const GLbitfield buffer_bits = dst->BufferBits(); | 559 | const GLbitfield buffer_bits = dst->BufferBits(); |
| 561 | const bool has_depth = (buffer_bits & ~GL_COLOR_BUFFER_BIT) != 0; | 560 | const bool has_depth = (buffer_bits & ~GL_COLOR_BUFFER_BIT) != 0; |
| 562 | const bool is_linear = !has_depth && filter == Tegra::Engines::Fermi2D::Filter::Bilinear; | 561 | const bool is_linear = !has_depth && filter == Tegra::Engines::Fermi2D::Filter::Bilinear; |
| 563 | glBlitNamedFramebuffer(src->Handle(), dst->Handle(), src_region[0].x, src_region[0].y, | 562 | glBlitNamedFramebuffer(src->Handle(), dst->Handle(), src_region.start.x, src_region.start.y, |
| 564 | src_region[1].x, src_region[1].y, dst_region[0].x, dst_region[0].y, | 563 | src_region.end.x, src_region.end.y, dst_region.start.x, |
| 565 | dst_region[1].x, dst_region[1].y, buffer_bits, | 564 | dst_region.start.y, dst_region.end.x, dst_region.end.y, buffer_bits, |
| 566 | is_linear ? GL_LINEAR : GL_NEAREST); | 565 | is_linear ? GL_LINEAR : GL_NEAREST); |
| 567 | } | 566 | } |
| 568 | 567 | ||
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 3c871541b..df8be12ff 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h | |||
| @@ -28,7 +28,7 @@ using VideoCommon::ImageId; | |||
| 28 | using VideoCommon::ImageViewId; | 28 | using VideoCommon::ImageViewId; |
| 29 | using VideoCommon::ImageViewType; | 29 | using VideoCommon::ImageViewType; |
| 30 | using VideoCommon::NUM_RT; | 30 | using VideoCommon::NUM_RT; |
| 31 | using VideoCommon::Offset2D; | 31 | using VideoCommon::Region2D; |
| 32 | using VideoCommon::RenderTargets; | 32 | using VideoCommon::RenderTargets; |
| 33 | 33 | ||
| 34 | struct ImageBufferMap { | 34 | struct ImageBufferMap { |
| @@ -73,10 +73,8 @@ public: | |||
| 73 | 73 | ||
| 74 | void EmulateCopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); | 74 | void EmulateCopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); |
| 75 | 75 | ||
| 76 | void BlitFramebuffer(Framebuffer* dst, Framebuffer* src, | 76 | void BlitFramebuffer(Framebuffer* dst, Framebuffer* src, const Region2D& dst_region, |
| 77 | const std::array<Offset2D, 2>& dst_region, | 77 | const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, |
| 78 | const std::array<Offset2D, 2>& src_region, | ||
| 79 | Tegra::Engines::Fermi2D::Filter filter, | ||
| 80 | Tegra::Engines::Fermi2D::Operation operation); | 78 | Tegra::Engines::Fermi2D::Operation operation); |
| 81 | 79 | ||
| 82 | void AccelerateImageUpload(Image& image, const ImageBufferMap& map, | 80 | void AccelerateImageUpload(Image& image, const ImageBufferMap& map, |
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 1f6a169ae..b7f5b8bc2 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp | |||
| @@ -289,16 +289,15 @@ void UpdateTwoTexturesDescriptorSet(const Device& device, VkDescriptorSet descri | |||
| 289 | device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr); | 289 | device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr); |
| 290 | } | 290 | } |
| 291 | 291 | ||
| 292 | void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, | 292 | void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region, |
| 293 | const std::array<Offset2D, 2>& dst_region, | 293 | const Region2D& src_region) { |
| 294 | const std::array<Offset2D, 2>& src_region) { | ||
| 295 | const VkOffset2D offset{ | 294 | const VkOffset2D offset{ |
| 296 | .x = std::min(dst_region[0].x, dst_region[1].x), | 295 | .x = std::min(dst_region.start.x, dst_region.end.x), |
| 297 | .y = std::min(dst_region[0].y, dst_region[1].y), | 296 | .y = std::min(dst_region.start.y, dst_region.end.y), |
| 298 | }; | 297 | }; |
| 299 | const VkExtent2D extent{ | 298 | const VkExtent2D extent{ |
| 300 | .width = static_cast<u32>(std::abs(dst_region[1].x - dst_region[0].x)), | 299 | .width = static_cast<u32>(std::abs(dst_region.end.x - dst_region.start.x)), |
| 301 | .height = static_cast<u32>(std::abs(dst_region[1].y - dst_region[0].y)), | 300 | .height = static_cast<u32>(std::abs(dst_region.end.y - dst_region.start.y)), |
| 302 | }; | 301 | }; |
| 303 | const VkViewport viewport{ | 302 | const VkViewport viewport{ |
| 304 | .x = static_cast<float>(offset.x), | 303 | .x = static_cast<float>(offset.x), |
| @@ -313,11 +312,12 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, | |||
| 313 | .offset = offset, | 312 | .offset = offset, |
| 314 | .extent = extent, | 313 | .extent = extent, |
| 315 | }; | 314 | }; |
| 316 | const float scale_x = static_cast<float>(src_region[1].x - src_region[0].x); | 315 | const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x); |
| 317 | const float scale_y = static_cast<float>(src_region[1].y - src_region[0].y); | 316 | const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y); |
| 318 | const PushConstants push_constants{ | 317 | const PushConstants push_constants{ |
| 319 | .tex_scale = {scale_x, scale_y}, | 318 | .tex_scale = {scale_x, scale_y}, |
| 320 | .tex_offset = {static_cast<float>(src_region[0].x), static_cast<float>(src_region[0].y)}, | 319 | .tex_offset = {static_cast<float>(src_region.start.x), |
| 320 | static_cast<float>(src_region.start.y)}, | ||
| 321 | }; | 321 | }; |
| 322 | cmdbuf.SetViewport(0, viewport); | 322 | cmdbuf.SetViewport(0, viewport); |
| 323 | cmdbuf.SetScissor(0, scissor); | 323 | cmdbuf.SetScissor(0, scissor); |
| @@ -353,8 +353,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, | |||
| 353 | BlitImageHelper::~BlitImageHelper() = default; | 353 | BlitImageHelper::~BlitImageHelper() = default; |
| 354 | 354 | ||
| 355 | void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, | 355 | void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, |
| 356 | const std::array<Offset2D, 2>& dst_region, | 356 | const Region2D& dst_region, const Region2D& src_region, |
| 357 | const std::array<Offset2D, 2>& src_region, | ||
| 358 | Tegra::Engines::Fermi2D::Filter filter, | 357 | Tegra::Engines::Fermi2D::Filter filter, |
| 359 | Tegra::Engines::Fermi2D::Operation operation) { | 358 | Tegra::Engines::Fermi2D::Operation operation) { |
| 360 | const bool is_linear = filter == Tegra::Engines::Fermi2D::Filter::Bilinear; | 359 | const bool is_linear = filter == Tegra::Engines::Fermi2D::Filter::Bilinear; |
| @@ -383,8 +382,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV | |||
| 383 | 382 | ||
| 384 | void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, | 383 | void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, |
| 385 | VkImageView src_depth_view, VkImageView src_stencil_view, | 384 | VkImageView src_depth_view, VkImageView src_stencil_view, |
| 386 | const std::array<Offset2D, 2>& dst_region, | 385 | const Region2D& dst_region, const Region2D& src_region, |
| 387 | const std::array<Offset2D, 2>& src_region, | ||
| 388 | Tegra::Engines::Fermi2D::Filter filter, | 386 | Tegra::Engines::Fermi2D::Filter filter, |
| 389 | Tegra::Engines::Fermi2D::Operation operation) { | 387 | Tegra::Engines::Fermi2D::Operation operation) { |
| 390 | ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point); | 388 | ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point); |
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index 43fd3d737..0d81a06ed 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | namespace Vulkan { | 14 | namespace Vulkan { |
| 15 | 15 | ||
| 16 | using VideoCommon::Offset2D; | 16 | using VideoCommon::Region2D; |
| 17 | 17 | ||
| 18 | class Device; | 18 | class Device; |
| 19 | class Framebuffer; | 19 | class Framebuffer; |
| @@ -35,15 +35,13 @@ public: | |||
| 35 | ~BlitImageHelper(); | 35 | ~BlitImageHelper(); |
| 36 | 36 | ||
| 37 | void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, | 37 | void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, |
| 38 | const std::array<Offset2D, 2>& dst_region, | 38 | const Region2D& dst_region, const Region2D& src_region, |
| 39 | const std::array<Offset2D, 2>& src_region, | ||
| 40 | Tegra::Engines::Fermi2D::Filter filter, | 39 | Tegra::Engines::Fermi2D::Filter filter, |
| 41 | Tegra::Engines::Fermi2D::Operation operation); | 40 | Tegra::Engines::Fermi2D::Operation operation); |
| 42 | 41 | ||
| 43 | void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view, | 42 | void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view, |
| 44 | VkImageView src_stencil_view, const std::array<Offset2D, 2>& dst_region, | 43 | VkImageView src_stencil_view, const Region2D& dst_region, |
| 45 | const std::array<Offset2D, 2>& src_region, | 44 | const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, |
| 46 | Tegra::Engines::Fermi2D::Filter filter, | ||
| 47 | Tegra::Engines::Fermi2D::Operation operation); | 45 | Tegra::Engines::Fermi2D::Operation operation); |
| 48 | 46 | ||
| 49 | void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); | 47 | void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 017348e05..bdd0ce8bc 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -490,8 +490,7 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im | |||
| 490 | write_barrier); | 490 | write_barrier); |
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | [[nodiscard]] VkImageBlit MakeImageBlit(const std::array<Offset2D, 2>& dst_region, | 493 | [[nodiscard]] VkImageBlit MakeImageBlit(const Region2D& dst_region, const Region2D& src_region, |
| 494 | const std::array<Offset2D, 2>& src_region, | ||
| 495 | const VkImageSubresourceLayers& dst_layers, | 494 | const VkImageSubresourceLayers& dst_layers, |
| 496 | const VkImageSubresourceLayers& src_layers) { | 495 | const VkImageSubresourceLayers& src_layers) { |
| 497 | return VkImageBlit{ | 496 | return VkImageBlit{ |
| @@ -499,13 +498,13 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im | |||
| 499 | .srcOffsets = | 498 | .srcOffsets = |
| 500 | { | 499 | { |
| 501 | { | 500 | { |
| 502 | .x = src_region[0].x, | 501 | .x = src_region.start.x, |
| 503 | .y = src_region[0].y, | 502 | .y = src_region.start.y, |
| 504 | .z = 0, | 503 | .z = 0, |
| 505 | }, | 504 | }, |
| 506 | { | 505 | { |
| 507 | .x = src_region[1].x, | 506 | .x = src_region.end.x, |
| 508 | .y = src_region[1].y, | 507 | .y = src_region.end.y, |
| 509 | .z = 1, | 508 | .z = 1, |
| 510 | }, | 509 | }, |
| 511 | }, | 510 | }, |
| @@ -513,42 +512,42 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im | |||
| 513 | .dstOffsets = | 512 | .dstOffsets = |
| 514 | { | 513 | { |
| 515 | { | 514 | { |
| 516 | .x = dst_region[0].x, | 515 | .x = dst_region.start.x, |
| 517 | .y = dst_region[0].y, | 516 | .y = dst_region.start.y, |
| 518 | .z = 0, | 517 | .z = 0, |
| 519 | }, | 518 | }, |
| 520 | { | 519 | { |
| 521 | .x = dst_region[1].x, | 520 | .x = dst_region.end.x, |
| 522 | .y = dst_region[1].y, | 521 | .y = dst_region.end.y, |
| 523 | .z = 1, | 522 | .z = 1, |
| 524 | }, | 523 | }, |
| 525 | }, | 524 | }, |
| 526 | }; | 525 | }; |
| 527 | } | 526 | } |
| 528 | 527 | ||
| 529 | [[nodiscard]] VkImageResolve MakeImageResolve(const std::array<Offset2D, 2>& dst_region, | 528 | [[nodiscard]] VkImageResolve MakeImageResolve(const Region2D& dst_region, |
| 530 | const std::array<Offset2D, 2>& src_region, | 529 | const Region2D& src_region, |
| 531 | const VkImageSubresourceLayers& dst_layers, | 530 | const VkImageSubresourceLayers& dst_layers, |
| 532 | const VkImageSubresourceLayers& src_layers) { | 531 | const VkImageSubresourceLayers& src_layers) { |
| 533 | return VkImageResolve{ | 532 | return VkImageResolve{ |
| 534 | .srcSubresource = src_layers, | 533 | .srcSubresource = src_layers, |
| 535 | .srcOffset = | 534 | .srcOffset = |
| 536 | { | 535 | { |
| 537 | .x = src_region[0].x, | 536 | .x = src_region.start.x, |
| 538 | .y = src_region[0].y, | 537 | .y = src_region.start.y, |
| 539 | .z = 0, | 538 | .z = 0, |
| 540 | }, | 539 | }, |
| 541 | .dstSubresource = dst_layers, | 540 | .dstSubresource = dst_layers, |
| 542 | .dstOffset = | 541 | .dstOffset = |
| 543 | { | 542 | { |
| 544 | .x = dst_region[0].x, | 543 | .x = dst_region.start.x, |
| 545 | .y = dst_region[0].y, | 544 | .y = dst_region.start.y, |
| 546 | .z = 0, | 545 | .z = 0, |
| 547 | }, | 546 | }, |
| 548 | .extent = | 547 | .extent = |
| 549 | { | 548 | { |
| 550 | .width = static_cast<u32>(dst_region[1].x - dst_region[0].x), | 549 | .width = static_cast<u32>(dst_region.end.x - dst_region.start.x), |
| 551 | .height = static_cast<u32>(dst_region[1].y - dst_region[0].y), | 550 | .height = static_cast<u32>(dst_region.end.y - dst_region.start.y), |
| 552 | .depth = 1, | 551 | .depth = 1, |
| 553 | }, | 552 | }, |
| 554 | }; | 553 | }; |
| @@ -602,8 +601,7 @@ StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size) { | |||
| 602 | } | 601 | } |
| 603 | 602 | ||
| 604 | void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, | 603 | void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, |
| 605 | const std::array<Offset2D, 2>& dst_region, | 604 | const Region2D& dst_region, const Region2D& src_region, |
| 606 | const std::array<Offset2D, 2>& src_region, | ||
| 607 | Tegra::Engines::Fermi2D::Filter filter, | 605 | Tegra::Engines::Fermi2D::Filter filter, |
| 608 | Tegra::Engines::Fermi2D::Operation operation) { | 606 | Tegra::Engines::Fermi2D::Operation operation) { |
| 609 | const VkImageAspectFlags aspect_mask = ImageAspectMask(src.format); | 607 | const VkImageAspectFlags aspect_mask = ImageAspectMask(src.format); |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 628785d5e..4a57d378b 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -16,7 +16,7 @@ namespace Vulkan { | |||
| 16 | 16 | ||
| 17 | using VideoCommon::ImageId; | 17 | using VideoCommon::ImageId; |
| 18 | using VideoCommon::NUM_RT; | 18 | using VideoCommon::NUM_RT; |
| 19 | using VideoCommon::Offset2D; | 19 | using VideoCommon::Region2D; |
| 20 | using VideoCommon::RenderTargets; | 20 | using VideoCommon::RenderTargets; |
| 21 | using VideoCore::Surface::PixelFormat; | 21 | using VideoCore::Surface::PixelFormat; |
| 22 | 22 | ||
| @@ -71,8 +71,7 @@ struct TextureCacheRuntime { | |||
| 71 | [[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size); | 71 | [[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size); |
| 72 | 72 | ||
| 73 | void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, | 73 | void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, |
| 74 | const std::array<Offset2D, 2>& dst_region, | 74 | const Region2D& dst_region, const Region2D& src_region, |
| 75 | const std::array<Offset2D, 2>& src_region, | ||
| 76 | Tegra::Engines::Fermi2D::Filter filter, | 75 | Tegra::Engines::Fermi2D::Filter filter, |
| 77 | Tegra::Engines::Fermi2D::Operation operation); | 76 | Tegra::Engines::Fermi2D::Operation operation); |
| 78 | 77 | ||
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 98e33c3a0..59b7c678b 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -148,7 +148,9 @@ public: | |||
| 148 | /// Blit an image with the given parameters | 148 | /// Blit an image with the given parameters |
| 149 | void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, | 149 | void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, |
| 150 | const Tegra::Engines::Fermi2D::Surface& src, | 150 | const Tegra::Engines::Fermi2D::Surface& src, |
| 151 | const Tegra::Engines::Fermi2D::Config& copy); | 151 | const Tegra::Engines::Fermi2D::Config& copy, |
| 152 | std::optional<Region2D> src_region_override = {}, | ||
| 153 | std::optional<Region2D> dst_region_override = {}); | ||
| 152 | 154 | ||
| 153 | /// Invalidate the contents of the color buffer index | 155 | /// Invalidate the contents of the color buffer index |
| 154 | /// These contents become unspecified, the cache can assume aggressive optimizations. | 156 | /// These contents become unspecified, the cache can assume aggressive optimizations. |
| @@ -615,7 +617,9 @@ void TextureCache<P>::UnmapMemory(VAddr cpu_addr, size_t size) { | |||
| 615 | template <class P> | 617 | template <class P> |
| 616 | void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, | 618 | void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, |
| 617 | const Tegra::Engines::Fermi2D::Surface& src, | 619 | const Tegra::Engines::Fermi2D::Surface& src, |
| 618 | const Tegra::Engines::Fermi2D::Config& copy) { | 620 | const Tegra::Engines::Fermi2D::Config& copy, |
| 621 | std::optional<Region2D> src_override, | ||
| 622 | std::optional<Region2D> dst_override) { | ||
| 619 | const BlitImages images = GetBlitImages(dst, src); | 623 | const BlitImages images = GetBlitImages(dst, src); |
| 620 | const ImageId dst_id = images.dst_id; | 624 | const ImageId dst_id = images.dst_id; |
| 621 | const ImageId src_id = images.src_id; | 625 | const ImageId src_id = images.src_id; |
| @@ -631,20 +635,42 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, | |||
| 631 | const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range); | 635 | const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range); |
| 632 | const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info); | 636 | const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info); |
| 633 | const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples); | 637 | const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples); |
| 634 | const std::array src_region{ | 638 | |
| 635 | Offset2D{.x = copy.src_x0 >> src_samples_x, .y = copy.src_y0 >> src_samples_y}, | 639 | // out of bounds texture blit checking |
| 636 | Offset2D{.x = copy.src_x1 >> src_samples_x, .y = copy.src_y1 >> src_samples_y}, | 640 | const bool use_override = src_override.has_value(); |
| 641 | const s32 src_x0 = copy.src_x0 >> src_samples_x; | ||
| 642 | s32 src_x1 = use_override ? src_override->end.x : copy.src_x1 >> src_samples_x; | ||
| 643 | const s32 src_y0 = copy.src_y0 >> src_samples_y; | ||
| 644 | const s32 src_y1 = copy.src_y1 >> src_samples_y; | ||
| 645 | |||
| 646 | const auto src_width = static_cast<s32>(src_image.info.size.width); | ||
| 647 | const bool width_oob = src_x1 > src_width; | ||
| 648 | const auto width_diff = width_oob ? src_x1 - src_width : 0; | ||
| 649 | if (width_oob) { | ||
| 650 | src_x1 = src_width; | ||
| 651 | } | ||
| 652 | |||
| 653 | const Region2D src_dimensions{ | ||
| 654 | Offset2D{.x = src_x0, .y = src_y0}, | ||
| 655 | Offset2D{.x = src_x1, .y = src_y1}, | ||
| 637 | }; | 656 | }; |
| 657 | const auto src_region = use_override ? *src_override : src_dimensions; | ||
| 638 | 658 | ||
| 639 | const std::optional src_base = src_image.TryFindBase(src.Address()); | 659 | const std::optional src_base = src_image.TryFindBase(src.Address()); |
| 640 | const SubresourceRange src_range{.base = src_base.value(), .extent = {1, 1}}; | 660 | const SubresourceRange src_range{.base = src_base.value(), .extent = {1, 1}}; |
| 641 | const ImageViewInfo src_view_info(ImageViewType::e2D, images.src_format, src_range); | 661 | const ImageViewInfo src_view_info(ImageViewType::e2D, images.src_format, src_range); |
| 642 | const auto [src_framebuffer_id, src_view_id] = RenderTargetFromImage(src_id, src_view_info); | 662 | const auto [src_framebuffer_id, src_view_id] = RenderTargetFromImage(src_id, src_view_info); |
| 643 | const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples); | 663 | const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples); |
| 644 | const std::array dst_region{ | 664 | |
| 645 | Offset2D{.x = copy.dst_x0 >> dst_samples_x, .y = copy.dst_y0 >> dst_samples_y}, | 665 | const s32 dst_x0 = copy.dst_x0 >> dst_samples_x; |
| 646 | Offset2D{.x = copy.dst_x1 >> dst_samples_x, .y = copy.dst_y1 >> dst_samples_y}, | 666 | const s32 dst_x1 = copy.dst_x1 >> dst_samples_x; |
| 667 | const s32 dst_y0 = copy.dst_y0 >> dst_samples_y; | ||
| 668 | const s32 dst_y1 = copy.dst_y1 >> dst_samples_y; | ||
| 669 | const Region2D dst_dimensions{ | ||
| 670 | Offset2D{.x = dst_x0, .y = dst_y0}, | ||
| 671 | Offset2D{.x = dst_x1 - width_diff, .y = dst_y1}, | ||
| 647 | }; | 672 | }; |
| 673 | const auto dst_region = use_override ? *dst_override : dst_dimensions; | ||
| 648 | 674 | ||
| 649 | // Always call this after src_framebuffer_id was queried, as the address might be invalidated. | 675 | // Always call this after src_framebuffer_id was queried, as the address might be invalidated. |
| 650 | Framebuffer* const dst_framebuffer = &slot_framebuffers[dst_framebuffer_id]; | 676 | Framebuffer* const dst_framebuffer = &slot_framebuffers[dst_framebuffer_id]; |
| @@ -661,6 +687,21 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, | |||
| 661 | runtime.BlitImage(dst_framebuffer, dst_view, src_view, dst_region, src_region, copy.filter, | 687 | runtime.BlitImage(dst_framebuffer, dst_view, src_view, dst_region, src_region, copy.filter, |
| 662 | copy.operation); | 688 | copy.operation); |
| 663 | } | 689 | } |
| 690 | |||
| 691 | if (width_oob) { | ||
| 692 | // Continue copy of the oob region of the texture on the next row | ||
| 693 | auto oob_src = src; | ||
| 694 | oob_src.height++; | ||
| 695 | const Region2D src_region_override{ | ||
| 696 | Offset2D{.x = 0, .y = src_y0 + 1}, | ||
| 697 | Offset2D{.x = width_diff, .y = src_y1 + 1}, | ||
| 698 | }; | ||
| 699 | const Region2D dst_region_override{ | ||
| 700 | Offset2D{.x = dst_x1 - width_diff, .y = dst_y0}, | ||
| 701 | Offset2D{.x = dst_x1, .y = dst_y1}, | ||
| 702 | }; | ||
| 703 | BlitImage(dst, oob_src, copy, src_region_override, dst_region_override); | ||
| 704 | } | ||
| 664 | } | 705 | } |
| 665 | 706 | ||
| 666 | template <class P> | 707 | template <class P> |
diff --git a/src/video_core/texture_cache/types.h b/src/video_core/texture_cache/types.h index 2ad2d72a6..c9571f7e4 100644 --- a/src/video_core/texture_cache/types.h +++ b/src/video_core/texture_cache/types.h | |||
| @@ -64,6 +64,13 @@ struct Offset3D { | |||
| 64 | s32 z; | 64 | s32 z; |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | struct Region2D { | ||
| 68 | constexpr auto operator<=>(const Region2D&) const noexcept = default; | ||
| 69 | |||
| 70 | Offset2D start; | ||
| 71 | Offset2D end; | ||
| 72 | }; | ||
| 73 | |||
| 67 | struct Extent2D { | 74 | struct Extent2D { |
| 68 | constexpr auto operator<=>(const Extent2D&) const noexcept = default; | 75 | constexpr auto operator<=>(const Extent2D&) const noexcept = default; |
| 69 | 76 | ||
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index c9318c562..ab3512810 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -153,6 +153,10 @@ QString ButtonToText(const Common::ParamPackage& param) { | |||
| 153 | return QObject::tr("Button %1").arg(button_str); | 153 | return QObject::tr("Button %1").arg(button_str); |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | if (param.Has("motion")) { | ||
| 157 | return QObject::tr("SDL Motion"); | ||
| 158 | } | ||
| 159 | |||
| 156 | return {}; | 160 | return {}; |
| 157 | } | 161 | } |
| 158 | 162 | ||
| @@ -1245,12 +1249,16 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { | |||
| 1245 | const auto& device = input_devices[ui->comboDevices->currentIndex()]; | 1249 | const auto& device = input_devices[ui->comboDevices->currentIndex()]; |
| 1246 | auto button_mapping = input_subsystem->GetButtonMappingForDevice(device); | 1250 | auto button_mapping = input_subsystem->GetButtonMappingForDevice(device); |
| 1247 | auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device); | 1251 | auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device); |
| 1252 | auto motion_mapping = input_subsystem->GetMotionMappingForDevice(device); | ||
| 1248 | for (std::size_t i = 0; i < buttons_param.size(); ++i) { | 1253 | for (std::size_t i = 0; i < buttons_param.size(); ++i) { |
| 1249 | buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)]; | 1254 | buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)]; |
| 1250 | } | 1255 | } |
| 1251 | for (std::size_t i = 0; i < analogs_param.size(); ++i) { | 1256 | for (std::size_t i = 0; i < analogs_param.size(); ++i) { |
| 1252 | analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)]; | 1257 | analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)]; |
| 1253 | } | 1258 | } |
| 1259 | for (std::size_t i = 0; i < motions_param.size(); ++i) { | ||
| 1260 | motions_param[i] = motion_mapping[static_cast<Settings::NativeMotion::Values>(i)]; | ||
| 1261 | } | ||
| 1254 | 1262 | ||
| 1255 | UpdateUI(); | 1263 | UpdateUI(); |
| 1256 | } | 1264 | } |
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index f35c89e04..0cdaea8a4 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp | |||
| @@ -46,6 +46,7 @@ ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::Configur | |||
| 46 | SetConfiguration(); | 46 | SetConfiguration(); |
| 47 | 47 | ||
| 48 | // Force game list reload if any of the relevant settings are changed. | 48 | // Force game list reload if any of the relevant settings are changed. |
| 49 | connect(ui->show_add_ons, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate); | ||
| 49 | connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, | 50 | connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, |
| 50 | &ConfigureUi::RequestGameListUpdate); | 51 | &ConfigureUi::RequestGameListUpdate); |
| 51 | connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, | 52 | connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, |