summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/input_common/CMakeLists.txt2
-rw-r--r--src/input_common/main.cpp4
-rw-r--r--src/input_common/motion_from_button.cpp34
-rw-r--r--src/input_common/motion_from_button.h25
-rw-r--r--src/input_common/motion_input.cpp140
-rw-r--r--src/input_common/motion_input.h5
-rw-r--r--src/input_common/sdl/sdl_impl.cpp190
-rw-r--r--src/input_common/sdl/sdl_impl.h2
-rw-r--r--src/input_common/udp/client.cpp8
-rw-r--r--src/video_core/CMakeLists.txt9
-rw-r--r--src/video_core/engines/maxwell_dma.cpp2
-rw-r--r--src/video_core/engines/shader_header.h13
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp1
-rw-r--r--src/video_core/renderer_vulkan/wrapper.cpp48
14 files changed, 446 insertions, 37 deletions
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 09361e37e..c84685214 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -7,6 +7,8 @@ add_library(input_common STATIC
7 main.h 7 main.h
8 motion_emu.cpp 8 motion_emu.cpp
9 motion_emu.h 9 motion_emu.h
10 motion_from_button.cpp
11 motion_from_button.h
10 motion_input.cpp 12 motion_input.cpp
11 motion_input.h 13 motion_input.h
12 settings.cpp 14 settings.cpp
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 8da829132..3d97d95f7 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -11,6 +11,7 @@
11#include "input_common/keyboard.h" 11#include "input_common/keyboard.h"
12#include "input_common/main.h" 12#include "input_common/main.h"
13#include "input_common/motion_emu.h" 13#include "input_common/motion_emu.h"
14#include "input_common/motion_from_button.h"
14#include "input_common/touch_from_button.h" 15#include "input_common/touch_from_button.h"
15#include "input_common/udp/client.h" 16#include "input_common/udp/client.h"
16#include "input_common/udp/udp.h" 17#include "input_common/udp/udp.h"
@@ -32,6 +33,8 @@ struct InputSubsystem::Impl {
32 Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard); 33 Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
33 Input::RegisterFactory<Input::AnalogDevice>("analog_from_button", 34 Input::RegisterFactory<Input::AnalogDevice>("analog_from_button",
34 std::make_shared<AnalogFromButton>()); 35 std::make_shared<AnalogFromButton>());
36 Input::RegisterFactory<Input::MotionDevice>("keyboard",
37 std::make_shared<MotionFromButton>());
35 motion_emu = std::make_shared<MotionEmu>(); 38 motion_emu = std::make_shared<MotionEmu>();
36 Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu); 39 Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu);
37 Input::RegisterFactory<Input::TouchDevice>("touch_from_button", 40 Input::RegisterFactory<Input::TouchDevice>("touch_from_button",
@@ -50,6 +53,7 @@ struct InputSubsystem::Impl {
50 53
51 void Shutdown() { 54 void Shutdown() {
52 Input::UnregisterFactory<Input::ButtonDevice>("keyboard"); 55 Input::UnregisterFactory<Input::ButtonDevice>("keyboard");
56 Input::UnregisterFactory<Input::MotionDevice>("keyboard");
53 keyboard.reset(); 57 keyboard.reset();
54 Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button"); 58 Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
55 Input::UnregisterFactory<Input::MotionDevice>("motion_emu"); 59 Input::UnregisterFactory<Input::MotionDevice>("motion_emu");
diff --git a/src/input_common/motion_from_button.cpp b/src/input_common/motion_from_button.cpp
new file mode 100644
index 000000000..9d459f963
--- /dev/null
+++ b/src/input_common/motion_from_button.cpp
@@ -0,0 +1,34 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "input_common/motion_from_button.h"
6#include "input_common/motion_input.h"
7
8namespace InputCommon {
9
10class MotionKey final : public Input::MotionDevice {
11public:
12 using Button = std::unique_ptr<Input::ButtonDevice>;
13
14 MotionKey(Button key_) : key(std::move(key_)) {}
15
16 Input::MotionStatus GetStatus() const override {
17
18 if (key->GetStatus()) {
19 return motion.GetRandomMotion(2, 6);
20 }
21 return motion.GetRandomMotion(0, 0);
22 }
23
24private:
25 Button key;
26 InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f};
27};
28
29std::unique_ptr<Input::MotionDevice> MotionFromButton::Create(const Common::ParamPackage& params) {
30 auto key = Input::CreateDevice<Input::ButtonDevice>(params.Serialize());
31 return std::make_unique<MotionKey>(std::move(key));
32}
33
34} // namespace InputCommon
diff --git a/src/input_common/motion_from_button.h b/src/input_common/motion_from_button.h
new file mode 100644
index 000000000..a959046fb
--- /dev/null
+++ b/src/input_common/motion_from_button.h
@@ -0,0 +1,25 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/frontend/input.h"
8
9namespace InputCommon {
10
11/**
12 * An motion device factory that takes a keyboard button and uses it as a random
13 * motion device.
14 */
15class MotionFromButton final : public Input::Factory<Input::MotionDevice> {
16public:
17 /**
18 * Creates an motion device from button devices
19 * @param params contains parameters for creating the device:
20 * - "key": a serialized ParamPackage for creating a button device
21 */
22 std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override;
23};
24
25} // namespace InputCommon
diff --git a/src/input_common/motion_input.cpp b/src/input_common/motion_input.cpp
index 22a849866..e89019723 100644
--- a/src/input_common/motion_input.cpp
+++ b/src/input_common/motion_input.cpp
@@ -2,6 +2,7 @@
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 <random>
5#include "common/math_util.h" 6#include "common/math_util.h"
6#include "input_common/motion_input.h" 7#include "input_common/motion_input.h"
7 8
@@ -16,8 +17,16 @@ void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) {
16 17
17void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) { 18void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
18 gyro = gyroscope - gyro_drift; 19 gyro = gyroscope - gyro_drift;
20
21 // Auto adjust drift to minimize drift
22 if (!IsMoving(0.1f)) {
23 gyro_drift = (gyro_drift * 0.9999f) + (gyroscope * 0.0001f);
24 }
25
19 if (gyro.Length2() < gyro_threshold) { 26 if (gyro.Length2() < gyro_threshold) {
20 gyro = {}; 27 gyro = {};
28 } else {
29 only_accelerometer = false;
21 } 30 }
22} 31}
23 32
@@ -68,7 +77,7 @@ void MotionInput::UpdateOrientation(u64 elapsed_time) {
68 f32 q4 = quat.xyz[2]; 77 f32 q4 = quat.xyz[2];
69 const f32 sample_period = elapsed_time / 1000000.0f; 78 const f32 sample_period = elapsed_time / 1000000.0f;
70 79
71 // ignore invalid elapsed time 80 // Ignore invalid elapsed time
72 if (sample_period > 0.1f) { 81 if (sample_period > 0.1f) {
73 return; 82 return;
74 } 83 }
@@ -80,6 +89,13 @@ void MotionInput::UpdateOrientation(u64 elapsed_time) {
80 rad_gyro.y = -swap; 89 rad_gyro.y = -swap;
81 rad_gyro.z = -rad_gyro.z; 90 rad_gyro.z = -rad_gyro.z;
82 91
92 // Clear gyro values if there is no gyro present
93 if (only_accelerometer) {
94 rad_gyro.x = 0;
95 rad_gyro.y = 0;
96 rad_gyro.z = 0;
97 }
98
83 // Ignore drift correction if acceleration is not reliable 99 // Ignore drift correction if acceleration is not reliable
84 if (accel.Length() >= 0.75f && accel.Length() <= 1.25f) { 100 if (accel.Length() >= 0.75f && accel.Length() <= 1.25f) {
85 const f32 ax = -normal_accel.x; 101 const f32 ax = -normal_accel.x;
@@ -92,8 +108,11 @@ void MotionInput::UpdateOrientation(u64 elapsed_time) {
92 const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4; 108 const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
93 109
94 // Error is cross product between estimated direction and measured direction of gravity 110 // Error is cross product between estimated direction and measured direction of gravity
95 const Common::Vec3f new_real_error = {az * vx - ax * vz, ay * vz - az * vy, 111 const Common::Vec3f new_real_error = {
96 ax * vy - ay * vx}; 112 az * vx - ax * vz,
113 ay * vz - az * vy,
114 ax * vy - ay * vx,
115 };
97 116
98 derivative_error = new_real_error - real_error; 117 derivative_error = new_real_error - real_error;
99 real_error = new_real_error; 118 real_error = new_real_error;
@@ -106,9 +125,22 @@ void MotionInput::UpdateOrientation(u64 elapsed_time) {
106 } 125 }
107 126
108 // Apply feedback terms 127 // Apply feedback terms
109 rad_gyro += kp * real_error; 128 if (!only_accelerometer) {
110 rad_gyro += ki * integral_error; 129 rad_gyro += kp * real_error;
111 rad_gyro += kd * derivative_error; 130 rad_gyro += ki * integral_error;
131 rad_gyro += kd * derivative_error;
132 } else {
133 // Give more weight to acelerometer values to compensate for the lack of gyro
134 rad_gyro += 35.0f * kp * real_error;
135 rad_gyro += 10.0f * ki * integral_error;
136 rad_gyro += 10.0f * kd * derivative_error;
137
138 // Emulate gyro values for games that need them
139 gyro.x = -rad_gyro.y;
140 gyro.y = rad_gyro.x;
141 gyro.z = -rad_gyro.z;
142 UpdateRotation(elapsed_time);
143 }
112 } 144 }
113 145
114 const f32 gx = rad_gyro.y; 146 const f32 gx = rad_gyro.y;
@@ -159,18 +191,49 @@ Common::Vec3f MotionInput::GetRotations() const {
159 return rotations; 191 return rotations;
160} 192}
161 193
194Input::MotionStatus MotionInput::GetMotion() const {
195 const Common::Vec3f gyroscope = GetGyroscope();
196 const Common::Vec3f accelerometer = GetAcceleration();
197 const Common::Vec3f rotation = GetRotations();
198 const std::array<Common::Vec3f, 3> orientation = GetOrientation();
199 return {accelerometer, gyroscope, rotation, orientation};
200}
201
202Input::MotionStatus MotionInput::GetRandomMotion(int accel_magnitude, int gyro_magnitude) const {
203 std::random_device device;
204 std::mt19937 gen(device());
205 std::uniform_int_distribution<s16> distribution(-1000, 1000);
206 const Common::Vec3f gyroscope = {
207 distribution(gen) * 0.001f,
208 distribution(gen) * 0.001f,
209 distribution(gen) * 0.001f,
210 };
211 const Common::Vec3f accelerometer = {
212 distribution(gen) * 0.001f,
213 distribution(gen) * 0.001f,
214 distribution(gen) * 0.001f,
215 };
216 const Common::Vec3f rotation = {};
217 const std::array<Common::Vec3f, 3> orientation = {
218 Common::Vec3f{1.0f, 0, 0},
219 Common::Vec3f{0, 1.0f, 0},
220 Common::Vec3f{0, 0, 1.0f},
221 };
222 return {accelerometer * accel_magnitude, gyroscope * gyro_magnitude, rotation, orientation};
223}
224
162void MotionInput::ResetOrientation() { 225void MotionInput::ResetOrientation() {
163 if (!reset_enabled) { 226 if (!reset_enabled || only_accelerometer) {
164 return; 227 return;
165 } 228 }
166 if (!IsMoving(0.5f) && accel.z <= -0.9f) { 229 if (!IsMoving(0.5f) && accel.z <= -0.9f) {
167 ++reset_counter; 230 ++reset_counter;
168 if (reset_counter > 900) { 231 if (reset_counter > 900) {
169 // TODO: calculate quaternion from gravity vector
170 quat.w = 0; 232 quat.w = 0;
171 quat.xyz[0] = 0; 233 quat.xyz[0] = 0;
172 quat.xyz[1] = 0; 234 quat.xyz[1] = 0;
173 quat.xyz[2] = -1; 235 quat.xyz[2] = -1;
236 SetOrientationFromAccelerometer();
174 integral_error = {}; 237 integral_error = {};
175 reset_counter = 0; 238 reset_counter = 0;
176 } 239 }
@@ -178,4 +241,65 @@ void MotionInput::ResetOrientation() {
178 reset_counter = 0; 241 reset_counter = 0;
179 } 242 }
180} 243}
244
245void MotionInput::SetOrientationFromAccelerometer() {
246 int iterations = 0;
247 const f32 sample_period = 0.015f;
248
249 const auto normal_accel = accel.Normalized();
250 const f32 ax = -normal_accel.x;
251 const f32 ay = normal_accel.y;
252 const f32 az = -normal_accel.z;
253
254 while (!IsCalibrated(0.01f) && ++iterations < 100) {
255 // Short name local variable for readability
256 f32 q1 = quat.w;
257 f32 q2 = quat.xyz[0];
258 f32 q3 = quat.xyz[1];
259 f32 q4 = quat.xyz[2];
260
261 Common::Vec3f rad_gyro = {};
262 const f32 ax = -normal_accel.x;
263 const f32 ay = normal_accel.y;
264 const f32 az = -normal_accel.z;
265
266 // Estimated direction of gravity
267 const f32 vx = 2.0f * (q2 * q4 - q1 * q3);
268 const f32 vy = 2.0f * (q1 * q2 + q3 * q4);
269 const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
270
271 // Error is cross product between estimated direction and measured direction of gravity
272 const Common::Vec3f new_real_error = {
273 az * vx - ax * vz,
274 ay * vz - az * vy,
275 ax * vy - ay * vx,
276 };
277
278 derivative_error = new_real_error - real_error;
279 real_error = new_real_error;
280
281 rad_gyro += 10.0f * kp * real_error;
282 rad_gyro += 5.0f * ki * integral_error;
283 rad_gyro += 10.0f * kd * derivative_error;
284
285 const f32 gx = rad_gyro.y;
286 const f32 gy = rad_gyro.x;
287 const f32 gz = rad_gyro.z;
288
289 // Integrate rate of change of quaternion
290 const f32 pa = q2;
291 const f32 pb = q3;
292 const f32 pc = q4;
293 q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period);
294 q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period);
295 q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period);
296 q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period);
297
298 quat.w = q1;
299 quat.xyz[0] = q2;
300 quat.xyz[1] = q3;
301 quat.xyz[2] = q4;
302 quat = quat.Normalized();
303 }
304}
181} // namespace InputCommon 305} // namespace InputCommon
diff --git a/src/input_common/motion_input.h b/src/input_common/motion_input.h
index 54b4439d9..6342d0318 100644
--- a/src/input_common/motion_input.h
+++ b/src/input_common/motion_input.h
@@ -7,6 +7,7 @@
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/quaternion.h" 8#include "common/quaternion.h"
9#include "common/vector_math.h" 9#include "common/vector_math.h"
10#include "core/frontend/input.h"
10 11
11namespace InputCommon { 12namespace InputCommon {
12 13
@@ -37,12 +38,15 @@ public:
37 Common::Vec3f GetGyroscope() const; 38 Common::Vec3f GetGyroscope() const;
38 Common::Vec3f GetRotations() const; 39 Common::Vec3f GetRotations() const;
39 Common::Quaternion<f32> GetQuaternion() const; 40 Common::Quaternion<f32> GetQuaternion() const;
41 Input::MotionStatus GetMotion() const;
42 Input::MotionStatus GetRandomMotion(int accel_magnitude, int gyro_magnitude) const;
40 43
41 bool IsMoving(f32 sensitivity) const; 44 bool IsMoving(f32 sensitivity) const;
42 bool IsCalibrated(f32 sensitivity) const; 45 bool IsCalibrated(f32 sensitivity) const;
43 46
44private: 47private:
45 void ResetOrientation(); 48 void ResetOrientation();
49 void SetOrientationFromAccelerometer();
46 50
47 // PID constants 51 // PID constants
48 const f32 kp; 52 const f32 kp;
@@ -63,6 +67,7 @@ private:
63 f32 gyro_threshold = 0.0f; 67 f32 gyro_threshold = 0.0f;
64 u32 reset_counter = 0; 68 u32 reset_counter = 0;
65 bool reset_enabled = true; 69 bool reset_enabled = true;
70 bool only_accelerometer = true;
66}; 71};
67 72
68} // namespace InputCommon 73} // namespace InputCommon
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 27a96c18b..bd480570a 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -22,6 +22,7 @@
22#include "common/param_package.h" 22#include "common/param_package.h"
23#include "common/threadsafe_queue.h" 23#include "common/threadsafe_queue.h"
24#include "core/frontend/input.h" 24#include "core/frontend/input.h"
25#include "input_common/motion_input.h"
25#include "input_common/sdl/sdl_impl.h" 26#include "input_common/sdl/sdl_impl.h"
26#include "input_common/settings.h" 27#include "input_common/settings.h"
27 28
@@ -123,6 +124,10 @@ public:
123 return std::make_tuple(x, y); 124 return std::make_tuple(x, y);
124 } 125 }
125 126
127 const InputCommon::MotionInput& GetMotion() const {
128 return motion;
129 }
130
126 void SetHat(int hat, Uint8 direction) { 131 void SetHat(int hat, Uint8 direction) {
127 std::lock_guard lock{mutex}; 132 std::lock_guard lock{mutex};
128 state.hats.insert_or_assign(hat, direction); 133 state.hats.insert_or_assign(hat, direction);
@@ -173,6 +178,9 @@ private:
173 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; 178 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
174 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; 179 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
175 mutable std::mutex mutex; 180 mutable std::mutex mutex;
181
182 // motion is initalized without PID values as motion input is not aviable for SDL2
183 InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f};
176}; 184};
177 185
178std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { 186std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
@@ -423,6 +431,68 @@ private:
423 const float range; 431 const float range;
424}; 432};
425 433
434class SDLDirectionMotion final : public Input::MotionDevice {
435public:
436 explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
437 : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
438
439 Input::MotionStatus GetStatus() const override {
440 if (joystick->GetHatDirection(hat, direction)) {
441 return joystick->GetMotion().GetRandomMotion(2, 6);
442 }
443 return joystick->GetMotion().GetRandomMotion(0, 0);
444 }
445
446private:
447 std::shared_ptr<SDLJoystick> joystick;
448 int hat;
449 Uint8 direction;
450};
451
452class SDLAxisMotion final : public Input::MotionDevice {
453public:
454 explicit SDLAxisMotion(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
455 bool trigger_if_greater_)
456 : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
457 trigger_if_greater(trigger_if_greater_) {}
458
459 Input::MotionStatus GetStatus() const override {
460 const float axis_value = joystick->GetAxis(axis, 1.0f);
461 bool trigger = axis_value < threshold;
462 if (trigger_if_greater) {
463 trigger = axis_value > threshold;
464 }
465
466 if (trigger) {
467 return joystick->GetMotion().GetRandomMotion(2, 6);
468 }
469 return joystick->GetMotion().GetRandomMotion(0, 0);
470 }
471
472private:
473 std::shared_ptr<SDLJoystick> joystick;
474 int axis;
475 float threshold;
476 bool trigger_if_greater;
477};
478
479class SDLButtonMotion final : public Input::MotionDevice {
480public:
481 explicit SDLButtonMotion(std::shared_ptr<SDLJoystick> joystick_, int button_)
482 : joystick(std::move(joystick_)), button(button_) {}
483
484 Input::MotionStatus GetStatus() const override {
485 if (joystick->GetButton(button)) {
486 return joystick->GetMotion().GetRandomMotion(2, 6);
487 }
488 return joystick->GetMotion().GetRandomMotion(0, 0);
489 }
490
491private:
492 std::shared_ptr<SDLJoystick> joystick;
493 int button;
494};
495
426/// A button device factory that creates button devices from SDL joystick 496/// A button device factory that creates button devices from SDL joystick
427class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> { 497class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
428public: 498public:
@@ -529,12 +599,78 @@ private:
529 SDLState& state; 599 SDLState& state;
530}; 600};
531 601
602/// A motion device factory that creates motion devices from SDL joystick
603class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> {
604public:
605 explicit SDLMotionFactory(SDLState& state_) : state(state_) {}
606 /**
607 * Creates motion device from joystick axes
608 * @param params contains parameters for creating the device:
609 * - "guid": the guid of the joystick to bind
610 * - "port": the nth joystick of the same type
611 */
612 std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override {
613 const std::string guid = params.Get("guid", "0");
614 const int port = params.Get("port", 0);
615
616 auto joystick = state.GetSDLJoystickByGUID(guid, port);
617
618 if (params.Has("hat")) {
619 const int hat = params.Get("hat", 0);
620 const std::string direction_name = params.Get("direction", "");
621 Uint8 direction;
622 if (direction_name == "up") {
623 direction = SDL_HAT_UP;
624 } else if (direction_name == "down") {
625 direction = SDL_HAT_DOWN;
626 } else if (direction_name == "left") {
627 direction = SDL_HAT_LEFT;
628 } else if (direction_name == "right") {
629 direction = SDL_HAT_RIGHT;
630 } else {
631 direction = 0;
632 }
633 // This is necessary so accessing GetHat with hat won't crash
634 joystick->SetHat(hat, SDL_HAT_CENTERED);
635 return std::make_unique<SDLDirectionMotion>(joystick, hat, direction);
636 }
637
638 if (params.Has("axis")) {
639 const int axis = params.Get("axis", 0);
640 const float threshold = params.Get("threshold", 0.5f);
641 const std::string direction_name = params.Get("direction", "");
642 bool trigger_if_greater;
643 if (direction_name == "+") {
644 trigger_if_greater = true;
645 } else if (direction_name == "-") {
646 trigger_if_greater = false;
647 } else {
648 trigger_if_greater = true;
649 LOG_ERROR(Input, "Unknown direction {}", direction_name);
650 }
651 // This is necessary so accessing GetAxis with axis won't crash
652 joystick->SetAxis(axis, 0);
653 return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater);
654 }
655
656 const int button = params.Get("button", 0);
657 // This is necessary so accessing GetButton with button won't crash
658 joystick->SetButton(button, false);
659 return std::make_unique<SDLButtonMotion>(joystick, button);
660 }
661
662private:
663 SDLState& state;
664};
665
532SDLState::SDLState() { 666SDLState::SDLState() {
533 using namespace Input; 667 using namespace Input;
534 analog_factory = std::make_shared<SDLAnalogFactory>(*this); 668 analog_factory = std::make_shared<SDLAnalogFactory>(*this);
535 button_factory = std::make_shared<SDLButtonFactory>(*this); 669 button_factory = std::make_shared<SDLButtonFactory>(*this);
670 motion_factory = std::make_shared<SDLMotionFactory>(*this);
536 RegisterFactory<AnalogDevice>("sdl", analog_factory); 671 RegisterFactory<AnalogDevice>("sdl", analog_factory);
537 RegisterFactory<ButtonDevice>("sdl", button_factory); 672 RegisterFactory<ButtonDevice>("sdl", button_factory);
673 RegisterFactory<MotionDevice>("sdl", motion_factory);
538 674
539 // If the frontend is going to manage the event loop, then we dont start one here 675 // If the frontend is going to manage the event loop, then we dont start one here
540 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK); 676 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK);
@@ -570,6 +706,7 @@ SDLState::~SDLState() {
570 using namespace Input; 706 using namespace Input;
571 UnregisterFactory<ButtonDevice>("sdl"); 707 UnregisterFactory<ButtonDevice>("sdl");
572 UnregisterFactory<AnalogDevice>("sdl"); 708 UnregisterFactory<AnalogDevice>("sdl");
709 UnregisterFactory<MotionDevice>("sdl");
573 710
574 CloseJoysticks(); 711 CloseJoysticks();
575 SDL_DelEventWatch(&SDLEventWatcher, this); 712 SDL_DelEventWatch(&SDLEventWatcher, this);
@@ -681,6 +818,27 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve
681 return {}; 818 return {};
682} 819}
683 820
821Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) {
822 switch (event.type) {
823 case SDL_JOYAXISMOTION: {
824 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
825 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
826 event.jaxis.axis, event.jaxis.value);
827 }
828 case SDL_JOYBUTTONUP: {
829 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
830 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
831 event.jbutton.button);
832 }
833 case SDL_JOYHATMOTION: {
834 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
835 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
836 event.jhat.hat, event.jhat.value);
837 }
838 }
839 return {};
840}
841
684Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid, 842Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
685 const SDL_GameControllerButtonBind& binding) { 843 const SDL_GameControllerButtonBind& binding) {
686 switch (binding.bindType) { 844 switch (binding.bindType) {
@@ -846,6 +1004,35 @@ public:
846 } 1004 }
847}; 1005};
848 1006
1007class SDLMotionPoller final : public SDLPoller {
1008public:
1009 explicit SDLMotionPoller(SDLState& state_) : SDLPoller(state_) {}
1010
1011 Common::ParamPackage GetNextInput() override {
1012 SDL_Event event;
1013 while (state.event_queue.Pop(event)) {
1014 const auto package = FromEvent(event);
1015 if (package) {
1016 return *package;
1017 }
1018 }
1019 return {};
1020 }
1021 [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
1022 switch (event.type) {
1023 case SDL_JOYAXISMOTION:
1024 if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
1025 break;
1026 }
1027 [[fallthrough]];
1028 case SDL_JOYBUTTONUP:
1029 case SDL_JOYHATMOTION:
1030 return {SDLEventToMotionParamPackage(state, event)};
1031 }
1032 return std::nullopt;
1033 }
1034};
1035
849/** 1036/**
850 * Attempts to match the press to a controller joy axis (left/right stick) and if a match 1037 * Attempts to match the press to a controller joy axis (left/right stick) and if a match
851 * isn't found, checks if the event matches anything from SDLButtonPoller and uses that 1038 * isn't found, checks if the event matches anything from SDLButtonPoller and uses that
@@ -937,6 +1124,9 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
937 case InputCommon::Polling::DeviceType::Button: 1124 case InputCommon::Polling::DeviceType::Button:
938 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this)); 1125 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
939 break; 1126 break;
1127 case InputCommon::Polling::DeviceType::Motion:
1128 pollers.emplace_back(std::make_unique<Polling::SDLMotionPoller>(*this));
1129 break;
940 } 1130 }
941 1131
942 return pollers; 1132 return pollers;
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h
index bd19ba61d..b9bb4dc56 100644
--- a/src/input_common/sdl/sdl_impl.h
+++ b/src/input_common/sdl/sdl_impl.h
@@ -21,6 +21,7 @@ namespace InputCommon::SDL {
21 21
22class SDLAnalogFactory; 22class SDLAnalogFactory;
23class SDLButtonFactory; 23class SDLButtonFactory;
24class SDLMotionFactory;
24class SDLJoystick; 25class SDLJoystick;
25 26
26class SDLState : public State { 27class SDLState : public State {
@@ -71,6 +72,7 @@ private:
71 72
72 std::shared_ptr<SDLButtonFactory> button_factory; 73 std::shared_ptr<SDLButtonFactory> button_factory;
73 std::shared_ptr<SDLAnalogFactory> analog_factory; 74 std::shared_ptr<SDLAnalogFactory> analog_factory;
75 std::shared_ptr<SDLMotionFactory> motion_factory;
74 76
75 bool start_thread = false; 77 bool start_thread = false;
76 std::atomic<bool> initialized = false; 78 std::atomic<bool> initialized = false;
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index cf72f6fef..9d0b9f31d 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -219,14 +219,10 @@ void Client::OnPadData(Response::PadData data) {
219 clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f); 219 clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f);
220 clients[client].motion.UpdateRotation(time_difference); 220 clients[client].motion.UpdateRotation(time_difference);
221 clients[client].motion.UpdateOrientation(time_difference); 221 clients[client].motion.UpdateOrientation(time_difference);
222 Common::Vec3f gyroscope = clients[client].motion.GetGyroscope();
223 Common::Vec3f accelerometer = clients[client].motion.GetAcceleration();
224 Common::Vec3f rotation = clients[client].motion.GetRotations();
225 std::array<Common::Vec3f, 3> orientation = clients[client].motion.GetOrientation();
226 222
227 { 223 {
228 std::lock_guard guard(clients[client].status.update_mutex); 224 std::lock_guard guard(clients[client].status.update_mutex);
229 clients[client].status.motion_status = {accelerometer, gyroscope, rotation, orientation}; 225 clients[client].status.motion_status = clients[client].motion.GetMotion();
230 226
231 // TODO: add a setting for "click" touch. Click touch refers to a device that differentiates 227 // TODO: add a setting for "click" touch. Click touch refers to a device that differentiates
232 // between a simple "tap" and a hard press that causes the touch screen to click. 228 // between a simple "tap" and a hard press that causes the touch screen to click.
@@ -250,6 +246,8 @@ void Client::OnPadData(Response::PadData data) {
250 clients[client].status.touch_status = {x, y, is_active}; 246 clients[client].status.touch_status = {x, y, is_active};
251 247
252 if (configuring) { 248 if (configuring) {
249 const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope();
250 const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration();
253 UpdateYuzuSettings(client, accelerometer, gyroscope, is_active); 251 UpdateYuzuSettings(client, accelerometer, gyroscope, is_active);
254 } 252 }
255 } 253 }
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index da9e9fdda..3df54816d 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -273,5 +273,12 @@ endif()
273if (MSVC) 273if (MSVC)
274 target_compile_options(video_core PRIVATE /we4267) 274 target_compile_options(video_core PRIVATE /we4267)
275else() 275else()
276 target_compile_options(video_core PRIVATE -Werror=conversion -Wno-error=sign-conversion -Werror=switch) 276 target_compile_options(video_core PRIVATE
277 -Werror=conversion
278 -Wno-error=sign-conversion
279 -Werror=switch
280 -Werror=unused-variable
281 -Werror=unused-but-set-variable
282 -Werror=class-memaccess
283 )
277endif() 284endif()
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index e88290754..8fa359d0a 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -114,8 +114,6 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
114 const u32 block_depth = src_params.block_size.depth; 114 const u32 block_depth = src_params.block_size.depth;
115 const size_t src_size = 115 const size_t src_size =
116 CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); 116 CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth);
117 const size_t src_layer_size =
118 CalculateSize(true, bytes_per_pixel, width, height, 1, block_height, block_depth);
119 117
120 if (read_buffer.size() < src_size) { 118 if (read_buffer.size() < src_size) {
121 read_buffer.resize(src_size); 119 read_buffer.resize(src_size);
diff --git a/src/video_core/engines/shader_header.h b/src/video_core/engines/shader_header.h
index 72e2a33d5..ceec05459 100644
--- a/src/video_core/engines/shader_header.h
+++ b/src/video_core/engines/shader_header.h
@@ -41,30 +41,30 @@ struct Header {
41 BitField<26, 1, u32> does_load_or_store; 41 BitField<26, 1, u32> does_load_or_store;
42 BitField<27, 1, u32> does_fp64; 42 BitField<27, 1, u32> does_fp64;
43 BitField<28, 4, u32> stream_out_mask; 43 BitField<28, 4, u32> stream_out_mask;
44 } common0{}; 44 } common0;
45 45
46 union { 46 union {
47 BitField<0, 24, u32> shader_local_memory_low_size; 47 BitField<0, 24, u32> shader_local_memory_low_size;
48 BitField<24, 8, u32> per_patch_attribute_count; 48 BitField<24, 8, u32> per_patch_attribute_count;
49 } common1{}; 49 } common1;
50 50
51 union { 51 union {
52 BitField<0, 24, u32> shader_local_memory_high_size; 52 BitField<0, 24, u32> shader_local_memory_high_size;
53 BitField<24, 8, u32> threads_per_input_primitive; 53 BitField<24, 8, u32> threads_per_input_primitive;
54 } common2{}; 54 } common2;
55 55
56 union { 56 union {
57 BitField<0, 24, u32> shader_local_memory_crs_size; 57 BitField<0, 24, u32> shader_local_memory_crs_size;
58 BitField<24, 4, OutputTopology> output_topology; 58 BitField<24, 4, OutputTopology> output_topology;
59 BitField<28, 4, u32> reserved; 59 BitField<28, 4, u32> reserved;
60 } common3{}; 60 } common3;
61 61
62 union { 62 union {
63 BitField<0, 12, u32> max_output_vertices; 63 BitField<0, 12, u32> max_output_vertices;
64 BitField<12, 8, u32> store_req_start; // NOTE: not used by geometry shaders. 64 BitField<12, 8, u32> store_req_start; // NOTE: not used by geometry shaders.
65 BitField<20, 4, u32> reserved; 65 BitField<20, 4, u32> reserved;
66 BitField<24, 8, u32> store_req_end; // NOTE: not used by geometry shaders. 66 BitField<24, 8, u32> store_req_end; // NOTE: not used by geometry shaders.
67 } common4{}; 67 } common4;
68 68
69 union { 69 union {
70 struct { 70 struct {
@@ -145,7 +145,7 @@ struct Header {
145 } 145 }
146 } ps; 146 } ps;
147 147
148 std::array<u32, 0xF> raw{}; 148 std::array<u32, 0xF> raw;
149 }; 149 };
150 150
151 u64 GetLocalMemorySize() const { 151 u64 GetLocalMemorySize() const {
@@ -153,7 +153,6 @@ struct Header {
153 (common2.shader_local_memory_high_size << 24)); 153 (common2.shader_local_memory_high_size << 24));
154 } 154 }
155}; 155};
156
157static_assert(sizeof(Header) == 0x50, "Incorrect structure size"); 156static_assert(sizeof(Header) == 0x50, "Incorrect structure size");
158 157
159} // namespace Tegra::Shader 158} // namespace Tegra::Shader
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index e7d95149f..a94e4f72e 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -193,7 +193,6 @@ bool IsASTCSupported() {
193Device::Device() 193Device::Device()
194 : max_uniform_buffers{BuildMaxUniformBuffers()}, base_bindings{BuildBaseBindings()} { 194 : max_uniform_buffers{BuildMaxUniformBuffers()}, base_bindings{BuildBaseBindings()} {
195 const std::string_view vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR)); 195 const std::string_view vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
196 const std::string_view renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
197 const std::string_view version = reinterpret_cast<const char*>(glGetString(GL_VERSION)); 196 const std::string_view version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
198 const std::vector extensions = GetExtensions(); 197 const std::vector extensions = GetExtensions();
199 198
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
index 1fb14e190..2598440fb 100644
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ b/src/video_core/renderer_vulkan/wrapper.cpp
@@ -6,6 +6,7 @@
6#include <exception> 6#include <exception>
7#include <memory> 7#include <memory>
8#include <optional> 8#include <optional>
9#include <string_view>
9#include <utility> 10#include <utility>
10#include <vector> 11#include <vector>
11 12
@@ -17,21 +18,42 @@ namespace Vulkan::vk {
17 18
18namespace { 19namespace {
19 20
21template <typename Func>
22void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld,
23 Func&& func) {
24 // Calling GetProperties calls Vulkan more than needed. But they are supposed to be cheap
25 // functions.
26 std::stable_sort(devices.begin(), devices.end(),
27 [&dld, &func](VkPhysicalDevice lhs, VkPhysicalDevice rhs) {
28 return func(vk::PhysicalDevice(lhs, dld).GetProperties(),
29 vk::PhysicalDevice(rhs, dld).GetProperties());
30 });
31}
32
33void SortPhysicalDevicesPerVendor(std::vector<VkPhysicalDevice>& devices,
34 const InstanceDispatch& dld,
35 std::initializer_list<u32> vendor_ids) {
36 for (auto it = vendor_ids.end(); it != vendor_ids.begin();) {
37 --it;
38 SortPhysicalDevices(devices, dld, [id = *it](const auto& lhs, const auto& rhs) {
39 return lhs.vendorID == id && rhs.vendorID != id;
40 });
41 }
42}
43
20void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld) { 44void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld) {
21 std::stable_sort(devices.begin(), devices.end(), [&](auto lhs, auto rhs) { 45 // Sort by name, this will set a base and make GPUs with higher numbers appear first
22 // This will call Vulkan more than needed, but these calls are cheap. 46 // (e.g. GTX 1650 will intentionally be listed before a GTX 1080).
23 const auto lhs_properties = vk::PhysicalDevice(lhs, dld).GetProperties(); 47 SortPhysicalDevices(devices, dld, [](const auto& lhs, const auto& rhs) {
24 const auto rhs_properties = vk::PhysicalDevice(rhs, dld).GetProperties(); 48 return std::string_view{lhs.deviceName} > std::string_view{rhs.deviceName};
25 49 });
26 // Prefer discrete GPUs, Nvidia over AMD, AMD over Intel, Intel over the rest. 50 // Prefer discrete over non-discrete
27 const bool preferred = 51 SortPhysicalDevices(devices, dld, [](const auto& lhs, const auto& rhs) {
28 (lhs_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && 52 return lhs.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
29 rhs_properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) || 53 rhs.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
30 (lhs_properties.vendorID == 0x10DE && rhs_properties.vendorID != 0x10DE) ||
31 (lhs_properties.vendorID == 0x1002 && rhs_properties.vendorID != 0x1002) ||
32 (lhs_properties.vendorID == 0x8086 && rhs_properties.vendorID != 0x8086);
33 return !preferred;
34 }); 54 });
55 // Prefer Nvidia over AMD, AMD over Intel, Intel over the rest.
56 SortPhysicalDevicesPerVendor(devices, dld, {0x10DE, 0x1002, 0x8086});
35} 57}
36 58
37template <typename T> 59template <typename T>