summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/math_util.h4
-rw-r--r--src/common/vector_math.h75
-rw-r--r--src/core/CMakeLists.txt14
-rw-r--r--src/core/hle/kernel/kernel.cpp66
-rw-r--r--src/core/hle/service/acc/acc.cpp8
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp10
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp5
-rw-r--r--src/core/hle/service/mii/manager.cpp2
-rw-r--r--src/core/hle/service/nifm/nifm.cpp12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h9
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp14
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h1
-rw-r--r--src/core/hle/service/vi/vi.cpp52
-rw-r--r--src/input_common/CMakeLists.txt29
-rwxr-xr-xsrc/input_common/analog_from_button.cpp18
-rw-r--r--src/input_common/gcadapter/gc_adapter.cpp35
-rw-r--r--src/input_common/gcadapter/gc_adapter.h6
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp48
-rw-r--r--src/input_common/keyboard.cpp5
-rw-r--r--src/input_common/main.cpp4
-rw-r--r--src/input_common/motion_emu.cpp41
-rw-r--r--src/input_common/motion_from_button.cpp2
-rw-r--r--src/input_common/motion_input.cpp38
-rw-r--r--src/input_common/motion_input.h10
-rw-r--r--src/input_common/sdl/sdl_impl.cpp89
-rw-r--r--src/input_common/settings.h2
-rw-r--r--src/input_common/touch_from_button.cpp8
-rw-r--r--src/input_common/udp/client.cpp78
-rw-r--r--src/input_common/udp/client.h18
-rw-r--r--src/input_common/udp/udp.cpp28
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.cpp3
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.h10
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp24
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp97
-rw-r--r--src/video_core/renderer_vulkan/vk_device.h12
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp11
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp12
-rw-r--r--src/video_core/renderer_vulkan/wrapper.cpp23
-rw-r--r--src/video_core/renderer_vulkan/wrapper.h4
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp37
-rw-r--r--src/yuzu/configuration/configure_input_player.h9
-rw-r--r--src/yuzu/configuration/configure_motion_touch.cpp2
47 files changed, 622 insertions, 380 deletions
diff --git a/src/common/math_util.h b/src/common/math_util.h
index 661c056ca..4c38d8040 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -20,8 +20,8 @@ struct Rectangle {
20 20
21 constexpr Rectangle() = default; 21 constexpr Rectangle() = default;
22 22
23 constexpr Rectangle(T left, T top, T right, T bottom) 23 constexpr Rectangle(T left_, T top_, T right_, T bottom_)
24 : left(left), top(top), right(right), bottom(bottom) {} 24 : left(left_), top(top_), right(right_), bottom(bottom_) {}
25 25
26 [[nodiscard]] T GetWidth() const { 26 [[nodiscard]] T GetWidth() const {
27 if constexpr (std::is_floating_point_v<T>) { 27 if constexpr (std::is_floating_point_v<T>) {
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index 2a0fcf541..22dba3c2d 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -87,7 +87,13 @@ public:
87 87
88 template <typename V> 88 template <typename V>
89 [[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const { 89 [[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
90 return {x * f, y * f}; 90 using TV = decltype(T{} * V{});
91 using C = std::common_type_t<T, V>;
92
93 return {
94 static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
95 static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
96 };
91 } 97 }
92 98
93 template <typename V> 99 template <typename V>
@@ -98,7 +104,13 @@ public:
98 104
99 template <typename V> 105 template <typename V>
100 [[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const { 106 [[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
101 return {x / f, y / f}; 107 using TV = decltype(T{} / V{});
108 using C = std::common_type_t<T, V>;
109
110 return {
111 static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
112 static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
113 };
102 } 114 }
103 115
104 template <typename V> 116 template <typename V>
@@ -168,7 +180,10 @@ public:
168 180
169template <typename T, typename V> 181template <typename T, typename V>
170[[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) { 182[[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
171 return Vec2<T>(f * vec.x, f * vec.y); 183 using C = std::common_type_t<T, V>;
184
185 return Vec2<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)),
186 static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)));
172} 187}
173 188
174using Vec2f = Vec2<float>; 189using Vec2f = Vec2<float>;
@@ -237,7 +252,14 @@ public:
237 252
238 template <typename V> 253 template <typename V>
239 [[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const { 254 [[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
240 return {x * f, y * f, z * f}; 255 using TV = decltype(T{} * V{});
256 using C = std::common_type_t<T, V>;
257
258 return {
259 static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
260 static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
261 static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)),
262 };
241 } 263 }
242 264
243 template <typename V> 265 template <typename V>
@@ -247,7 +269,14 @@ public:
247 } 269 }
248 template <typename V> 270 template <typename V>
249 [[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const { 271 [[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
250 return {x / f, y / f, z / f}; 272 using TV = decltype(T{} / V{});
273 using C = std::common_type_t<T, V>;
274
275 return {
276 static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
277 static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
278 static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)),
279 };
251 } 280 }
252 281
253 template <typename V> 282 template <typename V>
@@ -367,7 +396,11 @@ public:
367 396
368template <typename T, typename V> 397template <typename T, typename V>
369[[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) { 398[[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
370 return Vec3<T>(f * vec.x, f * vec.y, f * vec.z); 399 using C = std::common_type_t<T, V>;
400
401 return Vec3<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)),
402 static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)),
403 static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.z)));
371} 404}
372 405
373template <> 406template <>
@@ -446,7 +479,15 @@ public:
446 479
447 template <typename V> 480 template <typename V>
448 [[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const { 481 [[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
449 return {x * f, y * f, z * f, w * f}; 482 using TV = decltype(T{} * V{});
483 using C = std::common_type_t<T, V>;
484
485 return {
486 static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
487 static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
488 static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)),
489 static_cast<TV>(static_cast<C>(w) * static_cast<C>(f)),
490 };
450 } 491 }
451 492
452 template <typename V> 493 template <typename V>
@@ -457,7 +498,15 @@ public:
457 498
458 template <typename V> 499 template <typename V>
459 [[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const { 500 [[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
460 return {x / f, y / f, z / f, w / f}; 501 using TV = decltype(T{} / V{});
502 using C = std::common_type_t<T, V>;
503
504 return {
505 static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
506 static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
507 static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)),
508 static_cast<TV>(static_cast<C>(w) / static_cast<C>(f)),
509 };
461 } 510 }
462 511
463 template <typename V> 512 template <typename V>
@@ -582,7 +631,15 @@ public:
582 631
583template <typename T, typename V> 632template <typename T, typename V>
584[[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) { 633[[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
585 return {f * vec.x, f * vec.y, f * vec.z, f * vec.w}; 634 using TV = decltype(V{} * T{});
635 using C = std::common_type_t<T, V>;
636
637 return {
638 static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.x)),
639 static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.y)),
640 static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.z)),
641 static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.w)),
642 };
586} 643}
587 644
588using Vec4f = Vec4<float>; 645using Vec4f = Vec4<float>;
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index f910e438f..9dc320f53 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -1,9 +1,3 @@
1if (YUZU_ENABLE_BOXCAT)
2 set(BCAT_BOXCAT_ADDITIONAL_SOURCES hle/service/bcat/backend/boxcat.cpp hle/service/bcat/backend/boxcat.h)
3else()
4 set(BCAT_BOXCAT_ADDITIONAL_SOURCES)
5endif()
6
7add_library(core STATIC 1add_library(core STATIC
8 arm/arm_interface.h 2 arm/arm_interface.h
9 arm/arm_interface.cpp 3 arm/arm_interface.cpp
@@ -303,7 +297,6 @@ add_library(core STATIC
303 hle/service/audio/hwopus.h 297 hle/service/audio/hwopus.h
304 hle/service/bcat/backend/backend.cpp 298 hle/service/bcat/backend/backend.cpp
305 hle/service/bcat/backend/backend.h 299 hle/service/bcat/backend/backend.h
306 ${BCAT_BOXCAT_ADDITIONAL_SOURCES}
307 hle/service/bcat/bcat.cpp 300 hle/service/bcat/bcat.cpp
308 hle/service/bcat/bcat.h 301 hle/service/bcat/bcat.h
309 hle/service/bcat/module.cpp 302 hle/service/bcat/module.cpp
@@ -608,6 +601,13 @@ add_library(core STATIC
608 tools/freezer.h 601 tools/freezer.h
609) 602)
610 603
604if (YUZU_ENABLE_BOXCAT)
605 target_sources(core PRIVATE
606 hle/service/bcat/backend/boxcat.cpp
607 hle/service/bcat/backend/boxcat.h
608 )
609endif()
610
611if (MSVC) 611if (MSVC)
612 target_compile_options(core PRIVATE 612 target_compile_options(core PRIVATE
613 # 'expression' : signed/unsigned mismatch 613 # 'expression' : signed/unsigned mismatch
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index c04b23eff..ed30854ee 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -7,7 +7,6 @@
7#include <bitset> 7#include <bitset>
8#include <functional> 8#include <functional>
9#include <memory> 9#include <memory>
10#include <mutex>
11#include <thread> 10#include <thread>
12#include <unordered_map> 11#include <unordered_map>
13#include <utility> 12#include <utility>
@@ -107,7 +106,11 @@ struct KernelCore::Impl {
107 cores.clear(); 106 cores.clear();
108 107
109 exclusive_monitor.reset(); 108 exclusive_monitor.reset();
110 host_thread_ids.clear(); 109
110 num_host_threads = 0;
111 std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(),
112 std::thread::id{});
113 std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0);
111 } 114 }
112 115
113 void InitializePhysicalCores() { 116 void InitializePhysicalCores() {
@@ -177,54 +180,56 @@ struct KernelCore::Impl {
177 180
178 void MakeCurrentProcess(Process* process) { 181 void MakeCurrentProcess(Process* process) {
179 current_process = process; 182 current_process = process;
180
181 if (process == nullptr) { 183 if (process == nullptr) {
182 return; 184 return;
183 } 185 }
184 186 const u32 core_id = GetCurrentHostThreadID();
185 u32 core_id = GetCurrentHostThreadID();
186 if (core_id < Core::Hardware::NUM_CPU_CORES) { 187 if (core_id < Core::Hardware::NUM_CPU_CORES) {
187 system.Memory().SetCurrentPageTable(*process, core_id); 188 system.Memory().SetCurrentPageTable(*process, core_id);
188 } 189 }
189 } 190 }
190 191
191 void RegisterCoreThread(std::size_t core_id) { 192 void RegisterCoreThread(std::size_t core_id) {
192 std::unique_lock lock{register_thread_mutex}; 193 const std::thread::id this_id = std::this_thread::get_id();
193 if (!is_multicore) { 194 if (!is_multicore) {
194 single_core_thread_id = std::this_thread::get_id(); 195 single_core_thread_id = this_id;
195 } 196 }
196 const std::thread::id this_id = std::this_thread::get_id(); 197 const auto end = register_host_thread_keys.begin() + num_host_threads;
197 const auto it = host_thread_ids.find(this_id); 198 const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
198 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); 199 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
199 ASSERT(it == host_thread_ids.end()); 200 ASSERT(it == end);
200 ASSERT(!registered_core_threads[core_id]); 201 ASSERT(!registered_core_threads[core_id]);
201 host_thread_ids[this_id] = static_cast<u32>(core_id); 202 InsertHostThread(static_cast<u32>(core_id));
202 registered_core_threads.set(core_id); 203 registered_core_threads.set(core_id);
203 } 204 }
204 205
205 void RegisterHostThread() { 206 void RegisterHostThread() {
206 std::unique_lock lock{register_thread_mutex};
207 const std::thread::id this_id = std::this_thread::get_id(); 207 const std::thread::id this_id = std::this_thread::get_id();
208 const auto it = host_thread_ids.find(this_id); 208 const auto end = register_host_thread_keys.begin() + num_host_threads;
209 if (it != host_thread_ids.end()) { 209 const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
210 return; 210 if (it == end) {
211 InsertHostThread(registered_thread_ids++);
211 } 212 }
212 host_thread_ids[this_id] = registered_thread_ids++;
213 } 213 }
214 214
215 u32 GetCurrentHostThreadID() const { 215 void InsertHostThread(u32 value) {
216 const size_t index = num_host_threads++;
217 ASSERT_MSG(index < NUM_REGISTRABLE_HOST_THREADS, "Too many host threads");
218 register_host_thread_values[index] = value;
219 register_host_thread_keys[index] = std::this_thread::get_id();
220 }
221
222 [[nodiscard]] u32 GetCurrentHostThreadID() const {
216 const std::thread::id this_id = std::this_thread::get_id(); 223 const std::thread::id this_id = std::this_thread::get_id();
217 if (!is_multicore) { 224 if (!is_multicore && single_core_thread_id == this_id) {
218 if (single_core_thread_id == this_id) { 225 return static_cast<u32>(system.GetCpuManager().CurrentCore());
219 return static_cast<u32>(system.GetCpuManager().CurrentCore());
220 }
221 } 226 }
222 std::unique_lock lock{register_thread_mutex}; 227 const auto end = register_host_thread_keys.begin() + num_host_threads;
223 const auto it = host_thread_ids.find(this_id); 228 const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
224 if (it == host_thread_ids.end()) { 229 if (it == end) {
225 return Core::INVALID_HOST_THREAD_ID; 230 return Core::INVALID_HOST_THREAD_ID;
226 } 231 }
227 return it->second; 232 return register_host_thread_values[std::distance(register_host_thread_keys.begin(), it)];
228 } 233 }
229 234
230 Core::EmuThreadHandle GetCurrentEmuThreadID() const { 235 Core::EmuThreadHandle GetCurrentEmuThreadID() const {
@@ -322,10 +327,15 @@ struct KernelCore::Impl {
322 std::vector<Kernel::PhysicalCore> cores; 327 std::vector<Kernel::PhysicalCore> cores;
323 328
324 // 0-3 IDs represent core threads, >3 represent others 329 // 0-3 IDs represent core threads, >3 represent others
325 std::unordered_map<std::thread::id, u32> host_thread_ids; 330 std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
326 u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
327 std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads; 331 std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads;
328 mutable std::mutex register_thread_mutex; 332
333 // Number of host threads is a relatively high number to avoid overflowing
334 static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64;
335 std::atomic<size_t> num_host_threads{0};
336 std::array<std::atomic<std::thread::id>, NUM_REGISTRABLE_HOST_THREADS>
337 register_host_thread_keys{};
338 std::array<std::atomic<u32>, NUM_REGISTRABLE_HOST_THREADS> register_host_thread_values{};
329 339
330 // Kernel memory management 340 // Kernel memory management
331 std::unique_ptr<Memory::MemoryManager> memory_manager; 341 std::unique_ptr<Memory::MemoryManager> memory_manager;
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 6b1613510..2850dd805 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -496,7 +496,7 @@ public:
496 {3, nullptr, "LoadIdTokenCache"}, 496 {3, nullptr, "LoadIdTokenCache"},
497 {130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"}, 497 {130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"},
498 {150, nullptr, "CreateAuthorizationRequest"}, 498 {150, nullptr, "CreateAuthorizationRequest"},
499 {160, nullptr, "StoreOpenContext"}, 499 {160, &IManagerForApplication::StoreOpenContext, "StoreOpenContext"},
500 {170, nullptr, "LoadNetworkServiceLicenseKindAsync"}, 500 {170, nullptr, "LoadNetworkServiceLicenseKindAsync"},
501 }; 501 };
502 // clang-format on 502 // clang-format on
@@ -520,6 +520,12 @@ private:
520 rb.PushRaw<u64>(user_id.GetNintendoID()); 520 rb.PushRaw<u64>(user_id.GetNintendoID());
521 } 521 }
522 522
523 void StoreOpenContext(Kernel::HLERequestContext& ctx) {
524 LOG_WARNING(Service_ACC, "(STUBBED) called");
525 IPC::ResponseBuilder rb{ctx, 2};
526 rb.Push(RESULT_SUCCESS);
527 }
528
523 Common::UUID user_id; 529 Common::UUID user_id;
524}; 530};
525 531
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
index bd7ea75c2..e6cadf491 100644
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ b/src/core/hle/service/bcat/backend/boxcat.cpp
@@ -463,6 +463,16 @@ Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global,
463 {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)}, 463 {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)},
464 }; 464 };
465 465
466 if (!client.is_valid()) {
467 LOG_ERROR(Service_BCAT, "Client is invalid, going offline!");
468 return StatusResult::Offline;
469 }
470
471 if (!client.is_socket_open()) {
472 LOG_ERROR(Service_BCAT, "Failed to open socket, going offline!");
473 return StatusResult::Offline;
474 }
475
466 const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers); 476 const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers);
467 if (response == nullptr) 477 if (response == nullptr)
468 return StatusResult::Offline; 478 return StatusResult::Offline;
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 54a5fb84b..3cdef4888 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -79,7 +79,7 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons
79 } 79 }
80 80
81 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); 81 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
82 if (dir->GetFile(Common::FS::GetFilename(path)) == nullptr) { 82 if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) {
83 return FileSys::ERROR_PATH_NOT_FOUND; 83 return FileSys::ERROR_PATH_NOT_FOUND;
84 } 84 }
85 if (!dir->DeleteFile(Common::FS::GetFilename(path))) { 85 if (!dir->DeleteFile(Common::FS::GetFilename(path))) {
@@ -93,8 +93,9 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons
93ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const { 93ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const {
94 std::string path(Common::FS::SanitizePath(path_)); 94 std::string path(Common::FS::SanitizePath(path_));
95 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); 95 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
96 if (dir == nullptr && Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty()) 96 if (dir == nullptr || Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty()) {
97 dir = backing; 97 dir = backing;
98 }
98 auto new_dir = dir->CreateSubdirectory(Common::FS::GetFilename(path)); 99 auto new_dir = dir->CreateSubdirectory(Common::FS::GetFilename(path));
99 if (new_dir == nullptr) { 100 if (new_dir == nullptr) {
100 // TODO(DarkLordZach): Find a better error code for this 101 // TODO(DarkLordZach): Find a better error code for this
diff --git a/src/core/hle/service/mii/manager.cpp b/src/core/hle/service/mii/manager.cpp
index 5930765bc..1b75c2ebe 100644
--- a/src/core/hle/service/mii/manager.cpp
+++ b/src/core/hle/service/mii/manager.cpp
@@ -131,7 +131,7 @@ template <typename T>
131T GetRandomValue(T min, T max) { 131T GetRandomValue(T min, T max) {
132 std::random_device device; 132 std::random_device device;
133 std::mt19937 gen(device()); 133 std::mt19937 gen(device());
134 std::uniform_int_distribution<u64> distribution(0, static_cast<u64>(max)); 134 std::uniform_int_distribution<u64> distribution(static_cast<u64>(min), static_cast<u64>(max));
135 return static_cast<T>(distribution(gen)); 135 return static_cast<T>(distribution(gen));
136} 136}
137 137
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 2e9d95195..db7ec6d0e 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -62,7 +62,7 @@ public:
62 {18, nullptr, "SetRequirementByRevision"}, 62 {18, nullptr, "SetRequirementByRevision"},
63 {19, nullptr, "GetRequirement"}, 63 {19, nullptr, "GetRequirement"},
64 {20, nullptr, "GetRevision"}, 64 {20, nullptr, "GetRevision"},
65 {21, nullptr, "GetAppletInfo"}, 65 {21, &IRequest::GetAppletInfo, "GetAppletInfo"},
66 {22, nullptr, "GetAdditionalInfo"}, 66 {22, nullptr, "GetAdditionalInfo"},
67 {23, nullptr, "SetKeptInSleep"}, 67 {23, nullptr, "SetKeptInSleep"},
68 {24, nullptr, "RegisterSocketDescriptor"}, 68 {24, nullptr, "RegisterSocketDescriptor"},
@@ -125,6 +125,16 @@ private:
125 rb.Push(RESULT_SUCCESS); 125 rb.Push(RESULT_SUCCESS);
126 } 126 }
127 127
128 void GetAppletInfo(Kernel::HLERequestContext& ctx) {
129 LOG_WARNING(Service_NIFM, "(STUBBED) called");
130
131 IPC::ResponseBuilder rb{ctx, 8};
132 rb.Push(RESULT_SUCCESS);
133 rb.Push<u32>(0);
134 rb.Push<u32>(0);
135 rb.Push<u32>(0);
136 }
137
128 Kernel::EventPair event1, event2; 138 Kernel::EventPair event1, event2;
129}; 139};
130 140
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index 85e921ceb..3a5bebff3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -46,6 +46,8 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std:
46 return GetVARegions(input, output); 46 return GetVARegions(input, output);
47 case IoctlCommand::IocUnmapBufferCommand: 47 case IoctlCommand::IocUnmapBufferCommand:
48 return UnmapBuffer(input, output); 48 return UnmapBuffer(input, output);
49 case IoctlCommand::IocFreeSpaceCommand:
50 return FreeSpace(input, output);
49 default: 51 default:
50 break; 52 break;
51 } 53 }
@@ -91,6 +93,20 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
91 return result; 93 return result;
92} 94}
93 95
96u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {
97 IoctlFreeSpace params{};
98 std::memcpy(&params, input.data(), input.size());
99
100 LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset,
101 params.pages, params.page_size);
102
103 system.GPU().MemoryManager().Unmap(params.offset,
104 static_cast<std::size_t>(params.pages) * params.page_size);
105
106 std::memcpy(output.data(), &params, output.size());
107 return NvErrCodes::Success;
108}
109
94u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { 110u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
95 const auto num_entries = input.size() / sizeof(IoctlRemapEntry); 111 const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
96 112
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index 9a0cdff0c..fcdb40d93 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -82,6 +82,7 @@ private:
82 IocBindChannelCommand = 0x40044101, 82 IocBindChannelCommand = 0x40044101,
83 IocGetVaRegionsCommand = 0xC0404108, 83 IocGetVaRegionsCommand = 0xC0404108,
84 IocUnmapBufferCommand = 0xC0084105, 84 IocUnmapBufferCommand = 0xC0084105,
85 IocFreeSpaceCommand = 0xC0104103,
85 }; 86 };
86 87
87 struct IoctlInitalizeEx { 88 struct IoctlInitalizeEx {
@@ -107,6 +108,13 @@ private:
107 }; 108 };
108 static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); 109 static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
109 110
111 struct IoctlFreeSpace {
112 u64_le offset;
113 u32_le pages;
114 u32_le page_size;
115 };
116 static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size");
117
110 struct IoctlRemapEntry { 118 struct IoctlRemapEntry {
111 u16_le flags; 119 u16_le flags;
112 u16_le kind; 120 u16_le kind;
@@ -162,6 +170,7 @@ private:
162 u32 Remap(const std::vector<u8>& input, std::vector<u8>& output); 170 u32 Remap(const std::vector<u8>& input, std::vector<u8>& output);
163 u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); 171 u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
164 u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); 172 u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
173 u32 FreeSpace(const std::vector<u8>& input, std::vector<u8>& output);
165 u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output); 174 u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
166 u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); 175 u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
167 176
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 637b310d7..4f1e210b1 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -99,6 +99,20 @@ void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
99 queue_sequence.push_back(slot); 99 queue_sequence.push_back(slot);
100} 100}
101 101
102void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence) {
103 const auto itr = std::find_if(queue.begin(), queue.end(),
104 [slot](const Buffer& buffer) { return buffer.slot == slot; });
105 ASSERT(itr != queue.end());
106 ASSERT(itr->status != Buffer::Status::Free);
107 itr->status = Buffer::Status::Free;
108 itr->multi_fence = multi_fence;
109 itr->swap_interval = 0;
110
111 free_buffers.push_back(slot);
112
113 buffer_wait_event.writable->Signal();
114}
115
102std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { 116std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
103 auto itr = queue.end(); 117 auto itr = queue.end();
104 // Iterate to find a queued buffer matching the requested slot. 118 // Iterate to find a queued buffer matching the requested slot.
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 8a837e5aa..e7517c7e1 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -95,6 +95,7 @@ public:
95 void QueueBuffer(u32 slot, BufferTransformFlags transform, 95 void QueueBuffer(u32 slot, BufferTransformFlags transform,
96 const Common::Rectangle<int>& crop_rect, u32 swap_interval, 96 const Common::Rectangle<int>& crop_rect, u32 swap_interval,
97 Service::Nvidia::MultiFence& multi_fence); 97 Service::Nvidia::MultiFence& multi_fence);
98 void CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence);
98 std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer(); 99 std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer();
99 void ReleaseBuffer(u32 slot); 100 void ReleaseBuffer(u32 slot);
100 void Disconnect(); 101 void Disconnect();
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index d380c60fb..5b0e371fe 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -215,10 +215,9 @@ public:
215 explicit IGBPConnectRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 215 explicit IGBPConnectRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
216 Deserialize(); 216 Deserialize();
217 } 217 }
218 ~IGBPConnectRequestParcel() override = default;
219 218
220 void DeserializeData() override { 219 void DeserializeData() override {
221 std::u16string token = ReadInterfaceToken(); 220 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
222 data = Read<Data>(); 221 data = Read<Data>();
223 } 222 }
224 223
@@ -279,10 +278,9 @@ public:
279 : Parcel(std::move(buffer)) { 278 : Parcel(std::move(buffer)) {
280 Deserialize(); 279 Deserialize();
281 } 280 }
282 ~IGBPSetPreallocatedBufferRequestParcel() override = default;
283 281
284 void DeserializeData() override { 282 void DeserializeData() override {
285 std::u16string token = ReadInterfaceToken(); 283 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
286 data = Read<Data>(); 284 data = Read<Data>();
287 buffer = Read<NVFlinger::IGBPBuffer>(); 285 buffer = Read<NVFlinger::IGBPBuffer>();
288 } 286 }
@@ -306,15 +304,40 @@ protected:
306 } 304 }
307}; 305};
308 306
307class IGBPCancelBufferRequestParcel : public Parcel {
308public:
309 explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
310 Deserialize();
311 }
312
313 void DeserializeData() override {
314 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
315 data = Read<Data>();
316 }
317
318 struct Data {
319 u32_le slot;
320 Service::Nvidia::MultiFence multi_fence;
321 };
322
323 Data data;
324};
325
326class IGBPCancelBufferResponseParcel : public Parcel {
327protected:
328 void SerializeData() override {
329 Write<u32>(0); // Success
330 }
331};
332
309class IGBPDequeueBufferRequestParcel : public Parcel { 333class IGBPDequeueBufferRequestParcel : public Parcel {
310public: 334public:
311 explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 335 explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
312 Deserialize(); 336 Deserialize();
313 } 337 }
314 ~IGBPDequeueBufferRequestParcel() override = default;
315 338
316 void DeserializeData() override { 339 void DeserializeData() override {
317 std::u16string token = ReadInterfaceToken(); 340 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
318 data = Read<Data>(); 341 data = Read<Data>();
319 } 342 }
320 343
@@ -333,7 +356,6 @@ class IGBPDequeueBufferResponseParcel : public Parcel {
333public: 356public:
334 explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence) 357 explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence)
335 : slot(slot), multi_fence(multi_fence) {} 358 : slot(slot), multi_fence(multi_fence) {}
336 ~IGBPDequeueBufferResponseParcel() override = default;
337 359
338protected: 360protected:
339 void SerializeData() override { 361 void SerializeData() override {
@@ -352,10 +374,9 @@ public:
352 explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 374 explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
353 Deserialize(); 375 Deserialize();
354 } 376 }
355 ~IGBPRequestBufferRequestParcel() override = default;
356 377
357 void DeserializeData() override { 378 void DeserializeData() override {
358 std::u16string token = ReadInterfaceToken(); 379 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
359 slot = Read<u32_le>(); 380 slot = Read<u32_le>();
360 } 381 }
361 382
@@ -384,10 +405,9 @@ public:
384 explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 405 explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
385 Deserialize(); 406 Deserialize();
386 } 407 }
387 ~IGBPQueueBufferRequestParcel() override = default;
388 408
389 void DeserializeData() override { 409 void DeserializeData() override {
390 std::u16string token = ReadInterfaceToken(); 410 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
391 data = Read<Data>(); 411 data = Read<Data>();
392 } 412 }
393 413
@@ -447,10 +467,9 @@ public:
447 explicit IGBPQueryRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 467 explicit IGBPQueryRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
448 Deserialize(); 468 Deserialize();
449 } 469 }
450 ~IGBPQueryRequestParcel() override = default;
451 470
452 void DeserializeData() override { 471 void DeserializeData() override {
453 std::u16string token = ReadInterfaceToken(); 472 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
454 type = Read<u32_le>(); 473 type = Read<u32_le>();
455 } 474 }
456 475
@@ -596,7 +615,12 @@ private:
596 break; 615 break;
597 } 616 }
598 case TransactionId::CancelBuffer: { 617 case TransactionId::CancelBuffer: {
599 LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); 618 IGBPCancelBufferRequestParcel request{ctx.ReadBuffer()};
619
620 buffer_queue.CancelBuffer(request.data.slot, request.data.multi_fence);
621
622 IGBPCancelBufferResponseParcel response{};
623 ctx.WriteBuffer(response.Serialize());
600 break; 624 break;
601 } 625 }
602 case TransactionId::Disconnect: { 626 case TransactionId::Disconnect: {
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index c84685214..7b39a38c1 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -29,6 +29,35 @@ add_library(input_common STATIC
29 udp/udp.h 29 udp/udp.h
30) 30)
31 31
32if (MSVC)
33 target_compile_options(input_common PRIVATE
34 # 'expression' : signed/unsigned mismatch
35 /we4018
36 # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point)
37 /we4244
38 # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch
39 /we4245
40 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
41 /we4254
42 # 'var' : conversion from 'size_t' to 'type', possible loss of data
43 /we4267
44 # 'context' : truncation from 'type1' to 'type2'
45 /we4305
46 )
47else()
48 target_compile_options(input_common PRIVATE
49 -Werror=conversion
50 -Werror=ignored-qualifiers
51 -Werror=implicit-fallthrough
52 -Werror=reorder
53 -Werror=shadow
54 -Werror=sign-compare
55 -Werror=unused-but-set-parameter
56 -Werror=unused-but-set-variable
57 -Werror=unused-variable
58 )
59endif()
60
32if(SDL2_FOUND) 61if(SDL2_FOUND)
33 target_sources(input_common PRIVATE 62 target_sources(input_common PRIVATE
34 sdl/sdl_impl.cpp 63 sdl/sdl_impl.cpp
diff --git a/src/input_common/analog_from_button.cpp b/src/input_common/analog_from_button.cpp
index 6cabdaa3c..74744d7f3 100755
--- a/src/input_common/analog_from_button.cpp
+++ b/src/input_common/analog_from_button.cpp
@@ -20,18 +20,22 @@ public:
20 constexpr float SQRT_HALF = 0.707106781f; 20 constexpr float SQRT_HALF = 0.707106781f;
21 int x = 0, y = 0; 21 int x = 0, y = 0;
22 22
23 if (right->GetStatus()) 23 if (right->GetStatus()) {
24 ++x; 24 ++x;
25 if (left->GetStatus()) 25 }
26 if (left->GetStatus()) {
26 --x; 27 --x;
27 if (up->GetStatus()) 28 }
29 if (up->GetStatus()) {
28 ++y; 30 ++y;
29 if (down->GetStatus()) 31 }
32 if (down->GetStatus()) {
30 --y; 33 --y;
34 }
31 35
32 float coef = modifier->GetStatus() ? modifier_scale : 1.0f; 36 const float coef = modifier->GetStatus() ? modifier_scale : 1.0f;
33 return std::make_tuple(x * coef * (y == 0 ? 1.0f : SQRT_HALF), 37 return std::make_tuple(static_cast<float>(x) * coef * (y == 0 ? 1.0f : SQRT_HALF),
34 y * coef * (x == 0 ? 1.0f : SQRT_HALF)); 38 static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF));
35 } 39 }
36 40
37 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { 41 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp
index 89c148aba..c95feb0d7 100644
--- a/src/input_common/gcadapter/gc_adapter.cpp
+++ b/src/input_common/gcadapter/gc_adapter.cpp
@@ -21,7 +21,7 @@
21 21
22namespace GCAdapter { 22namespace GCAdapter {
23 23
24/// Used to loop through and assign button in poller 24// Used to loop through and assign button in poller
25constexpr std::array<PadButton, 12> PadButtonArray{ 25constexpr std::array<PadButton, 12> PadButtonArray{
26 PadButton::PAD_BUTTON_LEFT, PadButton::PAD_BUTTON_RIGHT, PadButton::PAD_BUTTON_DOWN, 26 PadButton::PAD_BUTTON_LEFT, PadButton::PAD_BUTTON_RIGHT, PadButton::PAD_BUTTON_DOWN,
27 PadButton::PAD_BUTTON_UP, PadButton::PAD_TRIGGER_Z, PadButton::PAD_TRIGGER_R, 27 PadButton::PAD_BUTTON_UP, PadButton::PAD_TRIGGER_Z, PadButton::PAD_TRIGGER_R,
@@ -29,6 +29,18 @@ constexpr std::array<PadButton, 12> PadButtonArray{
29 PadButton::PAD_BUTTON_X, PadButton::PAD_BUTTON_Y, PadButton::PAD_BUTTON_START, 29 PadButton::PAD_BUTTON_X, PadButton::PAD_BUTTON_Y, PadButton::PAD_BUTTON_START,
30}; 30};
31 31
32static void PadToState(const GCPadStatus& pad, GCState& out_state) {
33 for (const auto& button : PadButtonArray) {
34 const auto button_key = static_cast<u16>(button);
35 const auto button_value = (pad.button & button_key) != 0;
36 out_state.buttons.insert_or_assign(static_cast<s32>(button_key), button_value);
37 }
38
39 for (std::size_t i = 0; i < pad.axis_values.size(); ++i) {
40 out_state.axes.insert_or_assign(static_cast<u32>(i), pad.axis_values[i]);
41 }
42}
43
32Adapter::Adapter() { 44Adapter::Adapter() {
33 if (usb_adapter_handle != nullptr) { 45 if (usb_adapter_handle != nullptr) {
34 return; 46 return;
@@ -78,17 +90,17 @@ GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& ad
78 90
79 for (std::size_t i = 0; i < b1_buttons.size(); ++i) { 91 for (std::size_t i = 0; i < b1_buttons.size(); ++i) {
80 if ((b1 & (1U << i)) != 0) { 92 if ((b1 & (1U << i)) != 0) {
81 pad.button |= static_cast<u16>(b1_buttons[i]); 93 pad.button = static_cast<u16>(pad.button | static_cast<u16>(b1_buttons[i]));
82 } 94 }
83 } 95 }
84 96
85 for (std::size_t j = 0; j < b2_buttons.size(); ++j) { 97 for (std::size_t j = 0; j < b2_buttons.size(); ++j) {
86 if ((b2 & (1U << j)) != 0) { 98 if ((b2 & (1U << j)) != 0) {
87 pad.button |= static_cast<u16>(b2_buttons[j]); 99 pad.button = static_cast<u16>(pad.button | static_cast<u16>(b2_buttons[j]));
88 } 100 }
89 } 101 }
90 for (PadAxes axis : axes) { 102 for (PadAxes axis : axes) {
91 const std::size_t index = static_cast<std::size_t>(axis); 103 const auto index = static_cast<std::size_t>(axis);
92 pad.axis_values[index] = adapter_payload[offset + 3 + index]; 104 pad.axis_values[index] = adapter_payload[offset + 3 + index];
93 } 105 }
94 106
@@ -100,17 +112,6 @@ GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& ad
100 return pad; 112 return pad;
101} 113}
102 114
103void Adapter::PadToState(const GCPadStatus& pad, GCState& state) {
104 for (const auto& button : PadButtonArray) {
105 const u16 button_value = static_cast<u16>(button);
106 state.buttons.insert_or_assign(button_value, pad.button & button_value);
107 }
108
109 for (size_t i = 0; i < pad.axis_values.size(); ++i) {
110 state.axes.insert_or_assign(static_cast<u8>(i), pad.axis_values[i]);
111 }
112}
113
114void Adapter::Read() { 115void Adapter::Read() {
115 LOG_DEBUG(Input, "GC Adapter Read() thread started"); 116 LOG_DEBUG(Input, "GC Adapter Read() thread started");
116 117
@@ -250,7 +251,7 @@ void Adapter::GetGCEndpoint(libusb_device* device) {
250 const libusb_interface_descriptor* interface = &interfaceContainer->altsetting[i]; 251 const libusb_interface_descriptor* interface = &interfaceContainer->altsetting[i];
251 for (u8 e = 0; e < interface->bNumEndpoints; e++) { 252 for (u8 e = 0; e < interface->bNumEndpoints; e++) {
252 const libusb_endpoint_descriptor* endpoint = &interface->endpoint[e]; 253 const libusb_endpoint_descriptor* endpoint = &interface->endpoint[e];
253 if (endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) { 254 if ((endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) != 0) {
254 input_endpoint = endpoint->bEndpointAddress; 255 input_endpoint = endpoint->bEndpointAddress;
255 } else { 256 } else {
256 output_endpoint = endpoint->bEndpointAddress; 257 output_endpoint = endpoint->bEndpointAddress;
@@ -419,7 +420,7 @@ const std::array<GCState, 4>& Adapter::GetPadState() const {
419 return state; 420 return state;
420} 421}
421 422
422int Adapter::GetOriginValue(int port, int axis) const { 423int Adapter::GetOriginValue(u32 port, u32 axis) const {
423 return origin_status[port].axis_values[axis]; 424 return origin_status[port].axis_values[axis];
424} 425}
425 426
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h
index 75bf9fe74..4f5f3de8e 100644
--- a/src/input_common/gcadapter/gc_adapter.h
+++ b/src/input_common/gcadapter/gc_adapter.h
@@ -60,7 +60,7 @@ struct GCPadStatus {
60 60
61struct GCState { 61struct GCState {
62 std::unordered_map<int, bool> buttons; 62 std::unordered_map<int, bool> buttons;
63 std::unordered_map<int, u16> axes; 63 std::unordered_map<u32, u16> axes;
64}; 64};
65 65
66enum class ControllerTypes { None, Wired, Wireless }; 66enum class ControllerTypes { None, Wired, Wireless };
@@ -89,13 +89,11 @@ public:
89 std::array<GCState, 4>& GetPadState(); 89 std::array<GCState, 4>& GetPadState();
90 const std::array<GCState, 4>& GetPadState() const; 90 const std::array<GCState, 4>& GetPadState() const;
91 91
92 int GetOriginValue(int port, int axis) const; 92 int GetOriginValue(u32 port, u32 axis) const;
93 93
94private: 94private:
95 GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload); 95 GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload);
96 96
97 void PadToState(const GCPadStatus& pad, GCState& state);
98
99 void Read(); 97 void Read();
100 98
101 /// Resets status of device connected to port 99 /// Resets status of device connected to port
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index 92e9e8e89..893556916 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -15,7 +15,7 @@ namespace InputCommon {
15 15
16class GCButton final : public Input::ButtonDevice { 16class GCButton final : public Input::ButtonDevice {
17public: 17public:
18 explicit GCButton(int port_, int button_, const GCAdapter::Adapter* adapter) 18 explicit GCButton(u32 port_, int button_, const GCAdapter::Adapter* adapter)
19 : port(port_), button(button_), gcadapter(adapter) {} 19 : port(port_), button(button_), gcadapter(adapter) {}
20 20
21 ~GCButton() override; 21 ~GCButton() override;
@@ -28,14 +28,14 @@ public:
28 } 28 }
29 29
30private: 30private:
31 const int port; 31 const u32 port;
32 const int button; 32 const int button;
33 const GCAdapter::Adapter* gcadapter; 33 const GCAdapter::Adapter* gcadapter;
34}; 34};
35 35
36class GCAxisButton final : public Input::ButtonDevice { 36class GCAxisButton final : public Input::ButtonDevice {
37public: 37public:
38 explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, 38 explicit GCAxisButton(u32 port_, u32 axis_, float threshold_, bool trigger_if_greater_,
39 const GCAdapter::Adapter* adapter) 39 const GCAdapter::Adapter* adapter)
40 : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), 40 : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_),
41 gcadapter(adapter), 41 gcadapter(adapter),
@@ -56,8 +56,8 @@ public:
56 } 56 }
57 57
58private: 58private:
59 const int port; 59 const u32 port;
60 const int axis; 60 const u32 axis;
61 float threshold; 61 float threshold;
62 bool trigger_if_greater; 62 bool trigger_if_greater;
63 const GCAdapter::Adapter* gcadapter; 63 const GCAdapter::Adapter* gcadapter;
@@ -70,8 +70,8 @@ GCButtonFactory::GCButtonFactory(std::shared_ptr<GCAdapter::Adapter> adapter_)
70GCButton::~GCButton() = default; 70GCButton::~GCButton() = default;
71 71
72std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::ParamPackage& params) { 72std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::ParamPackage& params) {
73 const int button_id = params.Get("button", 0); 73 const auto button_id = params.Get("button", 0);
74 const int port = params.Get("port", 0); 74 const auto port = static_cast<u32>(params.Get("port", 0));
75 75
76 constexpr int PAD_STICK_ID = static_cast<u16>(GCAdapter::PadButton::PAD_STICK); 76 constexpr int PAD_STICK_ID = static_cast<u16>(GCAdapter::PadButton::PAD_STICK);
77 77
@@ -149,25 +149,27 @@ void GCButtonFactory::EndConfiguration() {
149 149
150class GCAnalog final : public Input::AnalogDevice { 150class GCAnalog final : public Input::AnalogDevice {
151public: 151public:
152 GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, 152 explicit GCAnalog(u32 port_, u32 axis_x_, u32 axis_y_, float deadzone_,
153 const GCAdapter::Adapter* adapter, float range_) 153 const GCAdapter::Adapter* adapter, float range_)
154 : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), 154 : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter),
155 origin_value_x(static_cast<float>(adapter->GetOriginValue(port_, axis_x_))), 155 origin_value_x(static_cast<float>(adapter->GetOriginValue(port_, axis_x_))),
156 origin_value_y(static_cast<float>(adapter->GetOriginValue(port_, axis_y_))), 156 origin_value_y(static_cast<float>(adapter->GetOriginValue(port_, axis_y_))),
157 range(range_) {} 157 range(range_) {}
158 158
159 float GetAxis(int axis) const { 159 float GetAxis(u32 axis) const {
160 if (gcadapter->DeviceConnected(port)) { 160 if (gcadapter->DeviceConnected(port)) {
161 std::lock_guard lock{mutex}; 161 std::lock_guard lock{mutex};
162 const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y; 162 const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y;
163 return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / (100.0f * range); 163 const auto axis_value =
164 static_cast<float>(gcadapter->GetPadState()[port].axes.at(axis));
165 return (axis_value - origin_value) / (100.0f * range);
164 } 166 }
165 return 0.0f; 167 return 0.0f;
166 } 168 }
167 169
168 std::pair<float, float> GetAnalog(int axis_x, int axis_y) const { 170 std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
169 float x = GetAxis(axis_x); 171 float x = GetAxis(analog_axis_x);
170 float y = GetAxis(axis_y); 172 float y = GetAxis(analog_axis_y);
171 173
172 // Make sure the coordinates are in the unit circle, 174 // Make sure the coordinates are in the unit circle,
173 // otherwise normalize it. 175 // otherwise normalize it.
@@ -208,9 +210,9 @@ public:
208 } 210 }
209 211
210private: 212private:
211 const int port; 213 const u32 port;
212 const int axis_x; 214 const u32 axis_x;
213 const int axis_y; 215 const u32 axis_y;
214 const float deadzone; 216 const float deadzone;
215 const GCAdapter::Adapter* gcadapter; 217 const GCAdapter::Adapter* gcadapter;
216 const float origin_value_x; 218 const float origin_value_x;
@@ -231,11 +233,11 @@ GCAnalogFactory::GCAnalogFactory(std::shared_ptr<GCAdapter::Adapter> adapter_)
231 * - "axis_y": the index of the axis to be bind as y-axis 233 * - "axis_y": the index of the axis to be bind as y-axis
232 */ 234 */
233std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::ParamPackage& params) { 235std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::ParamPackage& params) {
234 const int port = params.Get("port", 0); 236 const auto port = static_cast<u32>(params.Get("port", 0));
235 const int axis_x = params.Get("axis_x", 0); 237 const auto axis_x = static_cast<u32>(params.Get("axis_x", 0));
236 const int axis_y = params.Get("axis_y", 1); 238 const auto axis_y = static_cast<u32>(params.Get("axis_y", 1));
237 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); 239 const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
238 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); 240 const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
239 241
240 return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range); 242 return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range);
241} 243}
@@ -256,7 +258,7 @@ Common::ParamPackage GCAnalogFactory::GetNextInput() {
256 for (std::size_t port = 0; port < queue.size(); ++port) { 258 for (std::size_t port = 0; port < queue.size(); ++port) {
257 while (queue[port].Pop(pad)) { 259 while (queue[port].Pop(pad)) {
258 if (pad.axis == GCAdapter::PadAxes::Undefined || 260 if (pad.axis == GCAdapter::PadAxes::Undefined ||
259 std::abs((pad.axis_value - 128.0f) / 128.0f) < 0.1) { 261 std::abs((static_cast<float>(pad.axis_value) - 128.0f) / 128.0f) < 0.1f) {
260 continue; 262 continue;
261 } 263 }
262 // An analog device needs two axes, so we need to store the axis for later and wait for 264 // An analog device needs two axes, so we need to store the axis for later and wait for
diff --git a/src/input_common/keyboard.cpp b/src/input_common/keyboard.cpp
index afb8e6612..24a6f7a33 100644
--- a/src/input_common/keyboard.cpp
+++ b/src/input_common/keyboard.cpp
@@ -49,8 +49,9 @@ public:
49 void ChangeKeyStatus(int key_code, bool pressed) { 49 void ChangeKeyStatus(int key_code, bool pressed) {
50 std::lock_guard guard{mutex}; 50 std::lock_guard guard{mutex};
51 for (const KeyButtonPair& pair : list) { 51 for (const KeyButtonPair& pair : list) {
52 if (pair.key_code == key_code) 52 if (pair.key_code == key_code) {
53 pair.key_button->status.store(pressed); 53 pair.key_button->status.store(pressed);
54 }
54 } 55 }
55 } 56 }
56 57
@@ -73,7 +74,7 @@ KeyButton::~KeyButton() {
73} 74}
74 75
75std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage& params) { 76std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage& params) {
76 int key_code = params.Get("code", 0); 77 const int key_code = params.Get("code", 0);
77 std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list); 78 std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list);
78 key_button_list->AddKeyButton(key_code, button.get()); 79 key_button_list->AddKeyButton(key_code, button.get());
79 return button; 80 return button;
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 3d97d95f7..d32fd8b81 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -196,6 +196,10 @@ ButtonMapping InputSubsystem::GetButtonMappingForDevice(const Common::ParamPacka
196 return impl->GetButtonMappingForDevice(device); 196 return impl->GetButtonMappingForDevice(device);
197} 197}
198 198
199MotionMapping InputSubsystem::GetMotionMappingForDevice(const Common::ParamPackage& device) const {
200 return impl->GetMotionMappingForDevice(device);
201}
202
199GCAnalogFactory* InputSubsystem::GetGCAnalogs() { 203GCAnalogFactory* InputSubsystem::GetGCAnalogs() {
200 return impl->gcanalog.get(); 204 return impl->gcanalog.get();
201} 205}
diff --git a/src/input_common/motion_emu.cpp b/src/input_common/motion_emu.cpp
index 69fd3c1d2..d4da5596b 100644
--- a/src/input_common/motion_emu.cpp
+++ b/src/input_common/motion_emu.cpp
@@ -18,11 +18,11 @@ namespace InputCommon {
18// Implementation class of the motion emulation device 18// Implementation class of the motion emulation device
19class MotionEmuDevice { 19class MotionEmuDevice {
20public: 20public:
21 MotionEmuDevice(int update_millisecond, float sensitivity) 21 explicit MotionEmuDevice(int update_millisecond_, float sensitivity_)
22 : update_millisecond(update_millisecond), 22 : update_millisecond(update_millisecond_),
23 update_duration(std::chrono::duration_cast<std::chrono::steady_clock::duration>( 23 update_duration(std::chrono::duration_cast<std::chrono::steady_clock::duration>(
24 std::chrono::milliseconds(update_millisecond))), 24 std::chrono::milliseconds(update_millisecond))),
25 sensitivity(sensitivity), motion_emu_thread(&MotionEmuDevice::MotionEmuThread, this) {} 25 sensitivity(sensitivity_), motion_emu_thread(&MotionEmuDevice::MotionEmuThread, this) {}
26 26
27 ~MotionEmuDevice() { 27 ~MotionEmuDevice() {
28 if (motion_emu_thread.joinable()) { 28 if (motion_emu_thread.joinable()) {
@@ -37,16 +37,18 @@ public:
37 } 37 }
38 38
39 void Tilt(int x, int y) { 39 void Tilt(int x, int y) {
40 auto mouse_move = Common::MakeVec(x, y) - mouse_origin; 40 if (!is_tilting) {
41 if (is_tilting) { 41 return;
42 std::lock_guard guard{tilt_mutex}; 42 }
43 if (mouse_move.x == 0 && mouse_move.y == 0) { 43
44 tilt_angle = 0; 44 std::lock_guard guard{tilt_mutex};
45 } else { 45 const auto mouse_move = Common::MakeVec(x, y) - mouse_origin;
46 tilt_direction = mouse_move.Cast<float>(); 46 if (mouse_move.x == 0 && mouse_move.y == 0) {
47 tilt_angle = 47 tilt_angle = 0;
48 std::clamp(tilt_direction.Normalize() * sensitivity, 0.0f, Common::PI * 0.5f); 48 } else {
49 } 49 tilt_direction = mouse_move.Cast<float>();
50 tilt_angle =
51 std::clamp(tilt_direction.Normalize() * sensitivity, 0.0f, Common::PI * 0.5f);
50 } 52 }
51 } 53 }
52 54
@@ -86,11 +88,10 @@ private:
86 void MotionEmuThread() { 88 void MotionEmuThread() {
87 auto update_time = std::chrono::steady_clock::now(); 89 auto update_time = std::chrono::steady_clock::now();
88 Common::Quaternion<float> q = Common::MakeQuaternion(Common::Vec3<float>(), 0); 90 Common::Quaternion<float> q = Common::MakeQuaternion(Common::Vec3<float>(), 0);
89 Common::Quaternion<float> old_q;
90 91
91 while (!shutdown_event.WaitUntil(update_time)) { 92 while (!shutdown_event.WaitUntil(update_time)) {
92 update_time += update_duration; 93 update_time += update_duration;
93 old_q = q; 94 const Common::Quaternion<float> old_q = q;
94 95
95 { 96 {
96 std::lock_guard guard{tilt_mutex}; 97 std::lock_guard guard{tilt_mutex};
@@ -100,14 +101,14 @@ private:
100 Common::MakeVec(-tilt_direction.y, 0.0f, tilt_direction.x), tilt_angle); 101 Common::MakeVec(-tilt_direction.y, 0.0f, tilt_direction.x), tilt_angle);
101 } 102 }
102 103
103 auto inv_q = q.Inverse(); 104 const auto inv_q = q.Inverse();
104 105
105 // Set the gravity vector in world space 106 // Set the gravity vector in world space
106 auto gravity = Common::MakeVec(0.0f, -1.0f, 0.0f); 107 auto gravity = Common::MakeVec(0.0f, -1.0f, 0.0f);
107 108
108 // Find the angular rate vector in world space 109 // Find the angular rate vector in world space
109 auto angular_rate = ((q - old_q) * inv_q).xyz * 2; 110 auto angular_rate = ((q - old_q) * inv_q).xyz * 2;
110 angular_rate *= 1000 / update_millisecond / Common::PI * 180; 111 angular_rate *= static_cast<float>(1000 / update_millisecond) / Common::PI * 180.0f;
111 112
112 // Transform the two vectors from world space to 3DS space 113 // Transform the two vectors from world space to 3DS space
113 gravity = QuaternionRotate(inv_q, gravity); 114 gravity = QuaternionRotate(inv_q, gravity);
@@ -136,7 +137,7 @@ private:
136// can forward all the inputs to the implementation only when it is valid. 137// can forward all the inputs to the implementation only when it is valid.
137class MotionEmuDeviceWrapper : public Input::MotionDevice { 138class MotionEmuDeviceWrapper : public Input::MotionDevice {
138public: 139public:
139 MotionEmuDeviceWrapper(int update_millisecond, float sensitivity) { 140 explicit MotionEmuDeviceWrapper(int update_millisecond, float sensitivity) {
140 device = std::make_shared<MotionEmuDevice>(update_millisecond, sensitivity); 141 device = std::make_shared<MotionEmuDevice>(update_millisecond, sensitivity);
141 } 142 }
142 143
@@ -148,8 +149,8 @@ public:
148}; 149};
149 150
150std::unique_ptr<Input::MotionDevice> MotionEmu::Create(const Common::ParamPackage& params) { 151std::unique_ptr<Input::MotionDevice> MotionEmu::Create(const Common::ParamPackage& params) {
151 int update_period = params.Get("update_period", 100); 152 const int update_period = params.Get("update_period", 100);
152 float sensitivity = params.Get("sensitivity", 0.01f); 153 const float sensitivity = params.Get("sensitivity", 0.01f);
153 auto device_wrapper = std::make_unique<MotionEmuDeviceWrapper>(update_period, sensitivity); 154 auto device_wrapper = std::make_unique<MotionEmuDeviceWrapper>(update_period, sensitivity);
154 // Previously created device is disconnected here. Having two motion devices for 3DS is not 155 // Previously created device is disconnected here. Having two motion devices for 3DS is not
155 // expected. 156 // expected.
diff --git a/src/input_common/motion_from_button.cpp b/src/input_common/motion_from_button.cpp
index 9d459f963..29045a673 100644
--- a/src/input_common/motion_from_button.cpp
+++ b/src/input_common/motion_from_button.cpp
@@ -11,7 +11,7 @@ class MotionKey final : public Input::MotionDevice {
11public: 11public:
12 using Button = std::unique_ptr<Input::ButtonDevice>; 12 using Button = std::unique_ptr<Input::ButtonDevice>;
13 13
14 MotionKey(Button key_) : key(std::move(key_)) {} 14 explicit MotionKey(Button key_) : key(std::move(key_)) {}
15 15
16 Input::MotionStatus GetStatus() const override { 16 Input::MotionStatus GetStatus() const override {
17 17
diff --git a/src/input_common/motion_input.cpp b/src/input_common/motion_input.cpp
index e89019723..f77ba535d 100644
--- a/src/input_common/motion_input.cpp
+++ b/src/input_common/motion_input.cpp
@@ -8,8 +8,7 @@
8 8
9namespace InputCommon { 9namespace InputCommon {
10 10
11MotionInput::MotionInput(f32 new_kp, f32 new_ki, f32 new_kd) 11MotionInput::MotionInput(f32 new_kp, f32 new_ki, f32 new_kd) : kp(new_kp), ki(new_ki), kd(new_kd) {}
12 : kp(new_kp), ki(new_ki), kd(new_kd), quat{{0, 0, -1}, 0} {}
13 12
14void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) { 13void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) {
15 accel = acceleration; 14 accel = acceleration;
@@ -59,7 +58,7 @@ bool MotionInput::IsCalibrated(f32 sensitivity) const {
59} 58}
60 59
61void MotionInput::UpdateRotation(u64 elapsed_time) { 60void MotionInput::UpdateRotation(u64 elapsed_time) {
62 const f32 sample_period = elapsed_time / 1000000.0f; 61 const auto sample_period = static_cast<f32>(elapsed_time) / 1000000.0f;
63 if (sample_period > 0.1f) { 62 if (sample_period > 0.1f) {
64 return; 63 return;
65 } 64 }
@@ -75,7 +74,7 @@ void MotionInput::UpdateOrientation(u64 elapsed_time) {
75 f32 q2 = quat.xyz[0]; 74 f32 q2 = quat.xyz[0];
76 f32 q3 = quat.xyz[1]; 75 f32 q3 = quat.xyz[1];
77 f32 q4 = quat.xyz[2]; 76 f32 q4 = quat.xyz[2];
78 const f32 sample_period = elapsed_time / 1000000.0f; 77 const auto sample_period = static_cast<f32>(elapsed_time) / 1000000.0f;
79 78
80 // Ignore invalid elapsed time 79 // Ignore invalid elapsed time
81 if (sample_period > 0.1f) { 80 if (sample_period > 0.1f) {
@@ -203,21 +202,21 @@ Input::MotionStatus MotionInput::GetRandomMotion(int accel_magnitude, int gyro_m
203 std::random_device device; 202 std::random_device device;
204 std::mt19937 gen(device()); 203 std::mt19937 gen(device());
205 std::uniform_int_distribution<s16> distribution(-1000, 1000); 204 std::uniform_int_distribution<s16> distribution(-1000, 1000);
206 const Common::Vec3f gyroscope = { 205 const Common::Vec3f gyroscope{
207 distribution(gen) * 0.001f, 206 static_cast<f32>(distribution(gen)) * 0.001f,
208 distribution(gen) * 0.001f, 207 static_cast<f32>(distribution(gen)) * 0.001f,
209 distribution(gen) * 0.001f, 208 static_cast<f32>(distribution(gen)) * 0.001f,
210 }; 209 };
211 const Common::Vec3f accelerometer = { 210 const Common::Vec3f accelerometer{
212 distribution(gen) * 0.001f, 211 static_cast<f32>(distribution(gen)) * 0.001f,
213 distribution(gen) * 0.001f, 212 static_cast<f32>(distribution(gen)) * 0.001f,
214 distribution(gen) * 0.001f, 213 static_cast<f32>(distribution(gen)) * 0.001f,
215 }; 214 };
216 const Common::Vec3f rotation = {}; 215 constexpr Common::Vec3f rotation;
217 const std::array<Common::Vec3f, 3> orientation = { 216 constexpr std::array orientation{
218 Common::Vec3f{1.0f, 0, 0}, 217 Common::Vec3f{1.0f, 0.0f, 0.0f},
219 Common::Vec3f{0, 1.0f, 0}, 218 Common::Vec3f{0.0f, 1.0f, 0.0f},
220 Common::Vec3f{0, 0, 1.0f}, 219 Common::Vec3f{0.0f, 0.0f, 1.0f},
221 }; 220 };
222 return {accelerometer * accel_magnitude, gyroscope * gyro_magnitude, rotation, orientation}; 221 return {accelerometer * accel_magnitude, gyroscope * gyro_magnitude, rotation, orientation};
223} 222}
@@ -247,9 +246,6 @@ void MotionInput::SetOrientationFromAccelerometer() {
247 const f32 sample_period = 0.015f; 246 const f32 sample_period = 0.015f;
248 247
249 const auto normal_accel = accel.Normalized(); 248 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 249
254 while (!IsCalibrated(0.01f) && ++iterations < 100) { 250 while (!IsCalibrated(0.01f) && ++iterations < 100) {
255 // Short name local variable for readability 251 // Short name local variable for readability
@@ -258,7 +254,7 @@ void MotionInput::SetOrientationFromAccelerometer() {
258 f32 q3 = quat.xyz[1]; 254 f32 q3 = quat.xyz[1];
259 f32 q4 = quat.xyz[2]; 255 f32 q4 = quat.xyz[2];
260 256
261 Common::Vec3f rad_gyro = {}; 257 Common::Vec3f rad_gyro;
262 const f32 ax = -normal_accel.x; 258 const f32 ax = -normal_accel.x;
263 const f32 ay = normal_accel.y; 259 const f32 ay = normal_accel.y;
264 const f32 az = -normal_accel.z; 260 const f32 az = -normal_accel.z;
diff --git a/src/input_common/motion_input.h b/src/input_common/motion_input.h
index 6342d0318..abb957f04 100644
--- a/src/input_common/motion_input.h
+++ b/src/input_common/motion_input.h
@@ -22,7 +22,7 @@ public:
22 MotionInput& operator=(MotionInput&&) = default; 22 MotionInput& operator=(MotionInput&&) = default;
23 23
24 void SetAcceleration(const Common::Vec3f& acceleration); 24 void SetAcceleration(const Common::Vec3f& acceleration);
25 void SetGyroscope(const Common::Vec3f& acceleration); 25 void SetGyroscope(const Common::Vec3f& gyroscope);
26 void SetQuaternion(const Common::Quaternion<f32>& quaternion); 26 void SetQuaternion(const Common::Quaternion<f32>& quaternion);
27 void SetGyroDrift(const Common::Vec3f& drift); 27 void SetGyroDrift(const Common::Vec3f& drift);
28 void SetGyroThreshold(f32 threshold); 28 void SetGyroThreshold(f32 threshold);
@@ -49,16 +49,16 @@ private:
49 void SetOrientationFromAccelerometer(); 49 void SetOrientationFromAccelerometer();
50 50
51 // PID constants 51 // PID constants
52 const f32 kp; 52 f32 kp;
53 const f32 ki; 53 f32 ki;
54 const f32 kd; 54 f32 kd;
55 55
56 // PID errors 56 // PID errors
57 Common::Vec3f real_error; 57 Common::Vec3f real_error;
58 Common::Vec3f integral_error; 58 Common::Vec3f integral_error;
59 Common::Vec3f derivative_error; 59 Common::Vec3f derivative_error;
60 60
61 Common::Quaternion<f32> quat; 61 Common::Quaternion<f32> quat{{0.0f, 0.0f, -1.0f}, 0.0f};
62 Common::Vec3f rotations; 62 Common::Vec3f rotations;
63 Common::Vec3f accel; 63 Common::Vec3f accel;
64 Common::Vec3f gyro; 64 Common::Vec3f gyro;
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index bd480570a..9c3035920 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -56,9 +56,9 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) {
56class SDLJoystick { 56class SDLJoystick {
57public: 57public:
58 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, 58 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
59 SDL_GameController* gamecontroller) 59 SDL_GameController* game_controller)
60 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, 60 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
61 sdl_controller{gamecontroller, &SDL_GameControllerClose} {} 61 sdl_controller{game_controller, &SDL_GameControllerClose} {}
62 62
63 void SetButton(int button, bool value) { 63 void SetButton(int button, bool value) {
64 std::lock_guard lock{mutex}; 64 std::lock_guard lock{mutex};
@@ -77,10 +77,10 @@ public:
77 77
78 float GetAxis(int axis, float range) const { 78 float GetAxis(int axis, float range) const {
79 std::lock_guard lock{mutex}; 79 std::lock_guard lock{mutex};
80 return state.axes.at(axis) / (32767.0f * range); 80 return static_cast<float>(state.axes.at(axis)) / (32767.0f * range);
81 } 81 }
82 82
83 bool RumblePlay(f32 amp_low, f32 amp_high, int time) { 83 bool RumblePlay(f32 amp_low, f32 amp_high, u32 time) {
84 const u16 raw_amp_low = static_cast<u16>(amp_low * 0xFFFF); 84 const u16 raw_amp_low = static_cast<u16>(amp_low * 0xFFFF);
85 const u16 raw_amp_high = static_cast<u16>(amp_high * 0xFFFF); 85 const u16 raw_amp_high = static_cast<u16>(amp_high * 0xFFFF);
86 // Lower drastically the number of state changes 86 // Lower drastically the number of state changes
@@ -124,7 +124,7 @@ public:
124 return std::make_tuple(x, y); 124 return std::make_tuple(x, y);
125 } 125 }
126 126
127 const InputCommon::MotionInput& GetMotion() const { 127 const MotionInput& GetMotion() const {
128 return motion; 128 return motion;
129 } 129 }
130 130
@@ -172,15 +172,15 @@ private:
172 } state; 172 } state;
173 std::string guid; 173 std::string guid;
174 int port; 174 int port;
175 u16 last_state_rumble_high; 175 u16 last_state_rumble_high = 0;
176 u16 last_state_rumble_low; 176 u16 last_state_rumble_low = 0;
177 std::chrono::time_point<std::chrono::system_clock> last_vibration; 177 std::chrono::time_point<std::chrono::system_clock> last_vibration;
178 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; 178 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
179 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; 179 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
180 mutable std::mutex mutex; 180 mutable std::mutex mutex;
181 181
182 // motion is initalized without PID values as motion input is not aviable for SDL2 182 // Motion is initialized without PID values as motion input is not aviable for SDL2
183 InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f}; 183 MotionInput motion{0.0f, 0.0f, 0.0f};
184}; 184};
185 185
186std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { 186std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
@@ -192,7 +192,7 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& g
192 nullptr, nullptr); 192 nullptr, nullptr);
193 it->second.emplace_back(std::move(joystick)); 193 it->second.emplace_back(std::move(joystick));
194 } 194 }
195 return it->second[port]; 195 return it->second[static_cast<std::size_t>(port)];
196 } 196 }
197 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr); 197 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
198 return joystick_map[guid].emplace_back(std::move(joystick)); 198 return joystick_map[guid].emplace_back(std::move(joystick));
@@ -212,7 +212,7 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_
212 return sdl_joystick == joystick->GetSDLJoystick(); 212 return sdl_joystick == joystick->GetSDLJoystick();
213 }); 213 });
214 if (vec_it != map_it->second.end()) { 214 if (vec_it != map_it->second.end()) {
215 // This is the common case: There is already an existing SDL_Joystick maped to a 215 // This is the common case: There is already an existing SDL_Joystick mapped to a
216 // SDLJoystick. return the SDLJoystick 216 // SDLJoystick. return the SDLJoystick
217 return *vec_it; 217 return *vec_it;
218 } 218 }
@@ -220,7 +220,7 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_
220 // Search for a SDLJoystick without a mapped SDL_Joystick... 220 // Search for a SDLJoystick without a mapped SDL_Joystick...
221 const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(), 221 const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(),
222 [](const std::shared_ptr<SDLJoystick>& joystick) { 222 [](const std::shared_ptr<SDLJoystick>& joystick) {
223 return !joystick->GetSDLJoystick(); 223 return joystick->GetSDLJoystick() == nullptr;
224 }); 224 });
225 if (nullptr_it != map_it->second.end()) { 225 if (nullptr_it != map_it->second.end()) {
226 // ... and map it 226 // ... and map it
@@ -273,22 +273,19 @@ void SDLState::InitJoystick(int joystick_index) {
273void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) { 273void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
274 const std::string guid = GetGUID(sdl_joystick); 274 const std::string guid = GetGUID(sdl_joystick);
275 275
276 std::shared_ptr<SDLJoystick> joystick; 276 std::lock_guard lock{joystick_map_mutex};
277 { 277 auto& joystick_guid_list = joystick_map[guid];
278 std::lock_guard lock{joystick_map_mutex}; 278 auto joystick_it = std::find_if(
279 // This call to guid is safe since the joystick is guaranteed to be in the map 279 joystick_guid_list.begin(), joystick_guid_list.end(),
280 const auto& joystick_guid_list = joystick_map[guid]; 280 [&sdl_joystick](auto& joystick) { return joystick->GetSDLJoystick() == sdl_joystick; });
281 const auto joystick_it =
282 std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
283 [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
284 return joystick->GetSDLJoystick() == sdl_joystick;
285 });
286 joystick = *joystick_it;
287 }
288 281
289 // Destruct SDL_Joystick outside the lock guard because SDL can internally call the 282 if (joystick_it != joystick_guid_list.end()) {
290 // event callback which locks the mutex again. 283 (*joystick_it)->SetSDLJoystick(nullptr, nullptr);
291 joystick->SetSDLJoystick(nullptr, nullptr); 284 joystick_guid_list.erase(joystick_it);
285 if (joystick_guid_list.empty()) {
286 joystick_map.erase(guid);
287 }
288 }
292} 289}
293 290
294void SDLState::HandleGameControllerEvent(const SDL_Event& event) { 291void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
@@ -392,8 +389,8 @@ private:
392 389
393class SDLAnalog final : public Input::AnalogDevice { 390class SDLAnalog final : public Input::AnalogDevice {
394public: 391public:
395 SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_, 392 explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_,
396 float range_) 393 float deadzone_, float range_)
397 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), 394 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_),
398 range(range_) {} 395 range(range_) {}
399 396
@@ -672,13 +669,13 @@ SDLState::SDLState() {
672 RegisterFactory<ButtonDevice>("sdl", button_factory); 669 RegisterFactory<ButtonDevice>("sdl", button_factory);
673 RegisterFactory<MotionDevice>("sdl", motion_factory); 670 RegisterFactory<MotionDevice>("sdl", motion_factory);
674 671
675 // If the frontend is going to manage the event loop, then we dont start one here 672 // If the frontend is going to manage the event loop, then we don't start one here
676 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK); 673 start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0;
677 if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { 674 if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) {
678 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); 675 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
679 return; 676 return;
680 } 677 }
681 has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER); 678 has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0;
682 if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) { 679 if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
683 LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError()); 680 LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
684 } 681 }
@@ -723,8 +720,8 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
723 std::vector<Common::ParamPackage> devices; 720 std::vector<Common::ParamPackage> devices;
724 for (const auto& [key, value] : joystick_map) { 721 for (const auto& [key, value] : joystick_map) {
725 for (const auto& joystick : value) { 722 for (const auto& joystick : value) {
726 auto joy = joystick->GetSDLJoystick(); 723 auto* joy = joystick->GetSDLJoystick();
727 if (auto controller = joystick->GetSDLGameController()) { 724 if (auto* controller = joystick->GetSDLGameController()) {
728 std::string name = 725 std::string name =
729 fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort()); 726 fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
730 devices.emplace_back(Common::ParamPackage{ 727 devices.emplace_back(Common::ParamPackage{
@@ -748,7 +745,7 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
748} 745}
749 746
750namespace { 747namespace {
751Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, u8 axis, 748Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis,
752 float value = 0.1f) { 749 float value = 0.1f) {
753 Common::ParamPackage params({{"engine", "sdl"}}); 750 Common::ParamPackage params({{"engine", "sdl"}});
754 params.Set("port", port); 751 params.Set("port", port);
@@ -764,7 +761,7 @@ Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid
764 return params; 761 return params;
765} 762}
766 763
767Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, u8 button) { 764Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, s32 button) {
768 Common::ParamPackage params({{"engine", "sdl"}}); 765 Common::ParamPackage params({{"engine", "sdl"}});
769 params.Set("port", port); 766 params.Set("port", port);
770 params.Set("guid", std::move(guid)); 767 params.Set("guid", std::move(guid));
@@ -772,7 +769,7 @@ Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid
772 return params; 769 return params;
773} 770}
774 771
775Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, u8 hat, u8 value) { 772Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat, s32 value) {
776 Common::ParamPackage params({{"engine", "sdl"}}); 773 Common::ParamPackage params({{"engine", "sdl"}});
777 774
778 params.Set("port", port); 775 params.Set("port", port);
@@ -802,17 +799,19 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve
802 case SDL_JOYAXISMOTION: { 799 case SDL_JOYAXISMOTION: {
803 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 800 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
804 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 801 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
805 event.jaxis.axis, event.jaxis.value); 802 static_cast<s32>(event.jaxis.axis),
803 event.jaxis.value);
806 } 804 }
807 case SDL_JOYBUTTONUP: { 805 case SDL_JOYBUTTONUP: {
808 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); 806 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
809 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 807 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
810 event.jbutton.button); 808 static_cast<s32>(event.jbutton.button));
811 } 809 }
812 case SDL_JOYHATMOTION: { 810 case SDL_JOYHATMOTION: {
813 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); 811 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
814 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 812 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
815 event.jhat.hat, event.jhat.value); 813 static_cast<s32>(event.jhat.hat),
814 static_cast<s32>(event.jhat.value));
816 } 815 }
817 } 816 }
818 return {}; 817 return {};
@@ -823,17 +822,19 @@ Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Eve
823 case SDL_JOYAXISMOTION: { 822 case SDL_JOYAXISMOTION: {
824 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 823 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
825 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 824 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
826 event.jaxis.axis, event.jaxis.value); 825 static_cast<s32>(event.jaxis.axis),
826 event.jaxis.value);
827 } 827 }
828 case SDL_JOYBUTTONUP: { 828 case SDL_JOYBUTTONUP: {
829 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); 829 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
830 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 830 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
831 event.jbutton.button); 831 static_cast<s32>(event.jbutton.button));
832 } 832 }
833 case SDL_JOYHATMOTION: { 833 case SDL_JOYHATMOTION: {
834 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); 834 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
835 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 835 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
836 event.jhat.hat, event.jhat.value); 836 static_cast<s32>(event.jhat.hat),
837 static_cast<s32>(event.jhat.value));
837 } 838 }
838 } 839 }
839 return {}; 840 return {};
@@ -1062,7 +1063,7 @@ public:
1062 if (event.type == SDL_JOYAXISMOTION) { 1063 if (event.type == SDL_JOYAXISMOTION) {
1063 const auto axis = event.jaxis.axis; 1064 const auto axis = event.jaxis.axis;
1064 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 1065 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
1065 const auto controller = joystick->GetSDLGameController(); 1066 auto* const controller = joystick->GetSDLGameController();
1066 if (controller) { 1067 if (controller) {
1067 const auto axis_left_x = 1068 const auto axis_left_x =
1068 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) 1069 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
diff --git a/src/input_common/settings.h b/src/input_common/settings.h
index ab0b95cf1..f52d28540 100644
--- a/src/input_common/settings.h
+++ b/src/input_common/settings.h
@@ -331,8 +331,6 @@ struct PlayerInput {
331 ButtonsRaw buttons; 331 ButtonsRaw buttons;
332 AnalogsRaw analogs; 332 AnalogsRaw analogs;
333 MotionRaw motions; 333 MotionRaw motions;
334 std::string lstick_mod;
335 std::string rstick_mod;
336 334
337 u32 body_color_left; 335 u32 body_color_left;
338 u32 body_color_right; 336 u32 body_color_right;
diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp
index 98da0ef1a..c37716aae 100644
--- a/src/input_common/touch_from_button.cpp
+++ b/src/input_common/touch_from_button.cpp
@@ -11,9 +11,11 @@ namespace InputCommon {
11class TouchFromButtonDevice final : public Input::TouchDevice { 11class TouchFromButtonDevice final : public Input::TouchDevice {
12public: 12public:
13 TouchFromButtonDevice() { 13 TouchFromButtonDevice() {
14 for (const auto& config_entry : 14 const auto button_index =
15 Settings::values.touch_from_button_maps[Settings::values.touch_from_button_map_index] 15 static_cast<std::size_t>(Settings::values.touch_from_button_map_index);
16 .buttons) { 16 const auto& buttons = Settings::values.touch_from_button_maps[button_index].buttons;
17
18 for (const auto& config_entry : buttons) {
17 const Common::ParamPackage package{config_entry}; 19 const Common::ParamPackage package{config_entry};
18 map.emplace_back( 20 map.emplace_back(
19 Input::CreateDevice<Input::ButtonDevice>(config_entry), 21 Input::CreateDevice<Input::ButtonDevice>(config_entry),
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index 9d0b9f31d..7039d6fc3 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -26,11 +26,11 @@ class Socket {
26public: 26public:
27 using clock = std::chrono::system_clock; 27 using clock = std::chrono::system_clock;
28 28
29 explicit Socket(const std::string& host, u16 port, u8 pad_index, u32 client_id, 29 explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, u32 client_id_,
30 SocketCallback callback) 30 SocketCallback callback_)
31 : callback(std::move(callback)), timer(io_service), 31 : callback(std::move(callback_)), timer(io_service),
32 socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id), 32 socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id_),
33 pad_index(pad_index) { 33 pad_index(pad_index_) {
34 boost::system::error_code ec{}; 34 boost::system::error_code ec{};
35 auto ipv4 = boost::asio::ip::make_address_v4(host, ec); 35 auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
36 if (ec.value() != boost::system::errc::success) { 36 if (ec.value() != boost::system::errc::success) {
@@ -93,13 +93,17 @@ private:
93 void HandleSend(const boost::system::error_code& error) { 93 void HandleSend(const boost::system::error_code& error) {
94 boost::system::error_code _ignored{}; 94 boost::system::error_code _ignored{};
95 // Send a request for getting port info for the pad 95 // Send a request for getting port info for the pad
96 Request::PortInfo port_info{1, {pad_index, 0, 0, 0}}; 96 const Request::PortInfo port_info{1, {static_cast<u8>(pad_index), 0, 0, 0}};
97 const auto port_message = Request::Create(port_info, client_id); 97 const auto port_message = Request::Create(port_info, client_id);
98 std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE); 98 std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE);
99 socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored); 99 socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored);
100 100
101 // Send a request for getting pad data for the pad 101 // Send a request for getting pad data for the pad
102 Request::PadData pad_data{Request::PadData::Flags::Id, pad_index, EMPTY_MAC_ADDRESS}; 102 const Request::PadData pad_data{
103 Request::PadData::Flags::Id,
104 static_cast<u8>(pad_index),
105 EMPTY_MAC_ADDRESS,
106 };
103 const auto pad_message = Request::Create(pad_data, client_id); 107 const auto pad_message = Request::Create(pad_data, client_id);
104 std::memcpy(send_buffer2.data(), &pad_message, PAD_DATA_SIZE); 108 std::memcpy(send_buffer2.data(), &pad_message, PAD_DATA_SIZE);
105 socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint, {}, _ignored); 109 socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint, {}, _ignored);
@@ -112,7 +116,7 @@ private:
112 udp::socket socket; 116 udp::socket socket;
113 117
114 u32 client_id{}; 118 u32 client_id{};
115 u8 pad_index{}; 119 std::size_t pad_index{};
116 120
117 static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); 121 static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>);
118 static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>); 122 static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>);
@@ -133,7 +137,7 @@ static void SocketLoop(Socket* socket) {
133Client::Client() { 137Client::Client() {
134 LOG_INFO(Input, "Udp Initialization started"); 138 LOG_INFO(Input, "Udp Initialization started");
135 for (std::size_t client = 0; client < clients.size(); client++) { 139 for (std::size_t client = 0; client < clients.size(); client++) {
136 u8 pad = client % 4; 140 const auto pad = client % 4;
137 StartCommunication(client, Settings::values.udp_input_address, 141 StartCommunication(client, Settings::values.udp_input_address,
138 Settings::values.udp_input_port, pad, 24872); 142 Settings::values.udp_input_port, pad, 24872);
139 // Set motion parameters 143 // Set motion parameters
@@ -166,9 +170,9 @@ std::vector<Common::ParamPackage> Client::GetInputDevices() const {
166bool Client::DeviceConnected(std::size_t pad) const { 170bool Client::DeviceConnected(std::size_t pad) const {
167 // Use last timestamp to detect if the socket has stopped sending data 171 // Use last timestamp to detect if the socket has stopped sending data
168 const auto now = std::chrono::system_clock::now(); 172 const auto now = std::chrono::system_clock::now();
169 u64 time_difference = 173 const auto time_difference = static_cast<u64>(
170 std::chrono::duration_cast<std::chrono::milliseconds>(now - clients[pad].last_motion_update) 174 std::chrono::duration_cast<std::chrono::milliseconds>(now - clients[pad].last_motion_update)
171 .count(); 175 .count());
172 return time_difference < 1000 && clients[pad].active == 1; 176 return time_difference < 1000 && clients[pad].active == 1;
173} 177}
174 178
@@ -177,9 +181,9 @@ void Client::ReloadUDPClient() {
177 ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port, client); 181 ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port, client);
178 } 182 }
179} 183}
180void Client::ReloadSocket(const std::string& host, u16 port, u8 pad_index, u32 client_id) { 184void Client::ReloadSocket(const std::string& host, u16 port, std::size_t pad_index, u32 client_id) {
181 // client number must be determined from host / port and pad index 185 // client number must be determined from host / port and pad index
182 std::size_t client = pad_index; 186 const std::size_t client = pad_index;
183 clients[client].socket->Stop(); 187 clients[client].socket->Stop();
184 clients[client].thread.join(); 188 clients[client].thread.join();
185 StartCommunication(client, host, port, pad_index, client_id); 189 StartCommunication(client, host, port, pad_index, client_id);
@@ -194,8 +198,8 @@ void Client::OnPortInfo(Response::PortInfo data) {
194} 198}
195 199
196void Client::OnPadData(Response::PadData data) { 200void Client::OnPadData(Response::PadData data) {
197 // client number must be determined from host / port and pad index 201 // Client number must be determined from host / port and pad index
198 std::size_t client = data.info.id; 202 const std::size_t client = data.info.id;
199 LOG_TRACE(Input, "PadData packet received"); 203 LOG_TRACE(Input, "PadData packet received");
200 if (data.packet_counter == clients[client].packet_sequence) { 204 if (data.packet_counter == clients[client].packet_sequence) {
201 LOG_WARNING( 205 LOG_WARNING(
@@ -207,11 +211,12 @@ void Client::OnPadData(Response::PadData data) {
207 clients[client].active = data.info.is_pad_active; 211 clients[client].active = data.info.is_pad_active;
208 clients[client].packet_sequence = data.packet_counter; 212 clients[client].packet_sequence = data.packet_counter;
209 const auto now = std::chrono::system_clock::now(); 213 const auto now = std::chrono::system_clock::now();
210 u64 time_difference = std::chrono::duration_cast<std::chrono::microseconds>( 214 const auto time_difference =
211 now - clients[client].last_motion_update) 215 static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>(
212 .count(); 216 now - clients[client].last_motion_update)
217 .count());
213 clients[client].last_motion_update = now; 218 clients[client].last_motion_update = now;
214 Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw}; 219 const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw};
215 clients[client].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y}); 220 clients[client].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y});
216 // Gyroscope values are not it the correct scale from better joy. 221 // Gyroscope values are not it the correct scale from better joy.
217 // Dividing by 312 allows us to make one full turn = 1 turn 222 // Dividing by 312 allows us to make one full turn = 1 turn
@@ -237,9 +242,11 @@ void Client::OnPadData(Response::PadData data) {
237 const u16 min_y = clients[client].status.touch_calibration->min_y; 242 const u16 min_y = clients[client].status.touch_calibration->min_y;
238 const u16 max_y = clients[client].status.touch_calibration->max_y; 243 const u16 max_y = clients[client].status.touch_calibration->max_y;
239 244
240 x = (std::clamp(static_cast<u16>(data.touch_1.x), min_x, max_x) - min_x) / 245 x = static_cast<float>(std::clamp(static_cast<u16>(data.touch_1.x), min_x, max_x) -
246 min_x) /
241 static_cast<float>(max_x - min_x); 247 static_cast<float>(max_x - min_x);
242 y = (std::clamp(static_cast<u16>(data.touch_1.y), min_y, max_y) - min_y) / 248 y = static_cast<float>(std::clamp(static_cast<u16>(data.touch_1.y), min_y, max_y) -
249 min_y) /
243 static_cast<float>(max_y - min_y); 250 static_cast<float>(max_y - min_y);
244 } 251 }
245 252
@@ -253,8 +260,8 @@ void Client::OnPadData(Response::PadData data) {
253 } 260 }
254} 261}
255 262
256void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, u8 pad_index, 263void Client::StartCommunication(std::size_t client, const std::string& host, u16 port,
257 u32 client_id) { 264 std::size_t pad_index, u32 client_id) {
258 SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, 265 SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
259 [this](Response::PortInfo info) { OnPortInfo(info); }, 266 [this](Response::PortInfo info) { OnPortInfo(info); },
260 [this](Response::PadData data) { OnPadData(data); }}; 267 [this](Response::PadData data) { OnPadData(data); }};
@@ -264,9 +271,9 @@ void Client::StartCommunication(std::size_t client, const std::string& host, u16
264} 271}
265 272
266void Client::Reset() { 273void Client::Reset() {
267 for (std::size_t client = 0; client < clients.size(); client++) { 274 for (auto& client : clients) {
268 clients[client].socket->Stop(); 275 client.socket->Stop();
269 clients[client].thread.join(); 276 client.thread.join();
270 } 277 }
271} 278}
272 279
@@ -325,16 +332,19 @@ const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() cons
325 return pad_queue; 332 return pad_queue;
326} 333}
327 334
328void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id, 335void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id,
329 std::function<void()> success_callback, 336 const std::function<void()>& success_callback,
330 std::function<void()> failure_callback) { 337 const std::function<void()>& failure_callback) {
331 std::thread([=] { 338 std::thread([=] {
332 Common::Event success_event; 339 Common::Event success_event;
333 SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {}, 340 SocketCallback callback{
334 [&](Response::PadData data) { success_event.Set(); }}; 341 .version = [](Response::Version) {},
342 .port_info = [](Response::PortInfo) {},
343 .pad_data = [&](Response::PadData) { success_event.Set(); },
344 };
335 Socket socket{host, port, pad_index, client_id, std::move(callback)}; 345 Socket socket{host, port, pad_index, client_id, std::move(callback)};
336 std::thread worker_thread{SocketLoop, &socket}; 346 std::thread worker_thread{SocketLoop, &socket};
337 bool result = success_event.WaitFor(std::chrono::seconds(8)); 347 const bool result = success_event.WaitFor(std::chrono::seconds(8));
338 socket.Stop(); 348 socket.Stop();
339 worker_thread.join(); 349 worker_thread.join();
340 if (result) { 350 if (result) {
@@ -346,7 +356,7 @@ void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 clie
346} 356}
347 357
348CalibrationConfigurationJob::CalibrationConfigurationJob( 358CalibrationConfigurationJob::CalibrationConfigurationJob(
349 const std::string& host, u16 port, u8 pad_index, u32 client_id, 359 const std::string& host, u16 port, std::size_t pad_index, u32 client_id,
350 std::function<void(Status)> status_callback, 360 std::function<void(Status)> status_callback,
351 std::function<void(u16, u16, u16, u16)> data_callback) { 361 std::function<void(u16, u16, u16, u16)> data_callback) {
352 362
@@ -366,7 +376,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
366 current_status = Status::Ready; 376 current_status = Status::Ready;
367 status_callback(current_status); 377 status_callback(current_status);
368 } 378 }
369 if (!data.touch_1.is_active) { 379 if (data.touch_1.is_active == 0) {
370 return; 380 return;
371 } 381 }
372 LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x, 382 LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x,
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h
index 523dc6a7a..747e0c0a2 100644
--- a/src/input_common/udp/client.h
+++ b/src/input_common/udp/client.h
@@ -84,8 +84,8 @@ public:
84 84
85 bool DeviceConnected(std::size_t pad) const; 85 bool DeviceConnected(std::size_t pad) const;
86 void ReloadUDPClient(); 86 void ReloadUDPClient();
87 void ReloadSocket(const std::string& host = "127.0.0.1", u16 port = 26760, u8 pad_index = 0, 87 void ReloadSocket(const std::string& host = "127.0.0.1", u16 port = 26760,
88 u32 client_id = 24872); 88 std::size_t pad_index = 0, u32 client_id = 24872);
89 89
90 std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue(); 90 std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue();
91 const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue() const; 91 const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue() const;
@@ -99,7 +99,7 @@ private:
99 DeviceStatus status; 99 DeviceStatus status;
100 std::thread thread; 100 std::thread thread;
101 u64 packet_sequence = 0; 101 u64 packet_sequence = 0;
102 u8 active; 102 u8 active = 0;
103 103
104 // Realtime values 104 // Realtime values
105 // motion is initalized with PID values for drift correction on joycons 105 // motion is initalized with PID values for drift correction on joycons
@@ -113,8 +113,8 @@ private:
113 void OnVersion(Response::Version); 113 void OnVersion(Response::Version);
114 void OnPortInfo(Response::PortInfo); 114 void OnPortInfo(Response::PortInfo);
115 void OnPadData(Response::PadData); 115 void OnPadData(Response::PadData);
116 void StartCommunication(std::size_t client, const std::string& host, u16 port, u8 pad_index, 116 void StartCommunication(std::size_t client, const std::string& host, u16 port,
117 u32 client_id); 117 std::size_t pad_index, u32 client_id);
118 void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, 118 void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
119 const Common::Vec3<float>& gyro, bool touch); 119 const Common::Vec3<float>& gyro, bool touch);
120 120
@@ -139,7 +139,7 @@ public:
139 * @param status_callback Callback for job status updates 139 * @param status_callback Callback for job status updates
140 * @param data_callback Called when calibration data is ready 140 * @param data_callback Called when calibration data is ready
141 */ 141 */
142 explicit CalibrationConfigurationJob(const std::string& host, u16 port, u8 pad_index, 142 explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index,
143 u32 client_id, std::function<void(Status)> status_callback, 143 u32 client_id, std::function<void(Status)> status_callback,
144 std::function<void(u16, u16, u16, u16)> data_callback); 144 std::function<void(u16, u16, u16, u16)> data_callback);
145 ~CalibrationConfigurationJob(); 145 ~CalibrationConfigurationJob();
@@ -149,8 +149,8 @@ private:
149 Common::Event complete_event; 149 Common::Event complete_event;
150}; 150};
151 151
152void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id, 152void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id,
153 std::function<void()> success_callback, 153 const std::function<void()>& success_callback,
154 std::function<void()> failure_callback); 154 const std::function<void()>& failure_callback);
155 155
156} // namespace InputCommon::CemuhookUDP 156} // namespace InputCommon::CemuhookUDP
diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp
index eba077a36..71a76a7aa 100644
--- a/src/input_common/udp/udp.cpp
+++ b/src/input_common/udp/udp.cpp
@@ -2,8 +2,6 @@
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 <atomic>
6#include <list>
7#include <mutex> 5#include <mutex>
8#include <utility> 6#include <utility>
9#include "common/assert.h" 7#include "common/assert.h"
@@ -15,8 +13,8 @@ namespace InputCommon {
15 13
16class UDPMotion final : public Input::MotionDevice { 14class UDPMotion final : public Input::MotionDevice {
17public: 15public:
18 UDPMotion(std::string ip_, int port_, int pad_, CemuhookUDP::Client* client_) 16 explicit UDPMotion(std::string ip_, int port_, u32 pad_, CemuhookUDP::Client* client_)
19 : ip(ip_), port(port_), pad(pad_), client(client_) {} 17 : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {}
20 18
21 Input::MotionStatus GetStatus() const override { 19 Input::MotionStatus GetStatus() const override {
22 return client->GetPadState(pad).motion_status; 20 return client->GetPadState(pad).motion_status;
@@ -25,7 +23,7 @@ public:
25private: 23private:
26 const std::string ip; 24 const std::string ip;
27 const int port; 25 const int port;
28 const int pad; 26 const u32 pad;
29 CemuhookUDP::Client* client; 27 CemuhookUDP::Client* client;
30 mutable std::mutex mutex; 28 mutable std::mutex mutex;
31}; 29};
@@ -40,11 +38,11 @@ UDPMotionFactory::UDPMotionFactory(std::shared_ptr<CemuhookUDP::Client> client_)
40 * - "port": the nth jcpad on the adapter 38 * - "port": the nth jcpad on the adapter
41 */ 39 */
42std::unique_ptr<Input::MotionDevice> UDPMotionFactory::Create(const Common::ParamPackage& params) { 40std::unique_ptr<Input::MotionDevice> UDPMotionFactory::Create(const Common::ParamPackage& params) {
43 const std::string ip = params.Get("ip", "127.0.0.1"); 41 auto ip = params.Get("ip", "127.0.0.1");
44 const int port = params.Get("port", 26760); 42 const auto port = params.Get("port", 26760);
45 const int pad = params.Get("pad_index", 0); 43 const auto pad = static_cast<u32>(params.Get("pad_index", 0));
46 44
47 return std::make_unique<UDPMotion>(ip, port, pad, client.get()); 45 return std::make_unique<UDPMotion>(std::move(ip), port, pad, client.get());
48} 46}
49 47
50void UDPMotionFactory::BeginConfiguration() { 48void UDPMotionFactory::BeginConfiguration() {
@@ -79,7 +77,7 @@ Common::ParamPackage UDPMotionFactory::GetNextInput() {
79 77
80class UDPTouch final : public Input::TouchDevice { 78class UDPTouch final : public Input::TouchDevice {
81public: 79public:
82 UDPTouch(std::string ip_, int port_, int pad_, CemuhookUDP::Client* client_) 80 explicit UDPTouch(std::string ip_, int port_, u32 pad_, CemuhookUDP::Client* client_)
83 : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} 81 : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {}
84 82
85 std::tuple<float, float, bool> GetStatus() const override { 83 std::tuple<float, float, bool> GetStatus() const override {
@@ -89,7 +87,7 @@ public:
89private: 87private:
90 const std::string ip; 88 const std::string ip;
91 const int port; 89 const int port;
92 const int pad; 90 const u32 pad;
93 CemuhookUDP::Client* client; 91 CemuhookUDP::Client* client;
94 mutable std::mutex mutex; 92 mutable std::mutex mutex;
95}; 93};
@@ -104,11 +102,11 @@ UDPTouchFactory::UDPTouchFactory(std::shared_ptr<CemuhookUDP::Client> client_)
104 * - "port": the nth jcpad on the adapter 102 * - "port": the nth jcpad on the adapter
105 */ 103 */
106std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamPackage& params) { 104std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamPackage& params) {
107 const std::string ip = params.Get("ip", "127.0.0.1"); 105 auto ip = params.Get("ip", "127.0.0.1");
108 const int port = params.Get("port", 26760); 106 const auto port = params.Get("port", 26760);
109 const int pad = params.Get("pad_index", 0); 107 const auto pad = static_cast<u32>(params.Get("pad_index", 0));
110 108
111 return std::make_unique<UDPTouch>(ip, port, pad, client.get()); 109 return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get());
112} 110}
113 111
114void UDPTouchFactory::BeginConfiguration() { 112void UDPTouchFactory::BeginConfiguration() {
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
index 81a39a3b8..da5c550ea 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
@@ -58,6 +58,7 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta
58 logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); 58 logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0);
59 logic_op.Assign(PackLogicOp(regs.logic_op.operation)); 59 logic_op.Assign(PackLogicOp(regs.logic_op.operation));
60 rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); 60 rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0);
61 topology.Assign(regs.draw.topology);
61 62
62 std::memcpy(&point_size, &regs.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast 63 std::memcpy(&point_size, &regs.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast
63 64
@@ -131,7 +132,6 @@ void FixedPipelineState::BlendingAttachment::Fill(const Maxwell& regs, std::size
131} 132}
132 133
133void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) { 134void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) {
134 const u32 topology_index = static_cast<u32>(regs.draw.topology.Value());
135 u32 packed_front_face = PackFrontFace(regs.front_face); 135 u32 packed_front_face = PackFrontFace(regs.front_face);
136 if (regs.screen_y_control.triangle_rast_flip != 0) { 136 if (regs.screen_y_control.triangle_rast_flip != 0) {
137 // Flip front face 137 // Flip front face
@@ -161,7 +161,6 @@ void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) {
161 depth_test_enable.Assign(regs.depth_test_enable); 161 depth_test_enable.Assign(regs.depth_test_enable);
162 front_face.Assign(packed_front_face); 162 front_face.Assign(packed_front_face);
163 depth_test_func.Assign(PackComparisonOp(regs.depth_test_func)); 163 depth_test_func.Assign(PackComparisonOp(regs.depth_test_func));
164 topology.Assign(topology_index);
165 cull_face.Assign(PackCullFace(regs.cull_face)); 164 cull_face.Assign(PackCullFace(regs.cull_face));
166 cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0); 165 cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0);
167 166
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
index cdcbb65f5..2c18eeaae 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
@@ -150,9 +150,8 @@ struct FixedPipelineState {
150 }; 150 };
151 union { 151 union {
152 u32 raw2; 152 u32 raw2;
153 BitField<0, 4, u32> topology; 153 BitField<0, 2, u32> cull_face;
154 BitField<4, 2, u32> cull_face; 154 BitField<2, 1, u32> cull_enable;
155 BitField<6, 1, u32> cull_enable;
156 }; 155 };
157 std::array<VertexBinding, Maxwell::NumVertexArrays> vertex_bindings; 156 std::array<VertexBinding, Maxwell::NumVertexArrays> vertex_bindings;
158 157
@@ -169,10 +168,6 @@ struct FixedPipelineState {
169 Maxwell::FrontFace FrontFace() const noexcept { 168 Maxwell::FrontFace FrontFace() const noexcept {
170 return UnpackFrontFace(front_face.Value()); 169 return UnpackFrontFace(front_face.Value());
171 } 170 }
172
173 constexpr Maxwell::PrimitiveTopology Topology() const noexcept {
174 return static_cast<Maxwell::PrimitiveTopology>(topology.Value());
175 }
176 }; 171 };
177 172
178 union { 173 union {
@@ -190,6 +185,7 @@ struct FixedPipelineState {
190 BitField<18, 1, u32> logic_op_enable; 185 BitField<18, 1, u32> logic_op_enable;
191 BitField<19, 4, u32> logic_op; 186 BitField<19, 4, u32> logic_op;
192 BitField<23, 1, u32> rasterize_enable; 187 BitField<23, 1, u32> rasterize_enable;
188 BitField<24, 4, Maxwell::PrimitiveTopology> topology;
193 }; 189 };
194 u32 point_size; 190 u32 point_size;
195 std::array<u32, Maxwell::NumVertexArrays> binding_divisors; 191 std::array<u32, Maxwell::NumVertexArrays> binding_divisors;
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 715182b3b..f2610868e 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -92,9 +92,9 @@ Common::DynamicLibrary OpenVulkanLibrary() {
92 return library; 92 return library;
93} 93}
94 94
95vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatch& dld, 95std::pair<vk::Instance, u32> CreateInstance(
96 WindowSystemType window_type = WindowSystemType::Headless, 96 Common::DynamicLibrary& library, vk::InstanceDispatch& dld,
97 bool enable_layers = false) { 97 WindowSystemType window_type = WindowSystemType::Headless, bool enable_layers = false) {
98 if (!library.IsOpen()) { 98 if (!library.IsOpen()) {
99 LOG_ERROR(Render_Vulkan, "Vulkan library not available"); 99 LOG_ERROR(Render_Vulkan, "Vulkan library not available");
100 return {}; 100 return {};
@@ -180,7 +180,10 @@ vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatc
180 } 180 }
181 } 181 }
182 182
183 vk::Instance instance = vk::Instance::Create(layers, extensions, dld); 183 // Limit the maximum version of Vulkan to avoid using untested version.
184 const u32 version = std::min(vk::AvailableVersion(dld), static_cast<u32>(VK_API_VERSION_1_1));
185
186 vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld);
184 if (!instance) { 187 if (!instance) {
185 LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance"); 188 LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance");
186 return {}; 189 return {};
@@ -188,7 +191,7 @@ vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatc
188 if (!vk::Load(*instance, dld)) { 191 if (!vk::Load(*instance, dld)) {
189 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); 192 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
190 } 193 }
191 return instance; 194 return std::make_pair(std::move(instance), version);
192} 195}
193 196
194std::string GetReadableVersion(u32 version) { 197std::string GetReadableVersion(u32 version) {
@@ -285,8 +288,8 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
285 288
286bool RendererVulkan::Init() { 289bool RendererVulkan::Init() {
287 library = OpenVulkanLibrary(); 290 library = OpenVulkanLibrary();
288 instance = CreateInstance(library, dld, render_window.GetWindowInfo().type, 291 std::tie(instance, instance_version) = CreateInstance(
289 Settings::values.renderer_debug); 292 library, dld, render_window.GetWindowInfo().type, Settings::values.renderer_debug);
290 if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { 293 if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) {
291 return false; 294 return false;
292 } 295 }
@@ -416,7 +419,8 @@ bool RendererVulkan::PickDevices() {
416 return false; 419 return false;
417 } 420 }
418 421
419 device = std::make_unique<VKDevice>(*instance, physical_device, *surface, dld); 422 device =
423 std::make_unique<VKDevice>(*instance, instance_version, physical_device, *surface, dld);
420 return device->Create(); 424 return device->Create();
421} 425}
422 426
@@ -426,7 +430,7 @@ void RendererVulkan::Report() const {
426 const std::string driver_version = GetDriverVersion(*device); 430 const std::string driver_version = GetDriverVersion(*device);
427 const std::string driver_name = fmt::format("{} {}", vendor_name, driver_version); 431 const std::string driver_name = fmt::format("{} {}", vendor_name, driver_version);
428 432
429 const std::string api_version = GetReadableVersion(device->GetApiVersion()); 433 const std::string api_version = GetReadableVersion(device->ApiVersion());
430 434
431 const std::string extensions = BuildCommaSeparatedExtensions(device->GetAvailableExtensions()); 435 const std::string extensions = BuildCommaSeparatedExtensions(device->GetAvailableExtensions());
432 436
@@ -445,7 +449,7 @@ void RendererVulkan::Report() const {
445std::vector<std::string> RendererVulkan::EnumerateDevices() { 449std::vector<std::string> RendererVulkan::EnumerateDevices() {
446 vk::InstanceDispatch dld; 450 vk::InstanceDispatch dld;
447 Common::DynamicLibrary library = OpenVulkanLibrary(); 451 Common::DynamicLibrary library = OpenVulkanLibrary();
448 vk::Instance instance = CreateInstance(library, dld); 452 vk::Instance instance = CreateInstance(library, dld).first;
449 if (!instance) { 453 if (!instance) {
450 return {}; 454 return {};
451 } 455 }
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index 49a4141ec..1044ca124 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -73,6 +73,8 @@ private:
73 vk::InstanceDispatch dld; 73 vk::InstanceDispatch dld;
74 74
75 vk::Instance instance; 75 vk::Instance instance;
76 u32 instance_version{};
77
76 vk::SurfaceKHR surface; 78 vk::SurfaceKHR surface;
77 79
78 VKScreenInfo screen_info; 80 VKScreenInfo screen_info;
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
index 3d8d3213d..e1217ca83 100644
--- a/src/video_core/renderer_vulkan/vk_device.cpp
+++ b/src/video_core/renderer_vulkan/vk_device.cpp
@@ -38,6 +38,9 @@ constexpr std::array Depth16UnormS8_UINT{
38 38
39constexpr std::array REQUIRED_EXTENSIONS{ 39constexpr std::array REQUIRED_EXTENSIONS{
40 VK_KHR_SWAPCHAIN_EXTENSION_NAME, 40 VK_KHR_SWAPCHAIN_EXTENSION_NAME,
41 VK_KHR_MAINTENANCE1_EXTENSION_NAME,
42 VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME,
43 VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME,
41 VK_KHR_16BIT_STORAGE_EXTENSION_NAME, 44 VK_KHR_16BIT_STORAGE_EXTENSION_NAME,
42 VK_KHR_8BIT_STORAGE_EXTENSION_NAME, 45 VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
43 VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, 46 VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
@@ -79,6 +82,21 @@ VkFormatFeatureFlags GetFormatFeatures(VkFormatProperties properties, FormatType
79 } 82 }
80} 83}
81 84
85[[nodiscard]] bool IsRDNA(std::string_view device_name, VkDriverIdKHR driver_id) {
86 static constexpr std::array RDNA_DEVICES{
87 "5700",
88 "5600",
89 "5500",
90 "5300",
91 };
92 if (driver_id != VK_DRIVER_ID_AMD_PROPRIETARY_KHR) {
93 return false;
94 }
95 return std::any_of(RDNA_DEVICES.begin(), RDNA_DEVICES.end(), [device_name](const char* name) {
96 return device_name.find(name) != std::string_view::npos;
97 });
98}
99
82std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties( 100std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
83 vk::PhysicalDevice physical, const vk::InstanceDispatch& dld) { 101 vk::PhysicalDevice physical, const vk::InstanceDispatch& dld) {
84 static constexpr std::array formats{ 102 static constexpr std::array formats{
@@ -172,10 +190,10 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
172 190
173} // Anonymous namespace 191} // Anonymous namespace
174 192
175VKDevice::VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, 193VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevice physical_,
176 const vk::InstanceDispatch& dld) 194 VkSurfaceKHR surface, const vk::InstanceDispatch& dld_)
177 : dld{dld}, physical{physical}, properties{physical.GetProperties()}, 195 : dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
178 format_properties{GetFormatProperties(physical, dld)} { 196 instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} {
179 SetupFamilies(surface); 197 SetupFamilies(surface);
180 SetupFeatures(); 198 SetupFeatures();
181} 199}
@@ -388,6 +406,15 @@ bool VKDevice::Create() {
388 406
389 CollectTelemetryParameters(); 407 CollectTelemetryParameters();
390 408
409 if (ext_extended_dynamic_state && IsRDNA(properties.deviceName, driver_id)) {
410 // AMD's proprietary driver supports VK_EXT_extended_dynamic_state but on RDNA devices it
411 // seems to cause stability issues
412 LOG_WARNING(
413 Render_Vulkan,
414 "Blacklisting AMD proprietary on RDNA devices from VK_EXT_extended_dynamic_state");
415 ext_extended_dynamic_state = false;
416 }
417
391 graphics_queue = logical.GetQueue(graphics_family); 418 graphics_queue = logical.GetQueue(graphics_family);
392 present_queue = logical.GetQueue(present_family); 419 present_queue = logical.GetQueue(present_family);
393 420
@@ -573,20 +600,6 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {
573 600
574std::vector<const char*> VKDevice::LoadExtensions() { 601std::vector<const char*> VKDevice::LoadExtensions() {
575 std::vector<const char*> extensions; 602 std::vector<const char*> extensions;
576 const auto Test = [&](const VkExtensionProperties& extension,
577 std::optional<std::reference_wrapper<bool>> status, const char* name,
578 bool push) {
579 if (extension.extensionName != std::string_view(name)) {
580 return;
581 }
582 if (push) {
583 extensions.push_back(name);
584 }
585 if (status) {
586 status->get() = true;
587 }
588 };
589
590 extensions.reserve(7 + REQUIRED_EXTENSIONS.size()); 603 extensions.reserve(7 + REQUIRED_EXTENSIONS.size());
591 extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()); 604 extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end());
592 605
@@ -595,28 +608,36 @@ std::vector<const char*> VKDevice::LoadExtensions() {
595 bool has_ext_transform_feedback{}; 608 bool has_ext_transform_feedback{};
596 bool has_ext_custom_border_color{}; 609 bool has_ext_custom_border_color{};
597 bool has_ext_extended_dynamic_state{}; 610 bool has_ext_extended_dynamic_state{};
598 for (const auto& extension : physical.EnumerateDeviceExtensionProperties()) { 611 for (const VkExtensionProperties& extension : physical.EnumerateDeviceExtensionProperties()) {
599 Test(extension, nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true); 612 const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name,
600 Test(extension, khr_uniform_buffer_standard_layout, 613 bool push) {
614 if (extension.extensionName != std::string_view(name)) {
615 return;
616 }
617 if (push) {
618 extensions.push_back(name);
619 }
620 if (status) {
621 status->get() = true;
622 }
623 };
624 test(nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true);
625 test(khr_uniform_buffer_standard_layout,
601 VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true); 626 VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true);
602 Test(extension, has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, 627 test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
603 false); 628 test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true);
604 Test(extension, ext_depth_range_unrestricted, 629 test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true);
605 VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true); 630 test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME,
606 Test(extension, ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true); 631 true);
607 Test(extension, ext_shader_viewport_index_layer, 632 test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false);
608 VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, true); 633 test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false);
609 Test(extension, has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, 634 test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
610 false); 635 if (instance_version >= VK_API_VERSION_1_1) {
611 Test(extension, has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, 636 test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false);
612 false); 637 }
613 Test(extension, has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME,
614 false);
615 Test(extension, has_ext_extended_dynamic_state,
616 VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
617 if (Settings::values.renderer_debug) { 638 if (Settings::values.renderer_debug) {
618 Test(extension, nv_device_diagnostics_config, 639 test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
619 VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, true); 640 true);
620 } 641 }
621 } 642 }
622 643
diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h
index 26a233db1..4286673d9 100644
--- a/src/video_core/renderer_vulkan/vk_device.h
+++ b/src/video_core/renderer_vulkan/vk_device.h
@@ -24,8 +24,8 @@ const u32 GuestWarpSize = 32;
24/// Handles data specific to a physical device. 24/// Handles data specific to a physical device.
25class VKDevice final { 25class VKDevice final {
26public: 26public:
27 explicit VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, 27 explicit VKDevice(VkInstance instance, u32 instance_version, vk::PhysicalDevice physical,
28 const vk::InstanceDispatch& dld); 28 VkSurfaceKHR surface, const vk::InstanceDispatch& dld);
29 ~VKDevice(); 29 ~VKDevice();
30 30
31 /// Initializes the device. Returns true on success. 31 /// Initializes the device. Returns true on success.
@@ -82,8 +82,13 @@ public:
82 return present_family; 82 return present_family;
83 } 83 }
84 84
85 /// Returns the current instance Vulkan API version in Vulkan-formatted version numbers.
86 u32 InstanceApiVersion() const {
87 return instance_version;
88 }
89
85 /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers. 90 /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers.
86 u32 GetApiVersion() const { 91 u32 ApiVersion() const {
87 return properties.apiVersion; 92 return properties.apiVersion;
88 } 93 }
89 94
@@ -239,6 +244,7 @@ private:
239 vk::Device logical; ///< Logical device. 244 vk::Device logical; ///< Logical device.
240 vk::Queue graphics_queue; ///< Main graphics queue. 245 vk::Queue graphics_queue; ///< Main graphics queue.
241 vk::Queue present_queue; ///< Main present queue. 246 vk::Queue present_queue; ///< Main present queue.
247 u32 instance_version{}; ///< Vulkan onstance version.
242 u32 graphics_family{}; ///< Main graphics queue family index. 248 u32 graphics_family{}; ///< Main graphics queue family index.
243 u32 present_family{}; ///< Main present queue family index. 249 u32 present_family{}; ///< Main present queue family index.
244 VkDriverIdKHR driver_id{}; ///< Driver ID. 250 VkDriverIdKHR driver_id{}; ///< Driver ID.
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index a4b9e7ef5..696eaeb5f 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -261,12 +261,12 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
261 vertex_input_ci.pNext = &input_divisor_ci; 261 vertex_input_ci.pNext = &input_divisor_ci;
262 } 262 }
263 263
264 const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()); 264 const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, state.topology);
265 const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ 265 const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{
266 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 266 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
267 .pNext = nullptr, 267 .pNext = nullptr,
268 .flags = 0, 268 .flags = 0,
269 .topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()), 269 .topology = MaxwellToVK::PrimitiveTopology(device, state.topology),
270 .primitiveRestartEnable = state.primitive_restart_enable != 0 && 270 .primitiveRestartEnable = state.primitive_restart_enable != 0 &&
271 SupportsPrimitiveRestart(input_assembly_topology), 271 SupportsPrimitiveRestart(input_assembly_topology),
272 }; 272 };
@@ -400,7 +400,6 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
400 static constexpr std::array extended{ 400 static constexpr std::array extended{
401 VK_DYNAMIC_STATE_CULL_MODE_EXT, 401 VK_DYNAMIC_STATE_CULL_MODE_EXT,
402 VK_DYNAMIC_STATE_FRONT_FACE_EXT, 402 VK_DYNAMIC_STATE_FRONT_FACE_EXT,
403 VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT,
404 VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT, 403 VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT,
405 VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT, 404 VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT,
406 VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT, 405 VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT,
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 5c038f4bc..dedc9c466 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -331,8 +331,7 @@ void VKPipelineCache::OnShaderRemoval(Shader* shader) {
331std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> 331std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>>
332VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { 332VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) {
333 Specialization specialization; 333 Specialization specialization;
334 if (fixed_state.dynamic_state.Topology() == Maxwell::PrimitiveTopology::Points || 334 if (fixed_state.topology == Maxwell::PrimitiveTopology::Points) {
335 device.IsExtExtendedDynamicStateSupported()) {
336 float point_size; 335 float point_size;
337 std::memcpy(&point_size, &fixed_state.point_size, sizeof(float)); 336 std::memcpy(&point_size, &fixed_state.point_size, sizeof(float));
338 specialization.point_size = point_size; 337 specialization.point_size = point_size;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index f3c2483c8..e0fb8693f 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -948,7 +948,6 @@ void RasterizerVulkan::UpdateDynamicStates() {
948 UpdateDepthWriteEnable(regs); 948 UpdateDepthWriteEnable(regs);
949 UpdateDepthCompareOp(regs); 949 UpdateDepthCompareOp(regs);
950 UpdateFrontFace(regs); 950 UpdateFrontFace(regs);
951 UpdatePrimitiveTopology(regs);
952 UpdateStencilOp(regs); 951 UpdateStencilOp(regs);
953 UpdateStencilTestEnable(regs); 952 UpdateStencilTestEnable(regs);
954 } 953 }
@@ -1418,16 +1417,6 @@ void RasterizerVulkan::UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs) {
1418 [front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); }); 1417 [front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); });
1419} 1418}
1420 1419
1421void RasterizerVulkan::UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs) {
1422 const Maxwell::PrimitiveTopology primitive_topology = regs.draw.topology.Value();
1423 if (!state_tracker.ChangePrimitiveTopology(primitive_topology)) {
1424 return;
1425 }
1426 scheduler.Record([this, primitive_topology](vk::CommandBuffer cmdbuf) {
1427 cmdbuf.SetPrimitiveTopologyEXT(MaxwellToVK::PrimitiveTopology(device, primitive_topology));
1428 });
1429}
1430
1431void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) { 1420void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) {
1432 if (!state_tracker.TouchStencilOp()) { 1421 if (!state_tracker.TouchStencilOp()) {
1433 return; 1422 return;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index b47c8fc13..237e51fa4 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -259,7 +259,6 @@ private:
259 void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs); 259 void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs);
260 void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs); 260 void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs);
261 void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs); 261 void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs);
262 void UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs);
263 void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); 262 void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs);
264 void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); 263 void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
265 264
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index cd7d7a4e4..a20452b87 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -272,12 +272,19 @@ bool IsPrecise(Operation operand) {
272 return false; 272 return false;
273} 273}
274 274
275u32 ShaderVersion(const VKDevice& device) {
276 if (device.InstanceApiVersion() < VK_API_VERSION_1_1) {
277 return 0x00010000;
278 }
279 return 0x00010300;
280}
281
275class SPIRVDecompiler final : public Sirit::Module { 282class SPIRVDecompiler final : public Sirit::Module {
276public: 283public:
277 explicit SPIRVDecompiler(const VKDevice& device, const ShaderIR& ir, ShaderType stage, 284 explicit SPIRVDecompiler(const VKDevice& device, const ShaderIR& ir, ShaderType stage,
278 const Registry& registry, const Specialization& specialization) 285 const Registry& registry, const Specialization& specialization)
279 : Module(0x00010300), device{device}, ir{ir}, stage{stage}, header{ir.GetHeader()}, 286 : Module(ShaderVersion(device)), device{device}, ir{ir}, stage{stage},
280 registry{registry}, specialization{specialization} { 287 header{ir.GetHeader()}, registry{registry}, specialization{specialization} {
281 if (stage != ShaderType::Compute) { 288 if (stage != ShaderType::Compute) {
282 transform_feedback = BuildTransformFeedback(registry.GetGraphicsInfo()); 289 transform_feedback = BuildTransformFeedback(registry.GetGraphicsInfo());
283 } 290 }
@@ -293,6 +300,7 @@ public:
293 AddCapability(spv::Capability::DrawParameters); 300 AddCapability(spv::Capability::DrawParameters);
294 AddCapability(spv::Capability::SubgroupBallotKHR); 301 AddCapability(spv::Capability::SubgroupBallotKHR);
295 AddCapability(spv::Capability::SubgroupVoteKHR); 302 AddCapability(spv::Capability::SubgroupVoteKHR);
303 AddExtension("SPV_KHR_16bit_storage");
296 AddExtension("SPV_KHR_shader_ballot"); 304 AddExtension("SPV_KHR_shader_ballot");
297 AddExtension("SPV_KHR_subgroup_vote"); 305 AddExtension("SPV_KHR_subgroup_vote");
298 AddExtension("SPV_KHR_storage_buffer_storage_class"); 306 AddExtension("SPV_KHR_storage_buffer_storage_class");
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
index 2598440fb..c034558a3 100644
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ b/src/video_core/renderer_vulkan/wrapper.cpp
@@ -11,6 +11,7 @@
11#include <vector> 11#include <vector>
12 12
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/logging/log.h"
14 15
15#include "video_core/renderer_vulkan/wrapper.h" 16#include "video_core/renderer_vulkan/wrapper.h"
16 17
@@ -415,18 +416,17 @@ VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffe
415 return VK_SUCCESS; 416 return VK_SUCCESS;
416} 417}
417 418
418Instance Instance::Create(Span<const char*> layers, Span<const char*> extensions, 419Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
419 InstanceDispatch& dld) noexcept { 420 InstanceDispatch& dld) noexcept {
420 static constexpr VkApplicationInfo application_info{ 421 const VkApplicationInfo application_info{
421 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 422 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
422 .pNext = nullptr, 423 .pNext = nullptr,
423 .pApplicationName = "yuzu Emulator", 424 .pApplicationName = "yuzu Emulator",
424 .applicationVersion = VK_MAKE_VERSION(0, 1, 0), 425 .applicationVersion = VK_MAKE_VERSION(0, 1, 0),
425 .pEngineName = "yuzu Emulator", 426 .pEngineName = "yuzu Emulator",
426 .engineVersion = VK_MAKE_VERSION(0, 1, 0), 427 .engineVersion = VK_MAKE_VERSION(0, 1, 0),
427 .apiVersion = VK_API_VERSION_1_1, 428 .apiVersion = version,
428 }; 429 };
429
430 const VkInstanceCreateInfo ci{ 430 const VkInstanceCreateInfo ci{
431 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 431 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
432 .pNext = nullptr, 432 .pNext = nullptr,
@@ -818,6 +818,21 @@ VkPhysicalDeviceMemoryProperties PhysicalDevice::GetMemoryProperties() const noe
818 return properties; 818 return properties;
819} 819}
820 820
821u32 AvailableVersion(const InstanceDispatch& dld) noexcept {
822 PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion;
823 if (!Proc(vkEnumerateInstanceVersion, dld, "vkEnumerateInstanceVersion")) {
824 // If the procedure is not found, Vulkan 1.0 is assumed
825 return VK_API_VERSION_1_0;
826 }
827 u32 version;
828 if (const VkResult result = vkEnumerateInstanceVersion(&version); result != VK_SUCCESS) {
829 LOG_ERROR(Render_Vulkan, "vkEnumerateInstanceVersion returned {}, assuming Vulkan 1.1",
830 ToString(result));
831 return VK_API_VERSION_1_1;
832 }
833 return version;
834}
835
821std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties( 836std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(
822 const InstanceDispatch& dld) { 837 const InstanceDispatch& dld) {
823 u32 num; 838 u32 num;
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h
index 234e01693..f64919623 100644
--- a/src/video_core/renderer_vulkan/wrapper.h
+++ b/src/video_core/renderer_vulkan/wrapper.h
@@ -564,7 +564,7 @@ class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> {
564 564
565public: 565public:
566 /// Creates a Vulkan instance. Use "operator bool" for error handling. 566 /// Creates a Vulkan instance. Use "operator bool" for error handling.
567 static Instance Create(Span<const char*> layers, Span<const char*> extensions, 567 static Instance Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
568 InstanceDispatch& dld) noexcept; 568 InstanceDispatch& dld) noexcept;
569 569
570 /// Enumerates physical devices. 570 /// Enumerates physical devices.
@@ -1090,6 +1090,8 @@ private:
1090 const DeviceDispatch* dld; 1090 const DeviceDispatch* dld;
1091}; 1091};
1092 1092
1093u32 AvailableVersion(const InstanceDispatch& dld) noexcept;
1094
1093std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties( 1095std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(
1094 const InstanceDispatch& dld); 1096 const InstanceDispatch& dld);
1095 1097
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 698cb1940..f58ca29d7 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -256,11 +256,6 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
256 ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot, 256 ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot,
257 }; 257 };
258 258
259 mod_buttons = {
260 ui->buttonLStickMod,
261 ui->buttonRStickMod,
262 };
263
264 analog_map_buttons = {{ 259 analog_map_buttons = {{
265 { 260 {
266 ui->buttonLStickUp, 261 ui->buttonLStickUp,
@@ -284,6 +279,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
284 analog_map_deadzone_label = {ui->labelLStickDeadzone, ui->labelRStickDeadzone}; 279 analog_map_deadzone_label = {ui->labelLStickDeadzone, ui->labelRStickDeadzone};
285 analog_map_deadzone_slider = {ui->sliderLStickDeadzone, ui->sliderRStickDeadzone}; 280 analog_map_deadzone_slider = {ui->sliderLStickDeadzone, ui->sliderRStickDeadzone};
286 analog_map_modifier_groupbox = {ui->buttonLStickModGroup, ui->buttonRStickModGroup}; 281 analog_map_modifier_groupbox = {ui->buttonLStickModGroup, ui->buttonRStickModGroup};
282 analog_map_modifier_button = {ui->buttonLStickMod, ui->buttonRStickMod};
287 analog_map_modifier_label = {ui->labelLStickModifierRange, ui->labelRStickModifierRange}; 283 analog_map_modifier_label = {ui->labelLStickModifierRange, ui->labelRStickModifierRange};
288 analog_map_modifier_slider = {ui->sliderLStickModifierRange, ui->sliderRStickModifierRange}; 284 analog_map_modifier_slider = {ui->sliderLStickModifierRange, ui->sliderRStickModifierRange};
289 analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup}; 285 analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup};
@@ -394,20 +390,26 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
394 } 390 }
395 391
396 // Handle clicks for the modifier buttons as well. 392 // Handle clicks for the modifier buttons as well.
397 ConfigureButtonClick(mod_buttons[analog_id], &stick_mod_param[analog_id], 393 connect(analog_map_modifier_button[analog_id], &QPushButton::clicked, [=, this] {
398 Config::default_stick_mod[analog_id], 394 HandleClick(
399 InputCommon::Polling::DeviceType::Button); 395 analog_map_modifier_button[analog_id],
396 [=, this](const Common::ParamPackage& params) {
397 analogs_param[analog_id].Set("modifier", params.Serialize());
398 },
399 InputCommon::Polling::DeviceType::Button);
400 });
400 401
401 mod_buttons[analog_id]->setContextMenuPolicy(Qt::CustomContextMenu); 402 analog_map_modifier_button[analog_id]->setContextMenuPolicy(Qt::CustomContextMenu);
402 403
403 connect(mod_buttons[analog_id], &QPushButton::customContextMenuRequested, 404 connect(analog_map_modifier_button[analog_id], &QPushButton::customContextMenuRequested,
404 [=, this](const QPoint& menu_location) { 405 [=, this](const QPoint& menu_location) {
405 QMenu context_menu; 406 QMenu context_menu;
406 context_menu.addAction(tr("Clear"), [&] { 407 context_menu.addAction(tr("Clear"), [&] {
407 stick_mod_param[analog_id].Clear(); 408 analogs_param[analog_id].Set("modifier", "");
408 mod_buttons[analog_id]->setText(tr("[not set]")); 409 analog_map_modifier_button[analog_id]->setText(tr("[not set]"));
409 }); 410 });
410 context_menu.exec(mod_buttons[analog_id]->mapToGlobal(menu_location)); 411 context_menu.exec(
412 analog_map_modifier_button[analog_id]->mapToGlobal(menu_location));
411 }); 413 });
412 414
413 connect(analog_map_range_spinbox[analog_id], qOverload<int>(&QSpinBox::valueChanged), 415 connect(analog_map_range_spinbox[analog_id], qOverload<int>(&QSpinBox::valueChanged),
@@ -636,8 +638,8 @@ void ConfigureInputPlayer::RestoreDefaults() {
636 SetAnalogParam(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]); 638 SetAnalogParam(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
637 } 639 }
638 640
639 stick_mod_param[analog_id] = Common::ParamPackage( 641 analogs_param[analog_id].Set(
640 InputCommon::GenerateKeyboardParam(Config::default_stick_mod[analog_id])); 642 "modifier", InputCommon::GenerateKeyboardParam(Config::default_stick_mod[analog_id]));
641 } 643 }
642 644
643 for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { 645 for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
@@ -669,8 +671,6 @@ void ConfigureInputPlayer::ClearAll() {
669 671
670 analogs_param[analog_id].Clear(); 672 analogs_param[analog_id].Clear();
671 } 673 }
672
673 stick_mod_param[analog_id].Clear();
674 } 674 }
675 675
676 for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { 676 for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
@@ -707,7 +707,8 @@ void ConfigureInputPlayer::UpdateUI() {
707 AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id])); 707 AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
708 } 708 }
709 709
710 mod_buttons[analog_id]->setText(ButtonToText(stick_mod_param[analog_id])); 710 analog_map_modifier_button[analog_id]->setText(
711 ButtonToText(Common::ParamPackage{analogs_param[analog_id].Get("modifier", "")}));
711 712
712 const auto deadzone_label = analog_map_deadzone_label[analog_id]; 713 const auto deadzone_label = analog_map_deadzone_label[analog_id];
713 const auto deadzone_slider = analog_map_deadzone_slider[analog_id]; 714 const auto deadzone_slider = analog_map_deadzone_slider[analog_id];
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index ce443dec5..c19aefffa 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -131,26 +131,25 @@ private:
131 131
132 std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param; 132 std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param;
133 std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param; 133 std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
134 std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> stick_mod_param;
135 std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions> motions_param; 134 std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions> motions_param;
136 135
137 static constexpr int ANALOG_SUB_BUTTONS_NUM = 4; 136 static constexpr int ANALOG_SUB_BUTTONS_NUM = 4;
138 137
139 /// Each button input is represented by a QPushButton. 138 /// Each button input is represented by a QPushButton.
140 std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map; 139 std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map;
141 /// Each motion input is represented by a QPushButton.
142 std::array<QPushButton*, Settings::NativeMotion::NumMotions> motion_map;
143 /// Extra buttons for the modifiers.
144 std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> mod_buttons;
145 140
146 /// A group of four QPushButtons represent one analog input. The buttons each represent up, 141 /// A group of four QPushButtons represent one analog input. The buttons each represent up,
147 /// down, left, right, respectively. 142 /// down, left, right, respectively.
148 std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs> 143 std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs>
149 analog_map_buttons; 144 analog_map_buttons;
150 145
146 /// Each motion input is represented by a QPushButton.
147 std::array<QPushButton*, Settings::NativeMotion::NumMotions> motion_map;
148
151 std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_label; 149 std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_label;
152 std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_slider; 150 std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_slider;
153 std::array<QGroupBox*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_groupbox; 151 std::array<QGroupBox*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_groupbox;
152 std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_button;
154 std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_label; 153 std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_label;
155 std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_slider; 154 std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_slider;
156 std::array<QGroupBox*, Settings::NativeAnalog::NumAnalogs> analog_map_range_groupbox; 155 std::array<QGroupBox*, Settings::NativeAnalog::NumAnalogs> analog_map_range_groupbox;
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp
index c7d085151..170574d9b 100644
--- a/src/yuzu/configuration/configure_motion_touch.cpp
+++ b/src/yuzu/configuration/configure_motion_touch.cpp
@@ -193,7 +193,7 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() {
193 udp_test_in_progress = true; 193 udp_test_in_progress = true;
194 InputCommon::CemuhookUDP::TestCommunication( 194 InputCommon::CemuhookUDP::TestCommunication(
195 ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 195 ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()),
196 static_cast<u8>(ui->udp_pad_index->currentIndex()), 24872, 196 static_cast<u32>(ui->udp_pad_index->currentIndex()), 24872,
197 [this] { 197 [this] {
198 LOG_INFO(Frontend, "UDP input test success"); 198 LOG_INFO(Frontend, "UDP input test success");
199 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true)); 199 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true));