diff options
m--------- | externals/ffmpeg | 0 | ||||
m--------- | externals/mbedtls | 0 | ||||
-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 |
19 files changed, 647 insertions, 142 deletions
diff --git a/externals/ffmpeg b/externals/ffmpeg -Subproject 6b6b9e593dd4d3aaf75f48d40a13ef03bdef9fd +Subproject 79e8d17024e6c6328a40fcee191ffd70798a9c6 diff --git a/externals/mbedtls b/externals/mbedtls -Subproject eac2416b8fdb2cb9c867a538100bf95326bad75 +Subproject 8c88150ca139e06aa2aae8349df8292a88148ea 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 @@ -// Copyright 2018 yuzu emulator team +// Copyright 2021 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <cstring> -#include "common/common_types.h" #include "common/logging/log.h" +#include "common/math_util.h" #include "common/settings.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" @@ -12,10 +11,19 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; -constexpr f32 angle_threshold = 0.08f; -constexpr f32 pinch_threshold = 100.0f; -Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase{system_} {} +// HW is around 700, value is set to 400 to make it easier to trigger with mouse +constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s +constexpr f32 angle_threshold = 0.015f; // Threshold in radians +constexpr f32 pinch_threshold = 0.5f; // Threshold in pixels +constexpr f32 press_delay = 0.5f; // Time in seconds +constexpr f32 double_tap_delay = 0.35f; // Time in seconds + +constexpr f32 Square(s32 num) { + return static_cast<f32>(num * num); +} + +Controller_Gesture::Controller_Gesture(Core::System& system) : ControllerBase(system) {} Controller_Gesture::~Controller_Gesture() = default; void Controller_Gesture::OnInit() { @@ -24,6 +32,8 @@ void Controller_Gesture::OnInit() { keyboard_finger_id[id] = MAX_POINTS; udp_finger_id[id] = MAX_POINTS; } + shared_memory.header.entry_count = 0; + force_update = true; } void Controller_Gesture::OnRelease() {} @@ -38,17 +48,23 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u shared_memory.header.last_entry_index = 0; return; } - shared_memory.header.entry_count = 16; - const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; - auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + ReadTouchInput(); - cur_entry.sampling_number = last_entry.sampling_number + 1; - cur_entry.sampling_number2 = cur_entry.sampling_number; + GestureProperties gesture = GetGestureProperties(); + f32 time_difference = static_cast<f32>(shared_memory.header.timestamp - last_update_timestamp) / + (1000 * 1000 * 1000); - // TODO(german77): Implement all gesture types + // Only update if necesary + if (!ShouldUpdateGesture(gesture, time_difference)) { + return; + } + last_update_timestamp = shared_memory.header.timestamp; + UpdateGestureSharedMemory(data, size, gesture, time_difference); +} + +void Controller_Gesture::ReadTouchInput() { const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); for (std::size_t id = 0; id < mouse_status.size(); ++id) { @@ -63,50 +79,71 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); } } +} - TouchType type = TouchType::Idle; - Attribute attributes{}; - GestureProperties gesture = GetGestureProperties(); - if (last_gesture.active_points != gesture.active_points) { - ++last_gesture.detection_count; +bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, + f32 time_difference) { + const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + if (force_update) { + force_update = false; + return true; } - if (gesture.active_points > 0) { - if (last_gesture.active_points == 0) { - attributes.is_new_touch.Assign(true); - last_gesture.average_distance = gesture.average_distance; - last_gesture.angle = gesture.angle; - } - type = TouchType::Touch; - if (gesture.mid_point.x != last_entry.x || gesture.mid_point.y != last_entry.y) { - type = TouchType::Pan; - } - if (std::abs(gesture.average_distance - last_gesture.average_distance) > pinch_threshold) { - type = TouchType::Pinch; - } - if (std::abs(gesture.angle - last_gesture.angle) > angle_threshold) { - type = TouchType::Rotate; + // Update if coordinates change + for (size_t id = 0; id < MAX_POINTS; id++) { + if (gesture.points[id].x != last_gesture.points[id].x || + gesture.points[id].y != last_gesture.points[id].y) { + return true; } + } + + // Update on press and hold event after 0.5 seconds + if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 && + time_difference > press_delay) { + return enable_press_and_tap; + } + + return false; +} + +void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, + GestureProperties& gesture, + f32 time_difference) { + TouchType type = TouchType::Idle; + Attribute attributes{}; + + const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - cur_entry.delta_x = gesture.mid_point.x - last_entry.x; - cur_entry.delta_y = gesture.mid_point.y - last_entry.y; - // TODO: Find how velocities are calculated - cur_entry.vel_x = static_cast<float>(cur_entry.delta_x) * 150.1f; - cur_entry.vel_y = static_cast<float>(cur_entry.delta_y) * 150.1f; + if (shared_memory.header.entry_count < 16) { + shared_memory.header.entry_count++; + } - // Slowdown the rate of change for less flapping - last_gesture.average_distance = - (last_gesture.average_distance * 0.9f) + (gesture.average_distance * 0.1f); - last_gesture.angle = (last_gesture.angle * 0.9f) + (gesture.angle * 0.1f); + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + // Reset values to default + cur_entry.delta_x = 0; + cur_entry.delta_y = 0; + cur_entry.vel_x = 0; + cur_entry.vel_y = 0; + cur_entry.direction = Direction::None; + cur_entry.rotation_angle = 0; + cur_entry.scale = 0; + + if (gesture.active_points > 0) { + if (last_gesture.active_points == 0) { + NewGesture(gesture, type, attributes); + } else { + UpdateExistingGesture(gesture, type, time_difference); + } } else { - cur_entry.delta_x = 0; - cur_entry.delta_y = 0; - cur_entry.vel_x = 0; - cur_entry.vel_y = 0; + EndGesture(gesture, last_gesture, type, attributes, time_difference); } - last_gesture.active_points = gesture.active_points; - cur_entry.detection_count = last_gesture.detection_count; + + // Apply attributes + cur_entry.detection_count = gesture.detection_count; cur_entry.type = type; cur_entry.attributes = attributes; cur_entry.x = gesture.mid_point.x; @@ -116,12 +153,190 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u cur_entry.points[id].x = gesture.points[id].x; cur_entry.points[id].y = gesture.points[id].y; } - cur_entry.rotation_angle = 0; - cur_entry.scale = 0; + last_gesture = gesture; std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); } +void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type, + Attribute& attributes) { + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + gesture.detection_count++; + type = TouchType::Touch; + + // New touch after cancel is not considered new + if (last_entry.type != TouchType::Cancel) { + attributes.is_new_touch.Assign(1); + enable_press_and_tap = true; + } +} + +void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type, + f32 time_difference) { + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + + // Promote to pan type if touch moved + for (size_t id = 0; id < MAX_POINTS; id++) { + if (gesture.points[id].x != last_gesture.points[id].x || + gesture.points[id].y != last_gesture.points[id].y) { + type = TouchType::Pan; + break; + } + } + + // Number of fingers changed cancel the last event and clear data + if (gesture.active_points != last_gesture.active_points) { + type = TouchType::Cancel; + enable_press_and_tap = false; + gesture.active_points = 0; + gesture.mid_point = {}; + for (size_t id = 0; id < MAX_POINTS; id++) { + gesture.points[id].x = 0; + gesture.points[id].y = 0; + } + return; + } + + // Calculate extra parameters of panning + if (type == TouchType::Pan) { + UpdatePanEvent(gesture, last_gesture, type, time_difference); + return; + } + + // Promote to press type + if (last_entry.type == TouchType::Touch) { + type = TouchType::Press; + } +} + +void Controller_Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, Attribute& attributes, f32 time_difference) { + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + if (last_gesture.active_points != 0) { + switch (last_entry.type) { + case TouchType::Touch: + if (enable_press_and_tap) { + SetTapEvent(gesture, last_gesture, type, attributes); + return; + } + type = TouchType::Cancel; + force_update = true; + break; + case TouchType::Press: + case TouchType::Tap: + case TouchType::Swipe: + case TouchType::Pinch: + case TouchType::Rotate: + type = TouchType::Complete; + force_update = true; + break; + case TouchType::Pan: + EndPanEvent(gesture, last_gesture, type, time_difference); + break; + default: + break; + } + return; + } + if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) { + gesture.detection_count++; + } +} + +void Controller_Gesture::SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, Attribute& attributes) { + type = TouchType::Tap; + gesture = last_gesture; + force_update = true; + f32 tap_time_difference = + static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000); + last_tap_timestamp = last_update_timestamp; + if (tap_time_difference < double_tap_delay) { + attributes.is_double_tap.Assign(1); + } +} + +void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, f32 time_difference) { + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + cur_entry.delta_x = gesture.mid_point.x - last_entry.x; + cur_entry.delta_y = gesture.mid_point.y - last_entry.y; + + cur_entry.vel_x = static_cast<f32>(cur_entry.delta_x) / time_difference; + cur_entry.vel_y = static_cast<f32>(cur_entry.delta_y) / time_difference; + last_pan_time_difference = time_difference; + + // Promote to pinch type + if (std::abs(gesture.average_distance - last_gesture.average_distance) > pinch_threshold) { + type = TouchType::Pinch; + cur_entry.scale = gesture.average_distance / last_gesture.average_distance; + } + + const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture.angle) / + (1 + (gesture.angle * last_gesture.angle))); + // Promote to rotate type + if (std::abs(angle_between_two_lines) > angle_threshold) { + type = TouchType::Rotate; + cur_entry.scale = 0; + cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; + } +} + +void Controller_Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, f32 time_difference) { + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + cur_entry.vel_x = + static_cast<f32>(last_entry.delta_x) / (last_pan_time_difference + time_difference); + cur_entry.vel_y = + static_cast<f32>(last_entry.delta_y) / (last_pan_time_difference + time_difference); + const f32 curr_vel = + std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y)); + + // Set swipe event with parameters + if (curr_vel > swipe_threshold) { + SetSwipeEvent(gesture, last_gesture, type); + return; + } + + // End panning without swipe + type = TouchType::Complete; + cur_entry.vel_x = 0; + cur_entry.vel_y = 0; + force_update = true; +} + +void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type) { + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = + shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; + type = TouchType::Swipe; + gesture = last_gesture; + force_update = true; + cur_entry.delta_x = last_entry.delta_x; + cur_entry.delta_y = last_entry.delta_y; + if (std::abs(cur_entry.delta_x) > std::abs(cur_entry.delta_y)) { + if (cur_entry.delta_x > 0) { + cur_entry.direction = Direction::Right; + return; + } + cur_entry.direction = Direction::Left; + return; + } + if (cur_entry.delta_y > 0) { + cur_entry.direction = Direction::Down; + return; + } + cur_entry.direction = Direction::Up; +} + void Controller_Gesture::OnLoadInputDevices() { touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); @@ -183,23 +398,33 @@ Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() for (size_t id = 0; id < gesture.active_points; ++id) { gesture.points[id].x = - static_cast<int>(active_fingers[id].x * Layout::ScreenUndocked::Width); + static_cast<s32>(active_fingers[id].x * Layout::ScreenUndocked::Width); gesture.points[id].y = - static_cast<int>(active_fingers[id].y * Layout::ScreenUndocked::Height); - gesture.mid_point.x += static_cast<int>(gesture.points[id].x / gesture.active_points); - gesture.mid_point.y += static_cast<int>(gesture.points[id].y / gesture.active_points); + static_cast<s32>(active_fingers[id].y * Layout::ScreenUndocked::Height); + + // Hack: There is no touch in docked but games still allow it + if (Settings::values.use_docked_mode.GetValue()) { + gesture.points[id].x = + static_cast<s32>(active_fingers[id].x * Layout::ScreenDocked::Width); + gesture.points[id].y = + static_cast<s32>(active_fingers[id].y * Layout::ScreenDocked::Height); + } + + gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points); + gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points); } for (size_t id = 0; id < gesture.active_points; ++id) { - const double distance = - std::pow(static_cast<float>(gesture.mid_point.x - gesture.points[id].x), 2) + - std::pow(static_cast<float>(gesture.mid_point.y - gesture.points[id].y), 2); - gesture.average_distance += - static_cast<float>(distance) / static_cast<float>(gesture.active_points); + const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) + + Square(gesture.mid_point.y - gesture.points[id].y)); + gesture.average_distance += distance / static_cast<f32>(gesture.active_points); } - gesture.angle = std::atan2(static_cast<float>(gesture.mid_point.y - gesture.points[0].y), - static_cast<float>(gesture.mid_point.x - gesture.points[0].x)); + gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y), + static_cast<f32>(gesture.mid_point.x - gesture.points[0].x)); + + gesture.detection_count = last_gesture.detection_count; + return gesture; } 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 @@ -// Copyright 2018 yuzu emulator team +// Copyright 2021 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -7,7 +7,6 @@ #include <array> #include "common/bit_field.h" #include "common/common_types.h" -#include "common/swap.h" #include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" @@ -35,10 +34,10 @@ private: enum class TouchType : u32 { Idle, // Nothing touching the screen - Complete, // Unknown. End of touch? - Cancel, // Never triggered - Touch, // Pressing without movement - Press, // Never triggered + Complete, // Set at the end of a touch event + Cancel, // Set when the number of fingers change + Touch, // A finger just touched the screen + Press, // Set if last type is touch and the finger hasn't moved Tap, // Fast press then release Pan, // All points moving together across the screen Swipe, // Fast press movement and release of a single point @@ -58,8 +57,8 @@ private: union { u32_le raw{}; - BitField<0, 1, u32> is_new_touch; - BitField<1, 1, u32> is_double_tap; + BitField<4, 1, u32> is_new_touch; + BitField<8, 1, u32> is_double_tap; }; }; static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); @@ -73,10 +72,9 @@ private: struct GestureState { s64_le sampling_number; s64_le sampling_number2; - s64_le detection_count; TouchType type; - Direction dir; + Direction direction; s32_le x; s32_le y; s32_le delta_x; @@ -84,8 +82,8 @@ private: f32 vel_x; f32 vel_y; Attribute attributes; - u32 scale; - u32 rotation_angle; + f32 scale; + f32 rotation_angle; s32_le point_count; std::array<Points, 4> points; }; @@ -109,10 +107,46 @@ private: Points mid_point{}; s64_le detection_count{}; u64_le delta_time{}; - float average_distance{}; - float angle{}; + f32 average_distance{}; + f32 angle{}; }; + // Reads input from all available input engines + void ReadTouchInput(); + + // Returns true if gesture state needs to be updated + bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference); + + // Updates the shared memory to the next state + void UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture, + f32 time_difference); + + // Initializes new gesture + void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes); + + // Updates existing gesture state + void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference); + + // Terminates exiting gesture + void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, + Attribute& attributes, f32 time_difference); + + // Set current event to a tap event + void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, + Attribute& attributes); + + // Calculates and set the extra parameters related to a pan event + void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type, f32 time_difference); + + // Terminates the pan event + void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, + f32 time_difference); + + // Set current event to a swipe event + void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture, + TouchType& type); + // Returns an unused finger id, if there is no fingers avaliable MAX_FINGERS will be returned std::optional<size_t> GetUnusedFingerID() const; @@ -134,6 +168,11 @@ private: std::array<size_t, MAX_FINGERS> keyboard_finger_id; std::array<size_t, MAX_FINGERS> udp_finger_id; std::array<Finger, MAX_POINTS> fingers; - GestureProperties last_gesture; + GestureProperties last_gesture{}; + s64_le last_update_timestamp{}; + s64_le last_tap_timestamp{}; + f32 last_pan_time_difference{}; + bool force_update{false}; + bool enable_press_and_tap{false}; }; } // 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 @@ namespace Service::SSL { +enum class CertificateFormat : u32 { + Pem = 1, + Der = 2, +}; + class ISslConnection final : public ServiceFramework<ISslConnection> { public: explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} { @@ -58,8 +63,8 @@ public: {1, nullptr, "GetOption"}, {2, &ISslContext::CreateConnection, "CreateConnection"}, {3, nullptr, "GetConnectionCount"}, - {4, nullptr, "ImportServerPki"}, - {5, nullptr, "ImportClientPki"}, + {4, &ISslContext::ImportServerPki, "ImportServerPki"}, + {5, &ISslContext::ImportClientPki, "ImportClientPki"}, {6, nullptr, "RemoveServerPki"}, {7, nullptr, "RemoveClientPki"}, {8, nullptr, "RegisterInternalPki"}, @@ -94,6 +99,39 @@ private: rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ISslConnection>(system); } + + void ImportServerPki(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto certificate_format = rp.PopEnum<CertificateFormat>(); + const auto pkcs_12_certificates = ctx.ReadBuffer(0); + + constexpr u64 server_id = 0; + + LOG_WARNING(Service_SSL, "(STUBBED) called, certificate_format={}", certificate_format); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(server_id); + } + + void ImportClientPki(Kernel::HLERequestContext& ctx) { + const auto pkcs_12_certificate = ctx.ReadBuffer(0); + const auto ascii_password = [&ctx] { + if (ctx.CanReadBuffer(1)) { + return ctx.ReadBuffer(1); + } + + return std::vector<u8>{}; + }(); + + constexpr u64 client_id = 0; + + LOG_WARNING(Service_SSL, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + rb.Push(client_id); + } }; 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 { // TODO return the correct motion device return {}; } +#ifdef HAVE_SDL2 + if (params.Get("class", "") == "sdl") { + return sdl->GetMotionMappingForDevice(params); + } +#endif return {}; } 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: virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) { return {}; } + virtual MotionMapping GetMotionMappingForDevice(const Common::ParamPackage&) { + return {}; + } }; 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 @@ #endif #include "common/logging/log.h" +#include "common/math_util.h" #include "common/param_package.h" #include "common/settings_input.h" #include "common/threadsafe_queue.h" @@ -68,13 +69,57 @@ public: SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, SDL_GameController* game_controller) : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, - sdl_controller{game_controller, &SDL_GameControllerClose} {} + sdl_controller{game_controller, &SDL_GameControllerClose} { + EnableMotion(); + } + + void EnableMotion() { + if (sdl_controller) { + SDL_GameController* controller = sdl_controller.get(); + if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) { + SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); + has_accel = true; + } + if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) { + SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); + has_gyro = true; + } + } + } void SetButton(int button, bool value) { std::lock_guard lock{mutex}; state.buttons.insert_or_assign(button, value); } + void SetMotion(SDL_ControllerSensorEvent event) { + constexpr float gravity_constant = 9.80665f; + std::lock_guard lock{mutex}; + u64 time_difference = event.timestamp - last_motion_update; + last_motion_update = event.timestamp; + switch (event.sensor) { + case SDL_SENSOR_ACCEL: { + const Common::Vec3f acceleration = {-event.data[0], event.data[2], -event.data[1]}; + motion.SetAcceleration(acceleration / gravity_constant); + break; + } + case SDL_SENSOR_GYRO: { + const Common::Vec3f gyroscope = {event.data[0], -event.data[2], event.data[1]}; + motion.SetGyroscope(gyroscope / (Common::PI * 2)); + break; + } + } + + // Ignore duplicated timestamps + if (time_difference == 0) { + return; + } + + motion.SetGyroThreshold(0.0001f); + motion.UpdateRotation(time_difference * 1000); + motion.UpdateOrientation(time_difference * 1000); + } + bool GetButton(int button) const { std::lock_guard lock{mutex}; return state.buttons.at(button); @@ -121,6 +166,14 @@ public: return std::make_tuple(x, y); } + bool HasGyro() const { + return has_gyro; + } + + bool HasAccel() const { + return has_accel; + } + const MotionInput& GetMotion() const { return motion; } @@ -173,8 +226,11 @@ private: std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; mutable std::mutex mutex; - // Motion is initialized without PID values as motion input is not aviable for SDL2 - MotionInput motion{0.0f, 0.0f, 0.0f}; + // Motion is initialized with the PID values + MotionInput motion{0.3f, 0.005f, 0.0f}; + u64 last_motion_update{}; + bool has_gyro{false}; + bool has_accel{false}; }; std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { @@ -296,6 +352,12 @@ void SDLState::HandleGameControllerEvent(const SDL_Event& event) { } break; } + case SDL_CONTROLLERSENSORUPDATE: { + if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) { + joystick->SetMotion(event.csensor); + } + break; + } case SDL_JOYDEVICEREMOVED: LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); @@ -449,6 +511,18 @@ private: std::shared_ptr<SDLJoystick> joystick; }; +class SDLMotion final : public Input::MotionDevice { +public: + explicit SDLMotion(std::shared_ptr<SDLJoystick> joystick_) : joystick(std::move(joystick_)) {} + + Input::MotionStatus GetStatus() const override { + return joystick->GetMotion().GetMotion(); + } + +private: + std::shared_ptr<SDLJoystick> joystick; +}; + class SDLDirectionMotion final : public Input::MotionDevice { public: explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) @@ -658,6 +732,10 @@ public: auto joystick = state.GetSDLJoystickByGUID(guid, port); + if (params.Has("motion")) { + return std::make_unique<SDLMotion>(joystick); + } + if (params.Has("hat")) { const int hat = params.Get("hat", 0); const std::string direction_name = params.Get("direction", ""); @@ -717,6 +795,17 @@ SDLState::SDLState() { RegisterFactory<VibrationDevice>("sdl", vibration_factory); RegisterFactory<MotionDevice>("sdl", motion_factory); + // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); + + // Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a + // GameController and not a generic one + SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1"); + + // Turn off Pro controller home led + SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0"); + // If the frontend is going to manage the event loop, then we don't start one here start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { @@ -853,6 +942,13 @@ Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s return params; } +Common::ParamPackage BuildMotionParam(int port, std::string guid) { + Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}}); + params.Set("port", port); + params.Set("guid", std::move(guid)); + return params; +} + Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { switch (event.type) { case SDL_JOYAXISMOTION: { @@ -907,6 +1003,35 @@ Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Eve } break; } + case SDL_CONTROLLERSENSORUPDATE: { + bool is_motion_shaking = false; + constexpr float gyro_threshold = 5.0f; + constexpr float accel_threshold = 11.0f; + if (event.csensor.sensor == SDL_SENSOR_ACCEL) { + const Common::Vec3f acceleration = {-event.csensor.data[0], event.csensor.data[2], + -event.csensor.data[1]}; + if (acceleration.Length() > accel_threshold) { + is_motion_shaking = true; + } + } + + if (event.csensor.sensor == SDL_SENSOR_GYRO) { + const Common::Vec3f gyroscope = {event.csensor.data[0], -event.csensor.data[2], + event.csensor.data[1]}; + if (gyroscope.Length() > gyro_threshold) { + is_motion_shaking = true; + } + } + + if (!is_motion_shaking) { + break; + } + + if (const auto joystick = state.GetSDLJoystickBySDLID(event.csensor.which)) { + return BuildMotionParam(joystick->GetPort(), joystick->GetGUID()); + } + break; + } } return {}; } @@ -1036,6 +1161,27 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa return mapping; } +MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& params) { + if (!params.Has("guid") || !params.Has("port")) { + return {}; + } + const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); + auto* controller = joystick->GetSDLGameController(); + if (controller == nullptr) { + return {}; + } + + joystick->EnableMotion(); + + if (!joystick->HasGyro() && !joystick->HasAccel()) { + return {}; + } + + MotionMapping mapping = {}; + mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, + BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); + return mapping; +} namespace Polling { class SDLPoller : public InputCommon::Polling::DevicePoller { public: @@ -1149,6 +1295,7 @@ public: [[fallthrough]]; case SDL_JOYBUTTONUP: case SDL_JOYHATMOTION: + case SDL_CONTROLLERSENSORUPDATE: return {SDLEventToMotionParamPackage(state, event)}; } 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: ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; + MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override; private: 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, } void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src, - const std::array<Offset2D, 2>& dst_region, - const std::array<Offset2D, 2>& src_region, + const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation) { state_tracker.NotifyScissor0(); @@ -560,9 +559,9 @@ void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src, const GLbitfield buffer_bits = dst->BufferBits(); const bool has_depth = (buffer_bits & ~GL_COLOR_BUFFER_BIT) != 0; const bool is_linear = !has_depth && filter == Tegra::Engines::Fermi2D::Filter::Bilinear; - glBlitNamedFramebuffer(src->Handle(), dst->Handle(), src_region[0].x, src_region[0].y, - src_region[1].x, src_region[1].y, dst_region[0].x, dst_region[0].y, - dst_region[1].x, dst_region[1].y, buffer_bits, + glBlitNamedFramebuffer(src->Handle(), dst->Handle(), src_region.start.x, src_region.start.y, + src_region.end.x, src_region.end.y, dst_region.start.x, + dst_region.start.y, dst_region.end.x, dst_region.end.y, buffer_bits, is_linear ? GL_LINEAR : GL_NEAREST); } 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; using VideoCommon::ImageViewId; using VideoCommon::ImageViewType; using VideoCommon::NUM_RT; -using VideoCommon::Offset2D; +using VideoCommon::Region2D; using VideoCommon::RenderTargets; struct ImageBufferMap { @@ -73,10 +73,8 @@ public: void EmulateCopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); - void BlitFramebuffer(Framebuffer* dst, Framebuffer* src, - const std::array<Offset2D, 2>& dst_region, - const std::array<Offset2D, 2>& src_region, - Tegra::Engines::Fermi2D::Filter filter, + void BlitFramebuffer(Framebuffer* dst, Framebuffer* src, const Region2D& dst_region, + const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation); 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 device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr); } -void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, - const std::array<Offset2D, 2>& dst_region, - const std::array<Offset2D, 2>& src_region) { +void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region, + const Region2D& src_region) { const VkOffset2D offset{ - .x = std::min(dst_region[0].x, dst_region[1].x), - .y = std::min(dst_region[0].y, dst_region[1].y), + .x = std::min(dst_region.start.x, dst_region.end.x), + .y = std::min(dst_region.start.y, dst_region.end.y), }; const VkExtent2D extent{ - .width = static_cast<u32>(std::abs(dst_region[1].x - dst_region[0].x)), - .height = static_cast<u32>(std::abs(dst_region[1].y - dst_region[0].y)), + .width = static_cast<u32>(std::abs(dst_region.end.x - dst_region.start.x)), + .height = static_cast<u32>(std::abs(dst_region.end.y - dst_region.start.y)), }; const VkViewport viewport{ .x = static_cast<float>(offset.x), @@ -313,11 +312,12 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, .offset = offset, .extent = extent, }; - const float scale_x = static_cast<float>(src_region[1].x - src_region[0].x); - const float scale_y = static_cast<float>(src_region[1].y - src_region[0].y); + const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x); + const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y); const PushConstants push_constants{ .tex_scale = {scale_x, scale_y}, - .tex_offset = {static_cast<float>(src_region[0].x), static_cast<float>(src_region[0].y)}, + .tex_offset = {static_cast<float>(src_region.start.x), + static_cast<float>(src_region.start.y)}, }; cmdbuf.SetViewport(0, viewport); cmdbuf.SetScissor(0, scissor); @@ -353,8 +353,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, BlitImageHelper::~BlitImageHelper() = default; void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, - const std::array<Offset2D, 2>& dst_region, - const std::array<Offset2D, 2>& src_region, + const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation) { const bool is_linear = filter == Tegra::Engines::Fermi2D::Filter::Bilinear; @@ -383,8 +382,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view, VkImageView src_stencil_view, - const std::array<Offset2D, 2>& dst_region, - const std::array<Offset2D, 2>& src_region, + const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation) { 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 @@ namespace Vulkan { -using VideoCommon::Offset2D; +using VideoCommon::Region2D; class Device; class Framebuffer; @@ -35,15 +35,13 @@ public: ~BlitImageHelper(); void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, - const std::array<Offset2D, 2>& dst_region, - const std::array<Offset2D, 2>& src_region, + const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation); void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view, - VkImageView src_stencil_view, const std::array<Offset2D, 2>& dst_region, - const std::array<Offset2D, 2>& src_region, - Tegra::Engines::Fermi2D::Filter filter, + VkImageView src_stencil_view, const Region2D& dst_region, + const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation); 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 write_barrier); } -[[nodiscard]] VkImageBlit MakeImageBlit(const std::array<Offset2D, 2>& dst_region, - const std::array<Offset2D, 2>& src_region, +[[nodiscard]] VkImageBlit MakeImageBlit(const Region2D& dst_region, const Region2D& src_region, const VkImageSubresourceLayers& dst_layers, const VkImageSubresourceLayers& src_layers) { return VkImageBlit{ @@ -499,13 +498,13 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im .srcOffsets = { { - .x = src_region[0].x, - .y = src_region[0].y, + .x = src_region.start.x, + .y = src_region.start.y, .z = 0, }, { - .x = src_region[1].x, - .y = src_region[1].y, + .x = src_region.end.x, + .y = src_region.end.y, .z = 1, }, }, @@ -513,42 +512,42 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im .dstOffsets = { { - .x = dst_region[0].x, - .y = dst_region[0].y, + .x = dst_region.start.x, + .y = dst_region.start.y, .z = 0, }, { - .x = dst_region[1].x, - .y = dst_region[1].y, + .x = dst_region.end.x, + .y = dst_region.end.y, .z = 1, }, }, }; } -[[nodiscard]] VkImageResolve MakeImageResolve(const std::array<Offset2D, 2>& dst_region, - const std::array<Offset2D, 2>& src_region, +[[nodiscard]] VkImageResolve MakeImageResolve(const Region2D& dst_region, + const Region2D& src_region, const VkImageSubresourceLayers& dst_layers, const VkImageSubresourceLayers& src_layers) { return VkImageResolve{ .srcSubresource = src_layers, .srcOffset = { - .x = src_region[0].x, - .y = src_region[0].y, + .x = src_region.start.x, + .y = src_region.start.y, .z = 0, }, .dstSubresource = dst_layers, .dstOffset = { - .x = dst_region[0].x, - .y = dst_region[0].y, + .x = dst_region.start.x, + .y = dst_region.start.y, .z = 0, }, .extent = { - .width = static_cast<u32>(dst_region[1].x - dst_region[0].x), - .height = static_cast<u32>(dst_region[1].y - dst_region[0].y), + .width = static_cast<u32>(dst_region.end.x - dst_region.start.x), + .height = static_cast<u32>(dst_region.end.y - dst_region.start.y), .depth = 1, }, }; @@ -602,8 +601,7 @@ StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size) { } void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, - const std::array<Offset2D, 2>& dst_region, - const std::array<Offset2D, 2>& src_region, + const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation) { 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 { using VideoCommon::ImageId; using VideoCommon::NUM_RT; -using VideoCommon::Offset2D; +using VideoCommon::Region2D; using VideoCommon::RenderTargets; using VideoCore::Surface::PixelFormat; @@ -71,8 +71,7 @@ struct TextureCacheRuntime { [[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size); void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, - const std::array<Offset2D, 2>& dst_region, - const std::array<Offset2D, 2>& src_region, + const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation); 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: /// Blit an image with the given parameters void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, const Tegra::Engines::Fermi2D::Surface& src, - const Tegra::Engines::Fermi2D::Config& copy); + const Tegra::Engines::Fermi2D::Config& copy, + std::optional<Region2D> src_region_override = {}, + std::optional<Region2D> dst_region_override = {}); /// Invalidate the contents of the color buffer index /// These contents become unspecified, the cache can assume aggressive optimizations. @@ -615,7 +617,9 @@ void TextureCache<P>::UnmapMemory(VAddr cpu_addr, size_t size) { template <class P> void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, const Tegra::Engines::Fermi2D::Surface& src, - const Tegra::Engines::Fermi2D::Config& copy) { + const Tegra::Engines::Fermi2D::Config& copy, + std::optional<Region2D> src_override, + std::optional<Region2D> dst_override) { const BlitImages images = GetBlitImages(dst, src); const ImageId dst_id = images.dst_id; const ImageId src_id = images.src_id; @@ -631,20 +635,42 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range); const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info); const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples); - const std::array src_region{ - Offset2D{.x = copy.src_x0 >> src_samples_x, .y = copy.src_y0 >> src_samples_y}, - Offset2D{.x = copy.src_x1 >> src_samples_x, .y = copy.src_y1 >> src_samples_y}, + + // out of bounds texture blit checking + const bool use_override = src_override.has_value(); + const s32 src_x0 = copy.src_x0 >> src_samples_x; + s32 src_x1 = use_override ? src_override->end.x : copy.src_x1 >> src_samples_x; + const s32 src_y0 = copy.src_y0 >> src_samples_y; + const s32 src_y1 = copy.src_y1 >> src_samples_y; + + const auto src_width = static_cast<s32>(src_image.info.size.width); + const bool width_oob = src_x1 > src_width; + const auto width_diff = width_oob ? src_x1 - src_width : 0; + if (width_oob) { + src_x1 = src_width; + } + + const Region2D src_dimensions{ + Offset2D{.x = src_x0, .y = src_y0}, + Offset2D{.x = src_x1, .y = src_y1}, }; + const auto src_region = use_override ? *src_override : src_dimensions; const std::optional src_base = src_image.TryFindBase(src.Address()); const SubresourceRange src_range{.base = src_base.value(), .extent = {1, 1}}; const ImageViewInfo src_view_info(ImageViewType::e2D, images.src_format, src_range); const auto [src_framebuffer_id, src_view_id] = RenderTargetFromImage(src_id, src_view_info); const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples); - const std::array dst_region{ - Offset2D{.x = copy.dst_x0 >> dst_samples_x, .y = copy.dst_y0 >> dst_samples_y}, - Offset2D{.x = copy.dst_x1 >> dst_samples_x, .y = copy.dst_y1 >> dst_samples_y}, + + const s32 dst_x0 = copy.dst_x0 >> dst_samples_x; + const s32 dst_x1 = copy.dst_x1 >> dst_samples_x; + const s32 dst_y0 = copy.dst_y0 >> dst_samples_y; + const s32 dst_y1 = copy.dst_y1 >> dst_samples_y; + const Region2D dst_dimensions{ + Offset2D{.x = dst_x0, .y = dst_y0}, + Offset2D{.x = dst_x1 - width_diff, .y = dst_y1}, }; + const auto dst_region = use_override ? *dst_override : dst_dimensions; // Always call this after src_framebuffer_id was queried, as the address might be invalidated. Framebuffer* const dst_framebuffer = &slot_framebuffers[dst_framebuffer_id]; @@ -661,6 +687,21 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, runtime.BlitImage(dst_framebuffer, dst_view, src_view, dst_region, src_region, copy.filter, copy.operation); } + + if (width_oob) { + // Continue copy of the oob region of the texture on the next row + auto oob_src = src; + oob_src.height++; + const Region2D src_region_override{ + Offset2D{.x = 0, .y = src_y0 + 1}, + Offset2D{.x = width_diff, .y = src_y1 + 1}, + }; + const Region2D dst_region_override{ + Offset2D{.x = dst_x1 - width_diff, .y = dst_y0}, + Offset2D{.x = dst_x1, .y = dst_y1}, + }; + BlitImage(dst, oob_src, copy, src_region_override, dst_region_override); + } } 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 { s32 z; }; +struct Region2D { + constexpr auto operator<=>(const Region2D&) const noexcept = default; + + Offset2D start; + Offset2D end; +}; + struct Extent2D { constexpr auto operator<=>(const Extent2D&) const noexcept = default; 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) { return QObject::tr("Button %1").arg(button_str); } + if (param.Has("motion")) { + return QObject::tr("SDL Motion"); + } + return {}; } @@ -1245,12 +1249,16 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { const auto& device = input_devices[ui->comboDevices->currentIndex()]; auto button_mapping = input_subsystem->GetButtonMappingForDevice(device); auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device); + auto motion_mapping = input_subsystem->GetMotionMappingForDevice(device); for (std::size_t i = 0; i < buttons_param.size(); ++i) { buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)]; } for (std::size_t i = 0; i < analogs_param.size(); ++i) { analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)]; } + for (std::size_t i = 0; i < motions_param.size(); ++i) { + motions_param[i] = motion_mapping[static_cast<Settings::NativeMotion::Values>(i)]; + } UpdateUI(); } 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 SetConfiguration(); // Force game list reload if any of the relevant settings are changed. + connect(ui->show_add_ons, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate); connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ConfigureUi::RequestGameListUpdate); connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, |