summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.ci/yuzu-patreon-step2.yml1
-rw-r--r--src/common/wall_clock.cpp2
-rw-r--r--src/common/wall_clock.h2
-rw-r--r--src/common/x64/native_clock.h2
-rw-r--r--src/core/core.h2
-rw-r--r--src/core/frontend/applets/controller.cpp8
-rw-r--r--src/core/frontend/applets/controller.h8
-rw-r--r--src/core/frontend/input.h3
-rw-r--r--src/core/hle/service/am/applets/applets.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h4
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp227
-rw-r--r--src/core/hle/service/hid/controllers/npad.h6
-rw-r--r--src/core/hle/service/hid/hid.cpp29
-rw-r--r--src/core/hle/service/hid/hid.h2
-rw-r--r--src/input_common/sdl/sdl_impl.cpp39
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp8
-rw-r--r--src/yuzu/game_list.cpp5
-rw-r--r--src/yuzu/game_list_p.h2
18 files changed, 244 insertions, 109 deletions
diff --git a/.ci/yuzu-patreon-step2.yml b/.ci/yuzu-patreon-step2.yml
index 41eccd973..3f338e2a0 100644
--- a/.ci/yuzu-patreon-step2.yml
+++ b/.ci/yuzu-patreon-step2.yml
@@ -9,6 +9,7 @@ stages:
displayName: 'build'
jobs:
- job: build
+ timeoutInMinutes: 120
displayName: 'windows-msvc'
pool:
vmImage: windows-2019
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp
index 3afbdb898..7a20e95b7 100644
--- a/src/common/wall_clock.cpp
+++ b/src/common/wall_clock.cpp
@@ -15,7 +15,7 @@ namespace Common {
using base_timer = std::chrono::steady_clock;
using base_time_point = std::chrono::time_point<base_timer>;
-class StandardWallClock : public WallClock {
+class StandardWallClock final : public WallClock {
public:
StandardWallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency)
: WallClock(emulated_cpu_frequency, emulated_clock_frequency, false) {
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h
index 5db30083d..bc7adfbf8 100644
--- a/src/common/wall_clock.h
+++ b/src/common/wall_clock.h
@@ -13,6 +13,8 @@ namespace Common {
class WallClock {
public:
+ virtual ~WallClock() = default;
+
/// Returns current wall time in nanoseconds
[[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0;
diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h
index 891a3bbfd..7c503df26 100644
--- a/src/common/x64/native_clock.h
+++ b/src/common/x64/native_clock.h
@@ -12,7 +12,7 @@
namespace Common {
namespace X64 {
-class NativeClock : public WallClock {
+class NativeClock final : public WallClock {
public:
NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, u64 rtsc_frequency);
diff --git a/src/core/core.h b/src/core/core.h
index 83ded63a5..27efe30bb 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -120,7 +120,7 @@ public:
* Gets the instance of the System singleton class.
* @returns Reference to the instance of the System singleton class.
*/
- static System& GetInstance() {
+ [[deprecated("Use of the global system instance is deprecated")]] static System& GetInstance() {
return s_instance;
}
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp
index 4505da758..c5d65f2d0 100644
--- a/src/core/frontend/applets/controller.cpp
+++ b/src/core/frontend/applets/controller.cpp
@@ -4,7 +4,6 @@
#include "common/assert.h"
#include "common/logging/log.h"
-#include "core/core.h"
#include "core/frontend/applets/controller.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/hid.h"
@@ -14,6 +13,9 @@ namespace Core::Frontend {
ControllerApplet::~ControllerApplet() = default;
+DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& service_manager_)
+ : service_manager{service_manager_} {}
+
DefaultControllerApplet::~DefaultControllerApplet() = default;
void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback,
@@ -21,9 +23,7 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
auto& npad =
- Core::System::GetInstance()
- .ServiceManager()
- .GetService<Service::HID::Hid>("hid")
+ service_manager.GetService<Service::HID::Hid>("hid")
->GetAppletResource()
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h
index a227f15cd..3e49cdbb9 100644
--- a/src/core/frontend/applets/controller.h
+++ b/src/core/frontend/applets/controller.h
@@ -8,6 +8,10 @@
#include "common/common_types.h"
+namespace Service::SM {
+class ServiceManager;
+}
+
namespace Core::Frontend {
using BorderColor = std::array<u8, 4>;
@@ -39,10 +43,14 @@ public:
class DefaultControllerApplet final : public ControllerApplet {
public:
+ explicit DefaultControllerApplet(Service::SM::ServiceManager& service_manager_);
~DefaultControllerApplet() override;
void ReconfigureControllers(std::function<void()> callback,
ControllerParameters parameters) const override;
+
+private:
+ Service::SM::ServiceManager& service_manager;
};
} // namespace Core::Frontend
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h
index 9da0d2829..277b70e53 100644
--- a/src/core/frontend/input.h
+++ b/src/core/frontend/input.h
@@ -33,6 +33,9 @@ public:
virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const {
return {};
}
+ virtual bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const {
+ return {};
+ }
};
/// An abstract class template for a factory that can create input devices.
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 4e0800f9a..2b626bb40 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -206,7 +206,8 @@ void AppletManager::SetDefaultAppletFrontendSet() {
void AppletManager::SetDefaultAppletsIfMissing() {
if (frontend.controller == nullptr) {
- frontend.controller = std::make_unique<Core::Frontend::DefaultControllerApplet>();
+ frontend.controller =
+ std::make_unique<Core::Frontend::DefaultControllerApplet>(system.ServiceManager());
}
if (frontend.e_commerce == nullptr) {
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
index 8bc69c372..f47a9e61c 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -31,6 +31,10 @@ public:
virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) = 0;
+ // When the controller is requesting a motion update for the shared memory
+ virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t size) {}
+
// Called when input devices should be loaded
virtual void OnLoadInputDevices() = 0;
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 620386cd1..fb007767d 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -365,6 +365,135 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
}
const u32 npad_index = static_cast<u32>(i);
+ RequestPadStateUpdate(npad_index);
+ auto& pad_state = npad_pad_states[npad_index];
+
+ auto& main_controller =
+ npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
+ auto& handheld_entry =
+ npad.handheld_states.npad[npad.handheld_states.common.last_entry_index];
+ auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index];
+ auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index];
+ auto& right_entry =
+ npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index];
+ auto& pokeball_entry =
+ npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index];
+ auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
+
+ libnx_entry.connection_status.raw = 0;
+ libnx_entry.connection_status.IsConnected.Assign(1);
+ auto& full_sixaxis_entry =
+ npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index];
+ auto& handheld_sixaxis_entry =
+ npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index];
+ auto& dual_left_sixaxis_entry =
+ npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index];
+ auto& dual_right_sixaxis_entry =
+ npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index];
+ auto& left_sixaxis_entry =
+ npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index];
+ auto& right_sixaxis_entry =
+ npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index];
+
+ switch (controller_type) {
+ case NPadControllerType::None:
+ UNREACHABLE();
+ break;
+ case NPadControllerType::ProController:
+ main_controller.connection_status.raw = 0;
+ main_controller.connection_status.IsConnected.Assign(1);
+ main_controller.connection_status.IsWired.Assign(1);
+ main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
+ main_controller.pad.l_stick = pad_state.l_stick;
+ main_controller.pad.r_stick = pad_state.r_stick;
+
+ libnx_entry.connection_status.IsWired.Assign(1);
+ break;
+ case NPadControllerType::Handheld:
+ handheld_entry.connection_status.raw = 0;
+ handheld_entry.connection_status.IsConnected.Assign(1);
+ handheld_entry.connection_status.IsWired.Assign(1);
+ handheld_entry.connection_status.IsLeftJoyConnected.Assign(1);
+ handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
+ handheld_entry.connection_status.IsLeftJoyWired.Assign(1);
+ handheld_entry.connection_status.IsRightJoyWired.Assign(1);
+ handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+ handheld_entry.pad.l_stick = pad_state.l_stick;
+ handheld_entry.pad.r_stick = pad_state.r_stick;
+
+ libnx_entry.connection_status.IsWired.Assign(1);
+ libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
+ libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
+ libnx_entry.connection_status.IsLeftJoyWired.Assign(1);
+ libnx_entry.connection_status.IsRightJoyWired.Assign(1);
+ break;
+ case NPadControllerType::JoyDual:
+ dual_entry.connection_status.raw = 0;
+ dual_entry.connection_status.IsConnected.Assign(1);
+ dual_entry.connection_status.IsLeftJoyConnected.Assign(1);
+ dual_entry.connection_status.IsRightJoyConnected.Assign(1);
+ dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+ dual_entry.pad.l_stick = pad_state.l_stick;
+ dual_entry.pad.r_stick = pad_state.r_stick;
+
+ libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
+ libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
+ break;
+ case NPadControllerType::JoyLeft:
+ left_entry.connection_status.raw = 0;
+ left_entry.connection_status.IsConnected.Assign(1);
+ left_entry.connection_status.IsLeftJoyConnected.Assign(1);
+ left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+ left_entry.pad.l_stick = pad_state.l_stick;
+ left_entry.pad.r_stick = pad_state.r_stick;
+
+ libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
+ break;
+ case NPadControllerType::JoyRight:
+ right_entry.connection_status.raw = 0;
+ right_entry.connection_status.IsConnected.Assign(1);
+ right_entry.connection_status.IsRightJoyConnected.Assign(1);
+ right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+ right_entry.pad.l_stick = pad_state.l_stick;
+ right_entry.pad.r_stick = pad_state.r_stick;
+
+ libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
+ break;
+ case NPadControllerType::Pokeball:
+ pokeball_entry.connection_status.raw = 0;
+ pokeball_entry.connection_status.IsConnected.Assign(1);
+ pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+ pokeball_entry.pad.l_stick = pad_state.l_stick;
+ pokeball_entry.pad.r_stick = pad_state.r_stick;
+ break;
+ }
+
+ // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
+ // any controllers.
+ libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+ libnx_entry.pad.l_stick = pad_state.l_stick;
+ libnx_entry.pad.r_stick = pad_state.r_stick;
+
+ press_state |= static_cast<u32>(pad_state.pad_states.raw);
+ }
+ std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
+ shared_memory_entries.size() * sizeof(NPadEntry));
+}
+
+void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t data_len) {
+ if (!IsControllerActivated()) {
+ return;
+ }
+ for (std::size_t i = 0; i < shared_memory_entries.size(); i++) {
+ auto& npad = shared_memory_entries[i];
+
+ const auto& controller_type = connected_controllers[i].type;
+
+ if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
+ continue;
+ }
+
const std::array<SixAxisGeneric*, 6> controller_sixaxes{
&npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left,
&npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right,
@@ -403,9 +532,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
}
}
- RequestPadStateUpdate(npad_index);
- auto& pad_state = npad_pad_states[npad_index];
-
auto& main_controller =
npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
auto& handheld_entry =
@@ -418,8 +544,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index];
auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
- libnx_entry.connection_status.raw = 0;
- libnx_entry.connection_status.IsConnected.Assign(1);
auto& full_sixaxis_entry =
npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index];
auto& handheld_sixaxis_entry =
@@ -438,15 +562,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
UNREACHABLE();
break;
case NPadControllerType::ProController:
- main_controller.connection_status.raw = 0;
- main_controller.connection_status.IsConnected.Assign(1);
- main_controller.connection_status.IsWired.Assign(1);
- main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
- main_controller.pad.l_stick = pad_state.l_stick;
- main_controller.pad.r_stick = pad_state.r_stick;
-
- libnx_entry.connection_status.IsWired.Assign(1);
-
if (sixaxis_sensors_enabled && motions[i][0]) {
full_sixaxis_entry.accel = motion_devices[0].accel;
full_sixaxis_entry.gyro = motion_devices[0].gyro;
@@ -455,23 +570,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
}
break;
case NPadControllerType::Handheld:
- handheld_entry.connection_status.raw = 0;
- handheld_entry.connection_status.IsConnected.Assign(1);
- handheld_entry.connection_status.IsWired.Assign(1);
- handheld_entry.connection_status.IsLeftJoyConnected.Assign(1);
- handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
- handheld_entry.connection_status.IsLeftJoyWired.Assign(1);
- handheld_entry.connection_status.IsRightJoyWired.Assign(1);
- handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
- handheld_entry.pad.l_stick = pad_state.l_stick;
- handheld_entry.pad.r_stick = pad_state.r_stick;
-
- libnx_entry.connection_status.IsWired.Assign(1);
- libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
- libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
- libnx_entry.connection_status.IsLeftJoyWired.Assign(1);
- libnx_entry.connection_status.IsRightJoyWired.Assign(1);
-
if (sixaxis_sensors_enabled && motions[i][0]) {
handheld_sixaxis_entry.accel = motion_devices[0].accel;
handheld_sixaxis_entry.gyro = motion_devices[0].gyro;
@@ -480,17 +578,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
}
break;
case NPadControllerType::JoyDual:
- dual_entry.connection_status.raw = 0;
- dual_entry.connection_status.IsConnected.Assign(1);
- dual_entry.connection_status.IsLeftJoyConnected.Assign(1);
- dual_entry.connection_status.IsRightJoyConnected.Assign(1);
- dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
- dual_entry.pad.l_stick = pad_state.l_stick;
- dual_entry.pad.r_stick = pad_state.r_stick;
-
- libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
- libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
-
if (sixaxis_sensors_enabled && motions[i][0]) {
// Set motion for the left joycon
dual_left_sixaxis_entry.accel = motion_devices[0].accel;
@@ -507,15 +594,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
}
break;
case NPadControllerType::JoyLeft:
- left_entry.connection_status.raw = 0;
- left_entry.connection_status.IsConnected.Assign(1);
- left_entry.connection_status.IsLeftJoyConnected.Assign(1);
- left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
- left_entry.pad.l_stick = pad_state.l_stick;
- left_entry.pad.r_stick = pad_state.r_stick;
-
- libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
-
if (sixaxis_sensors_enabled && motions[i][0]) {
left_sixaxis_entry.accel = motion_devices[0].accel;
left_sixaxis_entry.gyro = motion_devices[0].gyro;
@@ -524,15 +602,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
}
break;
case NPadControllerType::JoyRight:
- right_entry.connection_status.raw = 0;
- right_entry.connection_status.IsConnected.Assign(1);
- right_entry.connection_status.IsRightJoyConnected.Assign(1);
- right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
- right_entry.pad.l_stick = pad_state.l_stick;
- right_entry.pad.r_stick = pad_state.r_stick;
-
- libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
-
if (sixaxis_sensors_enabled && motions[i][1]) {
right_sixaxis_entry.accel = motion_devices[1].accel;
right_sixaxis_entry.gyro = motion_devices[1].gyro;
@@ -541,21 +610,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
}
break;
case NPadControllerType::Pokeball:
- pokeball_entry.connection_status.raw = 0;
- pokeball_entry.connection_status.IsConnected.Assign(1);
- pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
- pokeball_entry.pad.l_stick = pad_state.l_stick;
- pokeball_entry.pad.r_stick = pad_state.r_stick;
break;
}
-
- // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
- // any controllers.
- libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw;
- libnx_entry.pad.l_stick = pad_state.l_stick;
- libnx_entry.pad.r_stick = pad_state.r_stick;
-
- press_state |= static_cast<u32>(pad_state.pad_states.raw);
}
std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
shared_memory_entries.size() * sizeof(NPadEntry));
@@ -609,20 +665,31 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode)
}
}
-void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
+void Controller_NPad::VibrateController(const std::vector<u32>& controllers,
const std::vector<Vibration>& vibrations) {
- LOG_DEBUG(Service_HID, "(STUBBED) called");
+ LOG_TRACE(Service_HID, "called");
if (!Settings::values.vibration_enabled || !can_controllers_vibrate) {
return;
}
- for (std::size_t i = 0; i < controller_ids.size(); i++) {
- std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i));
- if (connected_controllers[controller_pos].is_connected) {
- // TODO(ogniK): Vibrate the physical controller
+ bool success = true;
+ for (std::size_t i = 0; i < controllers.size(); ++i) {
+ if (!connected_controllers[i].is_connected) {
+ continue;
}
+ using namespace Settings::NativeButton;
+ const auto& button_state = buttons[i];
+ if (button_state[A - BUTTON_HID_BEGIN]) {
+ if (button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay(
+ vibrations[0].amp_high, vibrations[0].amp_low, vibrations[0].freq_high,
+ vibrations[0].freq_low)) {
+ success = false;
+ }
+ }
+ }
+ if (success) {
+ last_processed_vibration = vibrations.back();
}
- last_processed_vibration = vibrations.back();
}
Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 654d97c3f..e65277c7b 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -32,6 +32,10 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
+ // When the controller is requesting a motion update for the shared memory
+ void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t size) override;
+
// Called when input devices should be loaded
void OnLoadInputDevices() override;
@@ -121,7 +125,7 @@ public:
void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode);
- void VibrateController(const std::vector<u32>& controller_ids,
+ void VibrateController(const std::vector<u32>& controllers,
const std::vector<Vibration>& vibrations);
Vibration GetLastVibration() const;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 6bb79622d..001427fd8 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -40,7 +40,8 @@ namespace Service::HID {
// Updating period for each HID device.
// HID is polled every 15ms, this value was derived from
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet
-constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz)
+constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz)
+constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz)
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
IAppletResource::IAppletResource(Core::System& system)
@@ -79,10 +80,14 @@ IAppletResource::IAppletResource(Core::System& system)
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
UpdateControllers(user_data, ns_late);
});
-
- // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
+ motion_update_event = Core::Timing::CreateEvent(
+ "HID::MotionPadCallback",
+ [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ UpdateMotion(user_data, ns_late);
+ });
system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event);
+ system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event);
ReloadInputDevices();
}
@@ -122,6 +127,16 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
}
+void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ auto& core_timing = system.CoreTiming();
+
+ for (const auto& controller : controllers) {
+ controller->OnMotionUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
+ }
+
+ core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event);
+}
+
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
public:
IActiveVibrationDeviceList() : ServiceFramework("IActiveVibrationDeviceList") {
@@ -815,18 +830,18 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- const auto controller_id{rp.Pop<u32>()};
+ const auto controller{rp.Pop<u32>()};
const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
- LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id,
+ LOG_DEBUG(Service_HID, "called, controller={}, applet_resource_user_id={}", controller,
applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .VibrateController({controller_id}, {vibration_values});
+ .VibrateController({controller}, {vibration_values});
}
void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
@@ -844,8 +859,6 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
std::memcpy(controller_list.data(), controllers.data(), controllers.size());
std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size());
- std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(),
- [](u32 controller_id) { return controller_id - 3; });
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.VibrateController(controller_list, vibration_list);
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index b7f6f4aa4..1c7d39b67 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -65,10 +65,12 @@ private:
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
+ void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
std::shared_ptr<Kernel::SharedMemory> shared_mem;
std::shared_ptr<Core::Timing::EventType> pad_update_event;
+ std::shared_ptr<Core::Timing::EventType> motion_update_event;
Core::System& system;
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index a9e676f4b..27a96c18b 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -5,6 +5,7 @@
#include <algorithm>
#include <array>
#include <atomic>
+#include <chrono>
#include <cmath>
#include <functional>
#include <mutex>
@@ -78,6 +79,33 @@ public:
return state.axes.at(axis) / (32767.0f * range);
}
+ bool RumblePlay(f32 amp_low, f32 amp_high, int time) {
+ const u16 raw_amp_low = static_cast<u16>(amp_low * 0xFFFF);
+ const u16 raw_amp_high = static_cast<u16>(amp_high * 0xFFFF);
+ // Lower drastically the number of state changes
+ if (raw_amp_low >> 11 == last_state_rumble_low >> 11 &&
+ raw_amp_high >> 11 == last_state_rumble_high >> 11) {
+ if (raw_amp_low + raw_amp_high != 0 ||
+ last_state_rumble_low + last_state_rumble_high == 0) {
+ return false;
+ }
+ }
+ // Don't change state if last vibration was < 20ms
+ const auto now = std::chrono::system_clock::now();
+ if (std::chrono::duration_cast<std::chrono::milliseconds>(now - last_vibration) <
+ std::chrono::milliseconds(20)) {
+ return raw_amp_low + raw_amp_high == 0;
+ }
+
+ last_vibration = now;
+ last_state_rumble_low = raw_amp_low;
+ last_state_rumble_high = raw_amp_high;
+ if (sdl_joystick) {
+ SDL_JoystickRumble(sdl_joystick.get(), raw_amp_low, raw_amp_high, time);
+ }
+ return false;
+ }
+
std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const {
float x = GetAxis(axis_x, range);
float y = GetAxis(axis_y, range);
@@ -139,6 +167,9 @@ private:
} state;
std::string guid;
int port;
+ u16 last_state_rumble_high;
+ u16 last_state_rumble_low;
+ std::chrono::time_point<std::chrono::system_clock> last_vibration;
std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
mutable std::mutex mutex;
@@ -207,7 +238,7 @@ void SDLState::InitJoystick(int joystick_index) {
sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
}
if (!sdl_joystick) {
- LOG_ERROR(Input, "failed to open joystick {}", joystick_index);
+ LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
return;
}
const std::string guid = GetGUID(sdl_joystick);
@@ -303,6 +334,12 @@ public:
return joystick->GetButton(button);
}
+ bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const override {
+ const f32 new_amp_low = pow(amp_low, 0.5f) * (3.0f - 2.0f * pow(amp_low, 0.15f));
+ const f32 new_amp_high = pow(amp_high, 0.5f) * (3.0f - 2.0f * pow(amp_high, 0.15f));
+ return joystick->RumblePlay(new_amp_low, new_amp_high, 250);
+ }
+
private:
std::shared_ptr<SDLJoystick> joystick;
int button;
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
index 05e31f1de..3d8d3213d 100644
--- a/src/video_core/renderer_vulkan/vk_device.cpp
+++ b/src/video_core/renderer_vulkan/vk_device.cpp
@@ -388,14 +388,6 @@ bool VKDevice::Create() {
CollectTelemetryParameters();
- if (ext_extended_dynamic_state && driver_id == VK_DRIVER_ID_AMD_PROPRIETARY_KHR) {
- // AMD's proprietary driver supports VK_EXT_extended_dynamic_state but the <stride> field
- // seems to be bugged. Blacklisting it for now.
- LOG_WARNING(Render_Vulkan,
- "Blacklisting AMD proprietary from VK_EXT_extended_dynamic_state");
- ext_extended_dynamic_state = false;
- }
-
graphics_queue = logical.GetQueue(graphics_family);
present_queue = logical.GetQueue(present_family);
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index a9738e298..70d865112 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -25,7 +25,8 @@
#include "yuzu/main.h"
#include "yuzu/uisettings.h"
-GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) : gamelist{gamelist} {}
+GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist, QObject* parent)
+ : QObject(parent), gamelist{gamelist} {}
// EventFilter in order to process systemkeys while editing the searchfield
bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) {
@@ -116,7 +117,7 @@ void GameListSearchField::setFocus() {
}
GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
- auto* const key_release_eater = new KeyReleaseEater(parent);
+ auto* const key_release_eater = new KeyReleaseEater(parent, this);
layout_filter = new QHBoxLayout;
layout_filter->setMargin(8);
label_filter = new QLabel;
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index 92779a9c7..248855aff 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -330,7 +330,7 @@ public:
private:
class KeyReleaseEater : public QObject {
public:
- explicit KeyReleaseEater(GameList* gamelist);
+ explicit KeyReleaseEater(GameList* gamelist, QObject* parent = nullptr);
private:
GameList* gamelist = nullptr;