summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--README.md2
-rw-r--r--externals/CMakeLists.txt4
m---------externals/cubeb0
-rw-r--r--externals/find-modules/FindUnicorn.cmake18
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/common/input.h18
-rw-r--r--src/common/logging/filter.cpp1
-rw-r--r--src/common/logging/types.h1
-rw-r--r--src/common/x64/cpu_detect.cpp12
-rw-r--r--src/core/CMakeLists.txt6
-rw-r--r--src/core/core.cpp6
-rw-r--r--src/core/core.h3
-rw-r--r--src/core/cpu_manager.cpp23
-rw-r--r--src/core/hid/emulated_console.cpp21
-rw-r--r--src/core/hid/emulated_console.h4
-rw-r--r--src/core/hid/emulated_controller.cpp99
-rw-r--r--src/core/hid/emulated_controller.h13
-rw-r--r--src/core/hid/emulated_devices.cpp66
-rw-r--r--src/core/hid/emulated_devices.h11
-rw-r--r--src/core/hid/hid_core.cpp10
-rw-r--r--src/core/hid/hid_core.h3
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.cpp2
-rw-r--r--src/core/hle/kernel/k_address_arbiter.cpp92
-rw-r--r--src/core/hle/kernel/k_auto_object.h4
-rw-r--r--src/core/hle/kernel/k_class_token.cpp5
-rw-r--r--src/core/hle/kernel/k_code_memory.cpp146
-rw-r--r--src/core/hle/kernel/k_code_memory.h66
-rw-r--r--src/core/hle/kernel/k_condition_variable.cpp245
-rw-r--r--src/core/hle/kernel/k_condition_variable.h2
-rw-r--r--src/core/hle/kernel/k_handle_table.cpp6
-rw-r--r--src/core/hle/kernel/k_handle_table.h2
-rw-r--r--src/core/hle/kernel/k_light_condition_variable.cpp80
-rw-r--r--src/core/hle/kernel/k_light_condition_variable.h58
-rw-r--r--src/core/hle/kernel/k_light_lock.cpp72
-rw-r--r--src/core/hle/kernel/k_light_lock.h2
-rw-r--r--src/core/hle/kernel/k_memory_block.h20
-rw-r--r--src/core/hle/kernel/k_page_linked_list.h4
-rw-r--r--src/core/hle/kernel/k_page_table.cpp119
-rw-r--r--src/core/hle/kernel/k_page_table.h8
-rw-r--r--src/core/hle/kernel/k_process.cpp28
-rw-r--r--src/core/hle/kernel/k_process.h1
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp101
-rw-r--r--src/core/hle/kernel/k_scheduler.h2
-rw-r--r--src/core/hle/kernel/k_scheduler_lock.h10
-rw-r--r--src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h1
-rw-r--r--src/core/hle/kernel/k_server_session.cpp3
-rw-r--r--src/core/hle/kernel/k_synchronization_object.cpp151
-rw-r--r--src/core/hle/kernel/k_synchronization_object.h32
-rw-r--r--src/core/hle/kernel/k_thread.cpp246
-rw-r--r--src/core/hle/kernel/k_thread.h72
-rw-r--r--src/core/hle/kernel/k_thread_queue.cpp49
-rw-r--r--src/core/hle/kernel/k_thread_queue.h74
-rw-r--r--src/core/hle/kernel/kernel.cpp81
-rw-r--r--src/core/hle/kernel/kernel.h9
-rw-r--r--src/core/hle/kernel/service_thread.cpp33
-rw-r--r--src/core/hle/kernel/svc.cpp249
-rw-r--r--src/core/hle/kernel/svc_wrap.h27
-rw-r--r--src/core/hle/kernel/time_manager.cpp6
-rw-r--r--src/core/hle/service/glue/glue.cpp4
-rw-r--r--src/core/hle/service/glue/notif.cpp44
-rw-r--r--src/core/hle/service/glue/notif.h25
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp165
-rw-r--r--src/core/hle/service/hid/controllers/npad.h8
-rw-r--r--src/core/hle/service/hid/hid.cpp26
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp13
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h3
-rw-r--r--src/input_common/drivers/gc_adapter.cpp6
-rw-r--r--src/input_common/drivers/gc_adapter.h8
-rw-r--r--src/input_common/drivers/keyboard.cpp2
-rw-r--r--src/input_common/drivers/keyboard.h4
-rw-r--r--src/input_common/drivers/mouse.cpp2
-rw-r--r--src/input_common/drivers/mouse.h4
-rw-r--r--src/input_common/drivers/sdl_driver.cpp19
-rw-r--r--src/input_common/drivers/sdl_driver.h14
-rw-r--r--src/input_common/drivers/tas_input.cpp95
-rw-r--r--src/input_common/drivers/tas_input.h65
-rw-r--r--src/input_common/drivers/touch_screen.cpp2
-rw-r--r--src/input_common/drivers/touch_screen.h4
-rw-r--r--src/input_common/drivers/udp_client.cpp2
-rw-r--r--src/input_common/drivers/udp_client.h6
-rw-r--r--src/input_common/helpers/stick_from_buttons.cpp75
-rw-r--r--src/input_common/helpers/touch_from_buttons.cpp11
-rw-r--r--src/input_common/input_engine.cpp86
-rw-r--r--src/input_common/input_engine.h53
-rw-r--r--src/input_common/input_mapping.h28
-rw-r--r--src/input_common/input_poller.cpp39
-rw-r--r--src/input_common/input_poller.h212
-rw-r--r--src/shader_recompiler/CMakeLists.txt12
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_barriers.cpp22
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_composite.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp31
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_control_flow.cpp18
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_convert.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_floating_point.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_image.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_logical.cpp26
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp171
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_select.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_shared_memory.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_special.cpp95
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_undefined.cpp30
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/glasm_emit_context.cpp (renamed from src/shader_recompiler/backend/glasm/emit_context.cpp)2
-rw-r--r--src/shader_recompiler/backend/glasm/glasm_emit_context.h (renamed from src/shader_recompiler/backend/glasm/emit_context.h)0
-rw-r--r--src/shader_recompiler/backend/glasm/reg_alloc.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_barriers.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_composite.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_control_flow.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_convert.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_image.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_logical.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_memory.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_select.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_shared_memory.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_special.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_undefined.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/glsl_emit_context.cpp (renamed from src/shader_recompiler/backend/glsl/emit_context.cpp)2
-rw-r--r--src/shader_recompiler/backend/glsl/glsl_emit_context.h (renamed from src/shader_recompiler/backend/glsl/emit_context.h)0
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.h4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image_atomic.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_select.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_special.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp (renamed from src/shader_recompiler/backend/spirv/emit_context.cpp)2
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.h (renamed from src/shader_recompiler/backend/spirv/emit_context.h)0
-rw-r--r--src/video_core/gpu.cpp44
-rw-r--r--src/video_core/gpu.h4
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp6
-rw-r--r--src/video_core/texture_cache/texture_cache.h14
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp1
-rw-r--r--src/yuzu/applets/qt_software_keyboard.cpp23
-rw-r--r--src/yuzu/debugger/profiler.cpp2
-rw-r--r--src/yuzu/main.cpp27
165 files changed, 2643 insertions, 1453 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c834e9396..a810e11c2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -131,7 +131,7 @@ add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS)
131if (MSVC) 131if (MSVC)
132 add_compile_options($<$<COMPILE_LANGUAGE:CXX>:/std:c++latest>) 132 add_compile_options($<$<COMPILE_LANGUAGE:CXX>:/std:c++latest>)
133 133
134 # cubeb and boost still make use of deprecated result_of. 134 # boost still makes use of deprecated result_of.
135 add_definitions(-D_HAS_DEPRECATED_RESULT_OF) 135 add_definitions(-D_HAS_DEPRECATED_RESULT_OF)
136else() 136else()
137 set(CMAKE_CXX_STANDARD 20) 137 set(CMAKE_CXX_STANDARD 20)
diff --git a/README.md b/README.md
index 2cb030aed..c09d49ca4 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ It is written in C++ with portability in mind, and we actively maintain builds f
17 alt="Azure Mainline CI Build Status"> 17 alt="Azure Mainline CI Build Status">
18 </a> 18 </a>
19 <a href="https://discord.com/invite/u77vRWY"> 19 <a href="https://discord.com/invite/u77vRWY">
20 <img src="https://img.shields.io/discord/398318088170242053?color=%237289DA&label=yuzu&logo=discord&logoColor=white" 20 <img src="https://img.shields.io/discord/398318088170242053?color=5865F2&label=yuzu&logo=discord&logoColor=white"
21 alt="Discord"> 21 alt="Discord">
22 </a> 22 </a>
23</p> 23</p>
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index a76a3d800..64d1e6aec 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -44,10 +44,6 @@ target_include_directories(mbedtls PUBLIC ./mbedtls/include)
44add_library(microprofile INTERFACE) 44add_library(microprofile INTERFACE)
45target_include_directories(microprofile INTERFACE ./microprofile) 45target_include_directories(microprofile INTERFACE ./microprofile)
46 46
47# Unicorn
48add_library(unicorn-headers INTERFACE)
49target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
50
51# libusb 47# libusb
52if (NOT LIBUSB_FOUND OR YUZU_USE_BUNDLED_LIBUSB) 48if (NOT LIBUSB_FOUND OR YUZU_USE_BUNDLED_LIBUSB)
53 add_subdirectory(libusb) 49 add_subdirectory(libusb)
diff --git a/externals/cubeb b/externals/cubeb
Subproject 1d66483ad2b93f0e00e175f9480c771af90003a Subproject 75d9d125ee655ef80f3bfcd97ae5a805931042b
diff --git a/externals/find-modules/FindUnicorn.cmake b/externals/find-modules/FindUnicorn.cmake
deleted file mode 100644
index a0f2a71f6..000000000
--- a/externals/find-modules/FindUnicorn.cmake
+++ /dev/null
@@ -1,18 +0,0 @@
1# Exports:
2# LIBUNICORN_FOUND
3# LIBUNICORN_INCLUDE_DIR
4# LIBUNICORN_LIBRARY
5
6find_path(LIBUNICORN_INCLUDE_DIR
7 unicorn/unicorn.h
8 HINTS $ENV{UNICORNDIR}
9 PATH_SUFFIXES include)
10
11find_library(LIBUNICORN_LIBRARY
12 NAMES unicorn
13 HINTS $ENV{UNICORNDIR})
14
15include(FindPackageHandleStandardArgs)
16find_package_handle_standard_args(unicorn DEFAULT_MSG
17 LIBUNICORN_LIBRARY LIBUNICORN_INCLUDE_DIR)
18mark_as_advanced(LIBUNICORN_INCLUDE_DIR LIBUNICORN_LIBRARY)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 63dd9febf..19d16147d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -24,6 +24,7 @@ if (MSVC)
24 # /W3 - Level 3 warnings 24 # /W3 - Level 3 warnings
25 # /MP - Multi-threaded compilation 25 # /MP - Multi-threaded compilation
26 # /Zi - Output debugging information 26 # /Zi - Output debugging information
27 # /Zm - Specifies the precompiled header memory allocation limit
27 # /Zo - Enhanced debug info for optimized builds 28 # /Zo - Enhanced debug info for optimized builds
28 # /permissive- - Enables stricter C++ standards conformance checks 29 # /permissive- - Enables stricter C++ standards conformance checks
29 # /EHsc - C++-only exception handling semantics 30 # /EHsc - C++-only exception handling semantics
@@ -36,6 +37,7 @@ if (MSVC)
36 add_compile_options( 37 add_compile_options(
37 /MP 38 /MP
38 /Zi 39 /Zi
40 /Zm200
39 /Zo 41 /Zo
40 /permissive- 42 /permissive-
41 /EHsc 43 /EHsc
diff --git a/src/common/input.h b/src/common/input.h
index eaee0bdea..f775a4c01 100644
--- a/src/common/input.h
+++ b/src/common/input.h
@@ -227,7 +227,7 @@ struct CallbackStatus {
227 227
228// Triggered once every input change 228// Triggered once every input change
229struct InputCallback { 229struct InputCallback {
230 std::function<void(CallbackStatus)> on_change; 230 std::function<void(const CallbackStatus&)> on_change;
231}; 231};
232 232
233/// An abstract class template for an input device (a button, an analog input, etc.). 233/// An abstract class template for an input device (a button, an analog input, etc.).
@@ -236,14 +236,10 @@ public:
236 virtual ~InputDevice() = default; 236 virtual ~InputDevice() = default;
237 237
238 // Request input device to update if necessary 238 // Request input device to update if necessary
239 virtual void SoftUpdate() { 239 virtual void SoftUpdate() {}
240 return;
241 }
242 240
243 // Force input device to update data regardless of the current state 241 // Force input device to update data regardless of the current state
244 virtual void ForceUpdate() { 242 virtual void ForceUpdate() {}
245 return;
246 }
247 243
248 // Sets the function to be triggered when input changes 244 // Sets the function to be triggered when input changes
249 void SetCallback(InputCallback callback_) { 245 void SetCallback(InputCallback callback_) {
@@ -251,7 +247,7 @@ public:
251 } 247 }
252 248
253 // Triggers the function set in the callback 249 // Triggers the function set in the callback
254 void TriggerOnChange(CallbackStatus status) { 250 void TriggerOnChange(const CallbackStatus& status) {
255 if (callback.on_change) { 251 if (callback.on_change) {
256 callback.on_change(status); 252 callback.on_change(status);
257 } 253 }
@@ -266,11 +262,9 @@ class OutputDevice {
266public: 262public:
267 virtual ~OutputDevice() = default; 263 virtual ~OutputDevice() = default;
268 264
269 virtual void SetLED([[maybe_unused]] LedStatus led_status) { 265 virtual void SetLED([[maybe_unused]] const LedStatus& led_status) {}
270 return;
271 }
272 266
273 virtual VibrationError SetVibration([[maybe_unused]] VibrationStatus vibration_status) { 267 virtual VibrationError SetVibration([[maybe_unused]] const VibrationStatus& vibration_status) {
274 return VibrationError::NotSupported; 268 return VibrationError::NotSupported;
275 } 269 }
276 270
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 42744c994..b898a652c 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -114,6 +114,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
114 SUB(Service, NGCT) \ 114 SUB(Service, NGCT) \
115 SUB(Service, NIFM) \ 115 SUB(Service, NIFM) \
116 SUB(Service, NIM) \ 116 SUB(Service, NIM) \
117 SUB(Service, NOTIF) \
117 SUB(Service, NPNS) \ 118 SUB(Service, NPNS) \
118 SUB(Service, NS) \ 119 SUB(Service, NS) \
119 SUB(Service, NVDRV) \ 120 SUB(Service, NVDRV) \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index 2d21fc483..9ed0c7ad6 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -82,6 +82,7 @@ enum class Class : u8 {
82 Service_NGCT, ///< The NGCT (No Good Content for Terra) service 82 Service_NGCT, ///< The NGCT (No Good Content for Terra) service
83 Service_NIFM, ///< The NIFM (Network interface) service 83 Service_NIFM, ///< The NIFM (Network interface) service
84 Service_NIM, ///< The NIM service 84 Service_NIM, ///< The NIM service
85 Service_NOTIF, ///< The NOTIF (Notification) service
85 Service_NPNS, ///< The NPNS service 86 Service_NPNS, ///< The NPNS service
86 Service_NS, ///< The NS services 87 Service_NS, ///< The NS services
87 Service_NVDRV, ///< The NVDRV (Nvidia driver) service 88 Service_NVDRV, ///< The NVDRV (Nvidia driver) service
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp
index fccd2eee5..fbeacc7e2 100644
--- a/src/common/x64/cpu_detect.cpp
+++ b/src/common/x64/cpu_detect.cpp
@@ -71,9 +71,6 @@ static CPUCaps Detect() {
71 else 71 else
72 caps.manufacturer = Manufacturer::Unknown; 72 caps.manufacturer = Manufacturer::Unknown;
73 73
74 u32 family = {};
75 u32 model = {};
76
77 __cpuid(cpu_id, 0x80000000); 74 __cpuid(cpu_id, 0x80000000);
78 75
79 u32 max_ex_fn = cpu_id[0]; 76 u32 max_ex_fn = cpu_id[0];
@@ -84,15 +81,6 @@ static CPUCaps Detect() {
84 // Detect family and other miscellaneous features 81 // Detect family and other miscellaneous features
85 if (max_std_fn >= 1) { 82 if (max_std_fn >= 1) {
86 __cpuid(cpu_id, 0x00000001); 83 __cpuid(cpu_id, 0x00000001);
87 family = (cpu_id[0] >> 8) & 0xf;
88 model = (cpu_id[0] >> 4) & 0xf;
89 if (family == 0xf) {
90 family += (cpu_id[0] >> 20) & 0xff;
91 }
92 if (family >= 6) {
93 model += ((cpu_id[0] >> 16) & 0xf) << 4;
94 }
95
96 if ((cpu_id[3] >> 25) & 1) 84 if ((cpu_id[3] >> 25) & 1)
97 caps.sse = true; 85 caps.sse = true;
98 if ((cpu_id[3] >> 26) & 1) 86 if ((cpu_id[3] >> 26) & 1)
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index eee8e2ccd..49bed614a 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -179,12 +179,15 @@ add_library(core STATIC
179 hle/kernel/k_client_port.h 179 hle/kernel/k_client_port.h
180 hle/kernel/k_client_session.cpp 180 hle/kernel/k_client_session.cpp
181 hle/kernel/k_client_session.h 181 hle/kernel/k_client_session.h
182 hle/kernel/k_code_memory.cpp
183 hle/kernel/k_code_memory.h
182 hle/kernel/k_condition_variable.cpp 184 hle/kernel/k_condition_variable.cpp
183 hle/kernel/k_condition_variable.h 185 hle/kernel/k_condition_variable.h
184 hle/kernel/k_event.cpp 186 hle/kernel/k_event.cpp
185 hle/kernel/k_event.h 187 hle/kernel/k_event.h
186 hle/kernel/k_handle_table.cpp 188 hle/kernel/k_handle_table.cpp
187 hle/kernel/k_handle_table.h 189 hle/kernel/k_handle_table.h
190 hle/kernel/k_light_condition_variable.cpp
188 hle/kernel/k_light_condition_variable.h 191 hle/kernel/k_light_condition_variable.h
189 hle/kernel/k_light_lock.cpp 192 hle/kernel/k_light_lock.cpp
190 hle/kernel/k_light_lock.h 193 hle/kernel/k_light_lock.h
@@ -237,6 +240,7 @@ add_library(core STATIC
237 hle/kernel/k_system_control.h 240 hle/kernel/k_system_control.h
238 hle/kernel/k_thread.cpp 241 hle/kernel/k_thread.cpp
239 hle/kernel/k_thread.h 242 hle/kernel/k_thread.h
243 hle/kernel/k_thread_queue.cpp
240 hle/kernel/k_thread_queue.h 244 hle/kernel/k_thread_queue.h
241 hle/kernel/k_trace.h 245 hle/kernel/k_trace.h
242 hle/kernel/k_transfer_memory.cpp 246 hle/kernel/k_transfer_memory.cpp
@@ -408,6 +412,8 @@ add_library(core STATIC
408 hle/service/glue/glue.h 412 hle/service/glue/glue.h
409 hle/service/glue/glue_manager.cpp 413 hle/service/glue/glue_manager.cpp
410 hle/service/glue/glue_manager.h 414 hle/service/glue/glue_manager.h
415 hle/service/glue/notif.cpp
416 hle/service/glue/notif.h
411 hle/service/grc/grc.cpp 417 hle/service/grc/grc.cpp
412 hle/service/grc/grc.h 418 hle/service/grc/grc.h
413 hle/service/hid/hid.cpp 419 hle/service/hid/hid.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 473ab9f81..aa96f709b 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -521,12 +521,6 @@ const ARM_Interface& System::CurrentArmInterface() const {
521 return impl->kernel.CurrentPhysicalCore().ArmInterface(); 521 return impl->kernel.CurrentPhysicalCore().ArmInterface();
522} 522}
523 523
524std::size_t System::CurrentCoreIndex() const {
525 std::size_t core = impl->kernel.GetCurrentHostThreadID();
526 ASSERT(core < Core::Hardware::NUM_CPU_CORES);
527 return core;
528}
529
530Kernel::PhysicalCore& System::CurrentPhysicalCore() { 524Kernel::PhysicalCore& System::CurrentPhysicalCore() {
531 return impl->kernel.CurrentPhysicalCore(); 525 return impl->kernel.CurrentPhysicalCore();
532} 526}
diff --git a/src/core/core.h b/src/core/core.h
index 645e5c241..52ff90359 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -208,9 +208,6 @@ public:
208 /// Gets an ARM interface to the CPU core that is currently running 208 /// Gets an ARM interface to the CPU core that is currently running
209 [[nodiscard]] const ARM_Interface& CurrentArmInterface() const; 209 [[nodiscard]] const ARM_Interface& CurrentArmInterface() const;
210 210
211 /// Gets the index of the currently running CPU core
212 [[nodiscard]] std::size_t CurrentCoreIndex() const;
213
214 /// Gets the physical core for the CPU core that is currently running 211 /// Gets the physical core for the CPU core that is currently running
215 [[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore(); 212 [[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore();
216 213
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 5d43c6e5d..cbcc54891 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -117,17 +117,18 @@ void CpuManager::MultiCoreRunGuestLoop() {
117 physical_core = &kernel.CurrentPhysicalCore(); 117 physical_core = &kernel.CurrentPhysicalCore();
118 } 118 }
119 system.ExitDynarmicProfile(); 119 system.ExitDynarmicProfile();
120 physical_core->ArmInterface().ClearExclusiveState(); 120 {
121 kernel.CurrentScheduler()->RescheduleCurrentCore(); 121 Kernel::KScopedDisableDispatch dd(kernel);
122 physical_core->ArmInterface().ClearExclusiveState();
123 }
122 } 124 }
123} 125}
124 126
125void CpuManager::MultiCoreRunIdleThread() { 127void CpuManager::MultiCoreRunIdleThread() {
126 auto& kernel = system.Kernel(); 128 auto& kernel = system.Kernel();
127 while (true) { 129 while (true) {
128 auto& physical_core = kernel.CurrentPhysicalCore(); 130 Kernel::KScopedDisableDispatch dd(kernel);
129 physical_core.Idle(); 131 kernel.CurrentPhysicalCore().Idle();
130 kernel.CurrentScheduler()->RescheduleCurrentCore();
131 } 132 }
132} 133}
133 134
@@ -135,12 +136,12 @@ void CpuManager::MultiCoreRunSuspendThread() {
135 auto& kernel = system.Kernel(); 136 auto& kernel = system.Kernel();
136 kernel.CurrentScheduler()->OnThreadStart(); 137 kernel.CurrentScheduler()->OnThreadStart();
137 while (true) { 138 while (true) {
138 auto core = kernel.GetCurrentHostThreadID(); 139 auto core = kernel.CurrentPhysicalCoreIndex();
139 auto& scheduler = *kernel.CurrentScheduler(); 140 auto& scheduler = *kernel.CurrentScheduler();
140 Kernel::KThread* current_thread = scheduler.GetCurrentThread(); 141 Kernel::KThread* current_thread = scheduler.GetCurrentThread();
141 Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); 142 Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context);
142 ASSERT(scheduler.ContextSwitchPending()); 143 ASSERT(scheduler.ContextSwitchPending());
143 ASSERT(core == kernel.GetCurrentHostThreadID()); 144 ASSERT(core == kernel.CurrentPhysicalCoreIndex());
144 scheduler.RescheduleCurrentCore(); 145 scheduler.RescheduleCurrentCore();
145 } 146 }
146} 147}
@@ -346,13 +347,9 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
346 sc_sync_first_use = false; 347 sc_sync_first_use = false;
347 } 348 }
348 349
349 // Abort if emulation was killed before the session really starts 350 // Emulation was stopped
350 if (!system.IsPoweredOn()) {
351 return;
352 }
353
354 if (stop_token.stop_requested()) { 351 if (stop_token.stop_requested()) {
355 break; 352 return;
356 } 353 }
357 354
358 auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); 355 auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp
index 80db8e9c6..685ec080c 100644
--- a/src/core/hid/emulated_console.cpp
+++ b/src/core/hid/emulated_console.cpp
@@ -66,9 +66,10 @@ void EmulatedConsole::ReloadInput() {
66 66
67 motion_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(motion_params); 67 motion_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(motion_params);
68 if (motion_devices) { 68 if (motion_devices) {
69 Common::Input::InputCallback motion_callback{ 69 motion_devices->SetCallback({
70 [this](Common::Input::CallbackStatus callback) { SetMotion(callback); }}; 70 .on_change =
71 motion_devices->SetCallback(motion_callback); 71 [this](const Common::Input::CallbackStatus& callback) { SetMotion(callback); },
72 });
72 } 73 }
73 74
74 // Unique index for identifying touch device source 75 // Unique index for identifying touch device source
@@ -78,9 +79,12 @@ void EmulatedConsole::ReloadInput() {
78 if (!touch_device) { 79 if (!touch_device) {
79 continue; 80 continue;
80 } 81 }
81 Common::Input::InputCallback touch_callback{ 82 touch_device->SetCallback({
82 [this, index](Common::Input::CallbackStatus callback) { SetTouch(callback, index); }}; 83 .on_change =
83 touch_device->SetCallback(touch_callback); 84 [this, index](const Common::Input::CallbackStatus& callback) {
85 SetTouch(callback, index);
86 },
87 });
84 index++; 88 index++;
85 } 89 }
86} 90}
@@ -127,7 +131,7 @@ void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
127 ReloadInput(); 131 ReloadInput();
128} 132}
129 133
130void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) { 134void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
131 std::lock_guard lock{mutex}; 135 std::lock_guard lock{mutex};
132 auto& raw_status = console.motion_values.raw_status; 136 auto& raw_status = console.motion_values.raw_status;
133 auto& emulated = console.motion_values.emulated; 137 auto& emulated = console.motion_values.emulated;
@@ -162,8 +166,7 @@ void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) {
162 TriggerOnChange(ConsoleTriggerType::Motion); 166 TriggerOnChange(ConsoleTriggerType::Motion);
163} 167}
164 168
165void EmulatedConsole::SetTouch(Common::Input::CallbackStatus callback, 169void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) {
166 [[maybe_unused]] std::size_t index) {
167 if (index >= console.touch_values.size()) { 170 if (index >= console.touch_values.size()) {
168 return; 171 return;
169 } 172 }
diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h
index bb3d7ab90..3afd284d5 100644
--- a/src/core/hid/emulated_console.h
+++ b/src/core/hid/emulated_console.h
@@ -155,14 +155,14 @@ private:
155 * Updates the motion status of the console 155 * Updates the motion status of the console
156 * @param callback A CallbackStatus containing gyro and accelerometer data 156 * @param callback A CallbackStatus containing gyro and accelerometer data
157 */ 157 */
158 void SetMotion(Common::Input::CallbackStatus callback); 158 void SetMotion(const Common::Input::CallbackStatus& callback);
159 159
160 /** 160 /**
161 * Updates the touch status of the console 161 * Updates the touch status of the console
162 * @param callback A CallbackStatus containing the touch position 162 * @param callback A CallbackStatus containing the touch position
163 * @param index Finger ID to be updated 163 * @param index Finger ID to be updated
164 */ 164 */
165 void SetTouch(Common::Input::CallbackStatus callback, std::size_t index); 165 void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index);
166 166
167 /** 167 /**
168 * Triggers a callback that something has changed on the console status 168 * Triggers a callback that something has changed on the console status
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index fbb19f230..93372445b 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -205,11 +205,12 @@ void EmulatedController::ReloadInput() {
205 continue; 205 continue;
206 } 206 }
207 const auto uuid = Common::UUID{button_params[index].Get("guid", "")}; 207 const auto uuid = Common::UUID{button_params[index].Get("guid", "")};
208 Common::Input::InputCallback button_callback{ 208 button_devices[index]->SetCallback({
209 [this, index, uuid](Common::Input::CallbackStatus callback) { 209 .on_change =
210 SetButton(callback, index, uuid); 210 [this, index, uuid](const Common::Input::CallbackStatus& callback) {
211 }}; 211 SetButton(callback, index, uuid);
212 button_devices[index]->SetCallback(button_callback); 212 },
213 });
213 button_devices[index]->ForceUpdate(); 214 button_devices[index]->ForceUpdate();
214 } 215 }
215 216
@@ -218,11 +219,12 @@ void EmulatedController::ReloadInput() {
218 continue; 219 continue;
219 } 220 }
220 const auto uuid = Common::UUID{stick_params[index].Get("guid", "")}; 221 const auto uuid = Common::UUID{stick_params[index].Get("guid", "")};
221 Common::Input::InputCallback stick_callback{ 222 stick_devices[index]->SetCallback({
222 [this, index, uuid](Common::Input::CallbackStatus callback) { 223 .on_change =
223 SetStick(callback, index, uuid); 224 [this, index, uuid](const Common::Input::CallbackStatus& callback) {
224 }}; 225 SetStick(callback, index, uuid);
225 stick_devices[index]->SetCallback(stick_callback); 226 },
227 });
226 stick_devices[index]->ForceUpdate(); 228 stick_devices[index]->ForceUpdate();
227 } 229 }
228 230
@@ -231,11 +233,12 @@ void EmulatedController::ReloadInput() {
231 continue; 233 continue;
232 } 234 }
233 const auto uuid = Common::UUID{trigger_params[index].Get("guid", "")}; 235 const auto uuid = Common::UUID{trigger_params[index].Get("guid", "")};
234 Common::Input::InputCallback trigger_callback{ 236 trigger_devices[index]->SetCallback({
235 [this, index, uuid](Common::Input::CallbackStatus callback) { 237 .on_change =
236 SetTrigger(callback, index, uuid); 238 [this, index, uuid](const Common::Input::CallbackStatus& callback) {
237 }}; 239 SetTrigger(callback, index, uuid);
238 trigger_devices[index]->SetCallback(trigger_callback); 240 },
241 });
239 trigger_devices[index]->ForceUpdate(); 242 trigger_devices[index]->ForceUpdate();
240 } 243 }
241 244
@@ -243,9 +246,12 @@ void EmulatedController::ReloadInput() {
243 if (!battery_devices[index]) { 246 if (!battery_devices[index]) {
244 continue; 247 continue;
245 } 248 }
246 Common::Input::InputCallback battery_callback{ 249 battery_devices[index]->SetCallback({
247 [this, index](Common::Input::CallbackStatus callback) { SetBattery(callback, index); }}; 250 .on_change =
248 battery_devices[index]->SetCallback(battery_callback); 251 [this, index](const Common::Input::CallbackStatus& callback) {
252 SetBattery(callback, index);
253 },
254 });
249 battery_devices[index]->ForceUpdate(); 255 battery_devices[index]->ForceUpdate();
250 } 256 }
251 257
@@ -253,9 +259,12 @@ void EmulatedController::ReloadInput() {
253 if (!motion_devices[index]) { 259 if (!motion_devices[index]) {
254 continue; 260 continue;
255 } 261 }
256 Common::Input::InputCallback motion_callback{ 262 motion_devices[index]->SetCallback({
257 [this, index](Common::Input::CallbackStatus callback) { SetMotion(callback, index); }}; 263 .on_change =
258 motion_devices[index]->SetCallback(motion_callback); 264 [this, index](const Common::Input::CallbackStatus& callback) {
265 SetMotion(callback, index);
266 },
267 });
259 motion_devices[index]->ForceUpdate(); 268 motion_devices[index]->ForceUpdate();
260 } 269 }
261 270
@@ -267,22 +276,24 @@ void EmulatedController::ReloadInput() {
267 if (!tas_button_devices[index]) { 276 if (!tas_button_devices[index]) {
268 continue; 277 continue;
269 } 278 }
270 Common::Input::InputCallback button_callback{ 279 tas_button_devices[index]->SetCallback({
271 [this, index, tas_uuid](Common::Input::CallbackStatus callback) { 280 .on_change =
272 SetButton(callback, index, tas_uuid); 281 [this, index, tas_uuid](const Common::Input::CallbackStatus& callback) {
273 }}; 282 SetButton(callback, index, tas_uuid);
274 tas_button_devices[index]->SetCallback(button_callback); 283 },
284 });
275 } 285 }
276 286
277 for (std::size_t index = 0; index < tas_stick_devices.size(); ++index) { 287 for (std::size_t index = 0; index < tas_stick_devices.size(); ++index) {
278 if (!tas_stick_devices[index]) { 288 if (!tas_stick_devices[index]) {
279 continue; 289 continue;
280 } 290 }
281 Common::Input::InputCallback stick_callback{ 291 tas_stick_devices[index]->SetCallback({
282 [this, index, tas_uuid](Common::Input::CallbackStatus callback) { 292 .on_change =
283 SetStick(callback, index, tas_uuid); 293 [this, index, tas_uuid](const Common::Input::CallbackStatus& callback) {
284 }}; 294 SetStick(callback, index, tas_uuid);
285 tas_stick_devices[index]->SetCallback(stick_callback); 295 },
296 });
286 } 297 }
287} 298}
288 299
@@ -440,7 +451,7 @@ void EmulatedController::SetButtonParam(std::size_t index, Common::ParamPackage
440 if (index >= button_params.size()) { 451 if (index >= button_params.size()) {
441 return; 452 return;
442 } 453 }
443 button_params[index] = param; 454 button_params[index] = std::move(param);
444 ReloadInput(); 455 ReloadInput();
445} 456}
446 457
@@ -448,7 +459,7 @@ void EmulatedController::SetStickParam(std::size_t index, Common::ParamPackage p
448 if (index >= stick_params.size()) { 459 if (index >= stick_params.size()) {
449 return; 460 return;
450 } 461 }
451 stick_params[index] = param; 462 stick_params[index] = std::move(param);
452 ReloadInput(); 463 ReloadInput();
453} 464}
454 465
@@ -456,11 +467,11 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage
456 if (index >= motion_params.size()) { 467 if (index >= motion_params.size()) {
457 return; 468 return;
458 } 469 }
459 motion_params[index] = param; 470 motion_params[index] = std::move(param);
460 ReloadInput(); 471 ReloadInput();
461} 472}
462 473
463void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::size_t index, 474void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
464 Common::UUID uuid) { 475 Common::UUID uuid) {
465 if (index >= controller.button_values.size()) { 476 if (index >= controller.button_values.size()) {
466 return; 477 return;
@@ -600,7 +611,7 @@ void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::
600 TriggerOnChange(ControllerTriggerType::Button, true); 611 TriggerOnChange(ControllerTriggerType::Button, true);
601} 612}
602 613
603void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::size_t index, 614void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
604 Common::UUID uuid) { 615 Common::UUID uuid) {
605 if (index >= controller.stick_values.size()) { 616 if (index >= controller.stick_values.size()) {
606 return; 617 return;
@@ -650,8 +661,8 @@ void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::s
650 TriggerOnChange(ControllerTriggerType::Stick, true); 661 TriggerOnChange(ControllerTriggerType::Stick, true);
651} 662}
652 663
653void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, 664void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callback,
654 Common::UUID uuid) { 665 std::size_t index, Common::UUID uuid) {
655 if (index >= controller.trigger_values.size()) { 666 if (index >= controller.trigger_values.size()) {
656 return; 667 return;
657 } 668 }
@@ -659,7 +670,7 @@ void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std:
659 const auto trigger_value = TransformToTrigger(callback); 670 const auto trigger_value = TransformToTrigger(callback);
660 671
661 // Only read trigger values that have the same uuid or are pressed once 672 // Only read trigger values that have the same uuid or are pressed once
662 if (controller.stick_values[index].uuid != uuid) { 673 if (controller.trigger_values[index].uuid != uuid) {
663 if (!trigger_value.pressed.value) { 674 if (!trigger_value.pressed.value) {
664 return; 675 return;
665 } 676 }
@@ -675,7 +686,7 @@ void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std:
675 return; 686 return;
676 } 687 }
677 688
678 const auto trigger = controller.trigger_values[index]; 689 const auto& trigger = controller.trigger_values[index];
679 690
680 switch (index) { 691 switch (index) {
681 case Settings::NativeTrigger::LTrigger: 692 case Settings::NativeTrigger::LTrigger:
@@ -692,7 +703,8 @@ void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std:
692 TriggerOnChange(ControllerTriggerType::Trigger, true); 703 TriggerOnChange(ControllerTriggerType::Trigger, true);
693} 704}
694 705
695void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::size_t index) { 706void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback,
707 std::size_t index) {
696 if (index >= controller.motion_values.size()) { 708 if (index >= controller.motion_values.size()) {
697 return; 709 return;
698 } 710 }
@@ -730,7 +742,8 @@ void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::
730 TriggerOnChange(ControllerTriggerType::Motion, true); 742 TriggerOnChange(ControllerTriggerType::Motion, true);
731} 743}
732 744
733void EmulatedController::SetBattery(Common::Input::CallbackStatus callback, std::size_t index) { 745void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback,
746 std::size_t index) {
734 if (index >= controller.battery_values.size()) { 747 if (index >= controller.battery_values.size()) {
735 return; 748 return;
736 } 749 }
@@ -1110,7 +1123,7 @@ void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npa
1110 1123
1111int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) { 1124int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) {
1112 std::lock_guard lock{mutex}; 1125 std::lock_guard lock{mutex};
1113 callback_list.insert_or_assign(last_callback_key, update_callback); 1126 callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
1114 return last_callback_key++; 1127 return last_callback_key++;
1115} 1128}
1116 1129
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 425b3e7c4..e42aafebc 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -328,35 +328,38 @@ private:
328 * @param callback A CallbackStatus containing the button status 328 * @param callback A CallbackStatus containing the button status
329 * @param index Button ID of the to be updated 329 * @param index Button ID of the to be updated
330 */ 330 */
331 void SetButton(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); 331 void SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
332 Common::UUID uuid);
332 333
333 /** 334 /**
334 * Updates the analog stick status of the controller 335 * Updates the analog stick status of the controller
335 * @param callback A CallbackStatus containing the analog stick status 336 * @param callback A CallbackStatus containing the analog stick status
336 * @param index stick ID of the to be updated 337 * @param index stick ID of the to be updated
337 */ 338 */
338 void SetStick(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); 339 void SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
340 Common::UUID uuid);
339 341
340 /** 342 /**
341 * Updates the trigger status of the controller 343 * Updates the trigger status of the controller
342 * @param callback A CallbackStatus containing the trigger status 344 * @param callback A CallbackStatus containing the trigger status
343 * @param index trigger ID of the to be updated 345 * @param index trigger ID of the to be updated
344 */ 346 */
345 void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); 347 void SetTrigger(const Common::Input::CallbackStatus& callback, std::size_t index,
348 Common::UUID uuid);
346 349
347 /** 350 /**
348 * Updates the motion status of the controller 351 * Updates the motion status of the controller
349 * @param callback A CallbackStatus containing gyro and accelerometer data 352 * @param callback A CallbackStatus containing gyro and accelerometer data
350 * @param index motion ID of the to be updated 353 * @param index motion ID of the to be updated
351 */ 354 */
352 void SetMotion(Common::Input::CallbackStatus callback, std::size_t index); 355 void SetMotion(const Common::Input::CallbackStatus& callback, std::size_t index);
353 356
354 /** 357 /**
355 * Updates the battery status of the controller 358 * Updates the battery status of the controller
356 * @param callback A CallbackStatus containing the battery status 359 * @param callback A CallbackStatus containing the battery status
357 * @param index Button ID of the to be updated 360 * @param index Button ID of the to be updated
358 */ 361 */
359 void SetBattery(Common::Input::CallbackStatus callback, std::size_t index); 362 void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index);
360 363
361 /** 364 /**
362 * Triggers a callback that something has changed on the controller status 365 * Triggers a callback that something has changed on the controller status
diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp
index 874780ec2..708480f2d 100644
--- a/src/core/hid/emulated_devices.cpp
+++ b/src/core/hid/emulated_devices.cpp
@@ -70,50 +70,55 @@ void EmulatedDevices::ReloadInput() {
70 if (!mouse_button_devices[index]) { 70 if (!mouse_button_devices[index]) {
71 continue; 71 continue;
72 } 72 }
73 Common::Input::InputCallback button_callback{ 73 mouse_button_devices[index]->SetCallback({
74 [this, index](Common::Input::CallbackStatus callback) { 74 .on_change =
75 SetMouseButton(callback, index); 75 [this, index](const Common::Input::CallbackStatus& callback) {
76 }}; 76 SetMouseButton(callback, index);
77 mouse_button_devices[index]->SetCallback(button_callback); 77 },
78 });
78 } 79 }
79 80
80 for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) { 81 for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) {
81 if (!mouse_analog_devices[index]) { 82 if (!mouse_analog_devices[index]) {
82 continue; 83 continue;
83 } 84 }
84 Common::Input::InputCallback button_callback{ 85 mouse_analog_devices[index]->SetCallback({
85 [this, index](Common::Input::CallbackStatus callback) { 86 .on_change =
86 SetMouseAnalog(callback, index); 87 [this, index](const Common::Input::CallbackStatus& callback) {
87 }}; 88 SetMouseAnalog(callback, index);
88 mouse_analog_devices[index]->SetCallback(button_callback); 89 },
90 });
89 } 91 }
90 92
91 if (mouse_stick_device) { 93 if (mouse_stick_device) {
92 Common::Input::InputCallback button_callback{ 94 mouse_stick_device->SetCallback({
93 [this](Common::Input::CallbackStatus callback) { SetMouseStick(callback); }}; 95 .on_change =
94 mouse_stick_device->SetCallback(button_callback); 96 [this](const Common::Input::CallbackStatus& callback) { SetMouseStick(callback); },
97 });
95 } 98 }
96 99
97 for (std::size_t index = 0; index < keyboard_devices.size(); ++index) { 100 for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {
98 if (!keyboard_devices[index]) { 101 if (!keyboard_devices[index]) {
99 continue; 102 continue;
100 } 103 }
101 Common::Input::InputCallback button_callback{ 104 keyboard_devices[index]->SetCallback({
102 [this, index](Common::Input::CallbackStatus callback) { 105 .on_change =
103 SetKeyboardButton(callback, index); 106 [this, index](const Common::Input::CallbackStatus& callback) {
104 }}; 107 SetKeyboardButton(callback, index);
105 keyboard_devices[index]->SetCallback(button_callback); 108 },
109 });
106 } 110 }
107 111
108 for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) { 112 for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) {
109 if (!keyboard_modifier_devices[index]) { 113 if (!keyboard_modifier_devices[index]) {
110 continue; 114 continue;
111 } 115 }
112 Common::Input::InputCallback button_callback{ 116 keyboard_modifier_devices[index]->SetCallback({
113 [this, index](Common::Input::CallbackStatus callback) { 117 .on_change =
114 SetKeyboardModifier(callback, index); 118 [this, index](const Common::Input::CallbackStatus& callback) {
115 }}; 119 SetKeyboardModifier(callback, index);
116 keyboard_modifier_devices[index]->SetCallback(button_callback); 120 },
121 });
117 } 122 }
118} 123}
119 124
@@ -159,7 +164,8 @@ void EmulatedDevices::RestoreConfig() {
159 ReloadFromSettings(); 164 ReloadFromSettings();
160} 165}
161 166
162void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) { 167void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback,
168 std::size_t index) {
163 if (index >= device_status.keyboard_values.size()) { 169 if (index >= device_status.keyboard_values.size()) {
164 return; 170 return;
165 } 171 }
@@ -216,7 +222,7 @@ void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) {
216 } 222 }
217} 223}
218 224
219void EmulatedDevices::SetKeyboardModifier(Common::Input::CallbackStatus callback, 225void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& callback,
220 std::size_t index) { 226 std::size_t index) {
221 if (index >= device_status.keyboard_moddifier_values.size()) { 227 if (index >= device_status.keyboard_moddifier_values.size()) {
222 return; 228 return;
@@ -286,7 +292,8 @@ void EmulatedDevices::SetKeyboardModifier(Common::Input::CallbackStatus callback
286 TriggerOnChange(DeviceTriggerType::KeyboardModdifier); 292 TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
287} 293}
288 294
289void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index) { 295void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callback,
296 std::size_t index) {
290 if (index >= device_status.mouse_button_values.size()) { 297 if (index >= device_status.mouse_button_values.size()) {
291 return; 298 return;
292 } 299 }
@@ -347,7 +354,8 @@ void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std
347 TriggerOnChange(DeviceTriggerType::Mouse); 354 TriggerOnChange(DeviceTriggerType::Mouse);
348} 355}
349 356
350void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index) { 357void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callback,
358 std::size_t index) {
351 if (index >= device_status.mouse_analog_values.size()) { 359 if (index >= device_status.mouse_analog_values.size()) {
352 return; 360 return;
353 } 361 }
@@ -374,7 +382,7 @@ void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std
374 TriggerOnChange(DeviceTriggerType::Mouse); 382 TriggerOnChange(DeviceTriggerType::Mouse);
375} 383}
376 384
377void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) { 385void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) {
378 std::lock_guard lock{mutex}; 386 std::lock_guard lock{mutex};
379 const auto touch_value = TransformToTouch(callback); 387 const auto touch_value = TransformToTouch(callback);
380 388
@@ -435,7 +443,7 @@ void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
435 443
436int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) { 444int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {
437 std::lock_guard lock{mutex}; 445 std::lock_guard lock{mutex};
438 callback_list.insert_or_assign(last_callback_key, update_callback); 446 callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
439 return last_callback_key++; 447 return last_callback_key++;
440} 448}
441 449
diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h
index c72327681..790d3b411 100644
--- a/src/core/hid/emulated_devices.h
+++ b/src/core/hid/emulated_devices.h
@@ -156,35 +156,34 @@ private:
156 * @param callback A CallbackStatus containing the key status 156 * @param callback A CallbackStatus containing the key status
157 * @param index key ID to be updated 157 * @param index key ID to be updated
158 */ 158 */
159 void SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index); 159 void SetKeyboardButton(const Common::Input::CallbackStatus& callback, std::size_t index);
160 160
161 /** 161 /**
162 * Updates the keyboard status of the keyboard device 162 * Updates the keyboard status of the keyboard device
163 * @param callback A CallbackStatus containing the modifier key status 163 * @param callback A CallbackStatus containing the modifier key status
164 * @param index modifier key ID to be updated 164 * @param index modifier key ID to be updated
165 */ 165 */
166 void SetKeyboardModifier(Common::Input::CallbackStatus callback, std::size_t index); 166 void SetKeyboardModifier(const Common::Input::CallbackStatus& callback, std::size_t index);
167 167
168 /** 168 /**
169 * Updates the mouse button status of the mouse device 169 * Updates the mouse button status of the mouse device
170 * @param callback A CallbackStatus containing the button status 170 * @param callback A CallbackStatus containing the button status
171 * @param index Button ID to be updated 171 * @param index Button ID to be updated
172 */ 172 */
173 void SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index); 173 void SetMouseButton(const Common::Input::CallbackStatus& callback, std::size_t index);
174 174
175 /** 175 /**
176 * Updates the mouse wheel status of the mouse device 176 * Updates the mouse wheel status of the mouse device
177 * @param callback A CallbackStatus containing the wheel status 177 * @param callback A CallbackStatus containing the wheel status
178 * @param index wheel ID to be updated 178 * @param index wheel ID to be updated
179 */ 179 */
180 void SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index); 180 void SetMouseAnalog(const Common::Input::CallbackStatus& callback, std::size_t index);
181 181
182 /** 182 /**
183 * Updates the mouse position status of the mouse device 183 * Updates the mouse position status of the mouse device
184 * @param callback A CallbackStatus containing the position status 184 * @param callback A CallbackStatus containing the position status
185 * @param index stick ID to be updated
186 */ 185 */
187 void SetMouseStick(Common::Input::CallbackStatus callback); 186 void SetMouseStick(const Common::Input::CallbackStatus& callback);
188 187
189 /** 188 /**
190 * Triggers a callback that something has changed on the device status 189 * Triggers a callback that something has changed on the device status
diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp
index 0c3eb5a62..a1c3bbb57 100644
--- a/src/core/hid/hid_core.cpp
+++ b/src/core/hid/hid_core.cpp
@@ -145,6 +145,16 @@ NpadIdType HIDCore::GetFirstNpadId() const {
145 return NpadIdType::Player1; 145 return NpadIdType::Player1;
146} 146}
147 147
148NpadIdType HIDCore::GetFirstDisconnectedNpadId() const {
149 for (std::size_t player_index = 0; player_index < available_controllers; ++player_index) {
150 const auto* const controller = GetEmulatedControllerByIndex(player_index);
151 if (!controller->IsConnected()) {
152 return controller->GetNpadIdType();
153 }
154 }
155 return NpadIdType::Player1;
156}
157
148void HIDCore::EnableAllControllerConfiguration() { 158void HIDCore::EnableAllControllerConfiguration() {
149 player_1->EnableConfiguration(); 159 player_1->EnableConfiguration();
150 player_2->EnableConfiguration(); 160 player_2->EnableConfiguration();
diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h
index 2fb0f7e19..837f7de49 100644
--- a/src/core/hid/hid_core.h
+++ b/src/core/hid/hid_core.h
@@ -45,6 +45,9 @@ public:
45 /// Returns the first connected npad id 45 /// Returns the first connected npad id
46 NpadIdType GetFirstNpadId() const; 46 NpadIdType GetFirstNpadId() const;
47 47
48 /// Returns the first disconnected npad id
49 NpadIdType GetFirstDisconnectedNpadId() const;
50
48 /// Sets all emulated controllers into configuring mode. 51 /// Sets all emulated controllers into configuring mode.
49 void EnableAllControllerConfiguration(); 52 void EnableAllControllerConfiguration();
50 53
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp
index 8ff0f695d..36fc0944a 100644
--- a/src/core/hle/kernel/init/init_slab_setup.cpp
+++ b/src/core/hle/kernel/init/init_slab_setup.cpp
@@ -9,6 +9,7 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hardware_properties.h" 10#include "core/hardware_properties.h"
11#include "core/hle/kernel/init/init_slab_setup.h" 11#include "core/hle/kernel/init/init_slab_setup.h"
12#include "core/hle/kernel/k_code_memory.h"
12#include "core/hle/kernel/k_event.h" 13#include "core/hle/kernel/k_event.h"
13#include "core/hle/kernel/k_memory_layout.h" 14#include "core/hle/kernel/k_memory_layout.h"
14#include "core/hle/kernel/k_memory_manager.h" 15#include "core/hle/kernel/k_memory_manager.h"
@@ -32,6 +33,7 @@ namespace Kernel::Init {
32 HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \ 33 HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \
33 HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \ 34 HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \
34 HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ 35 HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
36 HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__) \
35 HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \ 37 HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \
36 HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) 38 HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__)
37 39
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp
index 1b429bc1e..783c69858 100644
--- a/src/core/hle/kernel/k_address_arbiter.cpp
+++ b/src/core/hle/kernel/k_address_arbiter.cpp
@@ -8,6 +8,7 @@
8#include "core/hle/kernel/k_scheduler.h" 8#include "core/hle/kernel/k_scheduler.h"
9#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" 9#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
10#include "core/hle/kernel/k_thread.h" 10#include "core/hle/kernel/k_thread.h"
11#include "core/hle/kernel/k_thread_queue.h"
11#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/svc_results.h" 13#include "core/hle/kernel/svc_results.h"
13#include "core/hle/kernel/time_manager.h" 14#include "core/hle/kernel/time_manager.h"
@@ -28,7 +29,7 @@ bool ReadFromUser(Core::System& system, s32* out, VAddr address) {
28 29
29bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 value) { 30bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 value) {
30 auto& monitor = system.Monitor(); 31 auto& monitor = system.Monitor();
31 const auto current_core = system.CurrentCoreIndex(); 32 const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
32 33
33 // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. 34 // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.
34 // TODO(bunnei): We should call CanAccessAtomic(..) here. 35 // TODO(bunnei): We should call CanAccessAtomic(..) here.
@@ -58,7 +59,7 @@ bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 valu
58 59
59bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 new_value) { 60bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 new_value) {
60 auto& monitor = system.Monitor(); 61 auto& monitor = system.Monitor();
61 const auto current_core = system.CurrentCoreIndex(); 62 const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
62 63
63 // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. 64 // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.
64 // TODO(bunnei): We should call CanAccessAtomic(..) here. 65 // TODO(bunnei): We should call CanAccessAtomic(..) here.
@@ -85,6 +86,27 @@ bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32
85 return true; 86 return true;
86} 87}
87 88
89class ThreadQueueImplForKAddressArbiter final : public KThreadQueue {
90public:
91 explicit ThreadQueueImplForKAddressArbiter(KernelCore& kernel_, KAddressArbiter::ThreadTree* t)
92 : KThreadQueue(kernel_), m_tree(t) {}
93
94 void CancelWait(KThread* waiting_thread, ResultCode wait_result,
95 bool cancel_timer_task) override {
96 // If the thread is waiting on an address arbiter, remove it from the tree.
97 if (waiting_thread->IsWaitingForAddressArbiter()) {
98 m_tree->erase(m_tree->iterator_to(*waiting_thread));
99 waiting_thread->ClearAddressArbiter();
100 }
101
102 // Invoke the base cancel wait handler.
103 KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
104 }
105
106private:
107 KAddressArbiter::ThreadTree* m_tree;
108};
109
88} // namespace 110} // namespace
89 111
90ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) { 112ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) {
@@ -96,14 +118,14 @@ ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) {
96 auto it = thread_tree.nfind_light({addr, -1}); 118 auto it = thread_tree.nfind_light({addr, -1});
97 while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && 119 while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
98 (it->GetAddressArbiterKey() == addr)) { 120 (it->GetAddressArbiterKey() == addr)) {
121 // End the thread's wait.
99 KThread* target_thread = std::addressof(*it); 122 KThread* target_thread = std::addressof(*it);
100 target_thread->SetSyncedObject(nullptr, ResultSuccess); 123 target_thread->EndWait(ResultSuccess);
101 124
102 ASSERT(target_thread->IsWaitingForAddressArbiter()); 125 ASSERT(target_thread->IsWaitingForAddressArbiter());
103 target_thread->Wakeup(); 126 target_thread->ClearAddressArbiter();
104 127
105 it = thread_tree.erase(it); 128 it = thread_tree.erase(it);
106 target_thread->ClearAddressArbiter();
107 ++num_waiters; 129 ++num_waiters;
108 } 130 }
109 } 131 }
@@ -129,14 +151,14 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32
129 auto it = thread_tree.nfind_light({addr, -1}); 151 auto it = thread_tree.nfind_light({addr, -1});
130 while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && 152 while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
131 (it->GetAddressArbiterKey() == addr)) { 153 (it->GetAddressArbiterKey() == addr)) {
154 // End the thread's wait.
132 KThread* target_thread = std::addressof(*it); 155 KThread* target_thread = std::addressof(*it);
133 target_thread->SetSyncedObject(nullptr, ResultSuccess); 156 target_thread->EndWait(ResultSuccess);
134 157
135 ASSERT(target_thread->IsWaitingForAddressArbiter()); 158 ASSERT(target_thread->IsWaitingForAddressArbiter());
136 target_thread->Wakeup(); 159 target_thread->ClearAddressArbiter();
137 160
138 it = thread_tree.erase(it); 161 it = thread_tree.erase(it);
139 target_thread->ClearAddressArbiter();
140 ++num_waiters; 162 ++num_waiters;
141 } 163 }
142 } 164 }
@@ -197,14 +219,14 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32
197 219
198 while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && 220 while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
199 (it->GetAddressArbiterKey() == addr)) { 221 (it->GetAddressArbiterKey() == addr)) {
222 // End the thread's wait.
200 KThread* target_thread = std::addressof(*it); 223 KThread* target_thread = std::addressof(*it);
201 target_thread->SetSyncedObject(nullptr, ResultSuccess); 224 target_thread->EndWait(ResultSuccess);
202 225
203 ASSERT(target_thread->IsWaitingForAddressArbiter()); 226 ASSERT(target_thread->IsWaitingForAddressArbiter());
204 target_thread->Wakeup(); 227 target_thread->ClearAddressArbiter();
205 228
206 it = thread_tree.erase(it); 229 it = thread_tree.erase(it);
207 target_thread->ClearAddressArbiter();
208 ++num_waiters; 230 ++num_waiters;
209 } 231 }
210 } 232 }
@@ -214,6 +236,7 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32
214ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) { 236ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) {
215 // Prepare to wait. 237 // Prepare to wait.
216 KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); 238 KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
239 ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree));
217 240
218 { 241 {
219 KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; 242 KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout};
@@ -224,9 +247,6 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
224 return ResultTerminationRequested; 247 return ResultTerminationRequested;
225 } 248 }
226 249
227 // Set the synced object.
228 cur_thread->SetSyncedObject(nullptr, ResultTimedOut);
229
230 // Read the value from userspace. 250 // Read the value from userspace.
231 s32 user_value{}; 251 s32 user_value{};
232 bool succeeded{}; 252 bool succeeded{};
@@ -256,31 +276,20 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
256 // Set the arbiter. 276 // Set the arbiter.
257 cur_thread->SetAddressArbiter(&thread_tree, addr); 277 cur_thread->SetAddressArbiter(&thread_tree, addr);
258 thread_tree.insert(*cur_thread); 278 thread_tree.insert(*cur_thread);
259 cur_thread->SetState(ThreadState::Waiting);
260 cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
261 }
262
263 // Cancel the timer wait.
264 kernel.TimeManager().UnscheduleTimeEvent(cur_thread);
265 279
266 // Remove from the address arbiter. 280 // Wait for the thread to finish.
267 { 281 cur_thread->BeginWait(std::addressof(wait_queue));
268 KScopedSchedulerLock sl(kernel); 282 cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
269
270 if (cur_thread->IsWaitingForAddressArbiter()) {
271 thread_tree.erase(thread_tree.iterator_to(*cur_thread));
272 cur_thread->ClearAddressArbiter();
273 }
274 } 283 }
275 284
276 // Get the result. 285 // Get the result.
277 KSynchronizationObject* dummy{}; 286 return cur_thread->GetWaitResult();
278 return cur_thread->GetWaitResult(&dummy);
279} 287}
280 288
281ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { 289ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
282 // Prepare to wait. 290 // Prepare to wait.
283 KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); 291 KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
292 ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree));
284 293
285 { 294 {
286 KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; 295 KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout};
@@ -291,9 +300,6 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
291 return ResultTerminationRequested; 300 return ResultTerminationRequested;
292 } 301 }
293 302
294 // Set the synced object.
295 cur_thread->SetSyncedObject(nullptr, ResultTimedOut);
296
297 // Read the value from userspace. 303 // Read the value from userspace.
298 s32 user_value{}; 304 s32 user_value{};
299 if (!ReadFromUser(system, &user_value, addr)) { 305 if (!ReadFromUser(system, &user_value, addr)) {
@@ -316,26 +322,14 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
316 // Set the arbiter. 322 // Set the arbiter.
317 cur_thread->SetAddressArbiter(&thread_tree, addr); 323 cur_thread->SetAddressArbiter(&thread_tree, addr);
318 thread_tree.insert(*cur_thread); 324 thread_tree.insert(*cur_thread);
319 cur_thread->SetState(ThreadState::Waiting);
320 cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
321 }
322
323 // Cancel the timer wait.
324 kernel.TimeManager().UnscheduleTimeEvent(cur_thread);
325 325
326 // Remove from the address arbiter. 326 // Wait for the thread to finish.
327 { 327 cur_thread->BeginWait(std::addressof(wait_queue));
328 KScopedSchedulerLock sl(kernel); 328 cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
329
330 if (cur_thread->IsWaitingForAddressArbiter()) {
331 thread_tree.erase(thread_tree.iterator_to(*cur_thread));
332 cur_thread->ClearAddressArbiter();
333 }
334 } 329 }
335 330
336 // Get the result. 331 // Get the result.
337 KSynchronizationObject* dummy{}; 332 return cur_thread->GetWaitResult();
338 return cur_thread->GetWaitResult(&dummy);
339} 333}
340 334
341} // namespace Kernel 335} // namespace Kernel
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h
index e4fcdbc67..165b76747 100644
--- a/src/core/hle/kernel/k_auto_object.h
+++ b/src/core/hle/kernel/k_auto_object.h
@@ -170,6 +170,10 @@ public:
170 } 170 }
171 } 171 }
172 172
173 const std::string& GetName() const {
174 return name;
175 }
176
173private: 177private:
174 void RegisterWithKernel(); 178 void RegisterWithKernel();
175 void UnregisterWithKernel(); 179 void UnregisterWithKernel();
diff --git a/src/core/hle/kernel/k_class_token.cpp b/src/core/hle/kernel/k_class_token.cpp
index 0be0027be..21e2fe494 100644
--- a/src/core/hle/kernel/k_class_token.cpp
+++ b/src/core/hle/kernel/k_class_token.cpp
@@ -6,6 +6,7 @@
6#include "core/hle/kernel/k_class_token.h" 6#include "core/hle/kernel/k_class_token.h"
7#include "core/hle/kernel/k_client_port.h" 7#include "core/hle/kernel/k_client_port.h"
8#include "core/hle/kernel/k_client_session.h" 8#include "core/hle/kernel/k_client_session.h"
9#include "core/hle/kernel/k_code_memory.h"
9#include "core/hle/kernel/k_event.h" 10#include "core/hle/kernel/k_event.h"
10#include "core/hle/kernel/k_port.h" 11#include "core/hle/kernel/k_port.h"
11#include "core/hle/kernel/k_process.h" 12#include "core/hle/kernel/k_process.h"
@@ -48,7 +49,7 @@ static_assert(ClassToken<KWritableEvent> == 0b10001001'00000000);
48static_assert(ClassToken<KTransferMemory> == 0b10010001'00000000); 49static_assert(ClassToken<KTransferMemory> == 0b10010001'00000000);
49// static_assert(ClassToken<KDeviceAddressSpace> == 0b01100001'00000000); 50// static_assert(ClassToken<KDeviceAddressSpace> == 0b01100001'00000000);
50// static_assert(ClassToken<KSessionRequest> == 0b10100001'00000000); 51// static_assert(ClassToken<KSessionRequest> == 0b10100001'00000000);
51// static_assert(ClassToken<KCodeMemory> == 0b11000001'00000000); 52static_assert(ClassToken<KCodeMemory> == 0b11000001'00000000);
52 53
53// Ensure that the token hierarchy is correct. 54// Ensure that the token hierarchy is correct.
54 55
@@ -79,7 +80,7 @@ static_assert(ClassToken<KWritableEvent> == ((0b10001001 << 8) | ClassToken<KAut
79static_assert(ClassToken<KTransferMemory> == ((0b10010001 << 8) | ClassToken<KAutoObject>)); 80static_assert(ClassToken<KTransferMemory> == ((0b10010001 << 8) | ClassToken<KAutoObject>));
80// static_assert(ClassToken<KDeviceAddressSpace> == ((0b01100001 << 8) | ClassToken<KAutoObject>)); 81// static_assert(ClassToken<KDeviceAddressSpace> == ((0b01100001 << 8) | ClassToken<KAutoObject>));
81// static_assert(ClassToken<KSessionRequest> == ((0b10100001 << 8) | ClassToken<KAutoObject>)); 82// static_assert(ClassToken<KSessionRequest> == ((0b10100001 << 8) | ClassToken<KAutoObject>));
82// static_assert(ClassToken<KCodeMemory> == ((0b11000001 << 8) | ClassToken<KAutoObject>)); 83static_assert(ClassToken<KCodeMemory> == ((0b11000001 << 8) | ClassToken<KAutoObject>));
83 84
84// Ensure that the token hierarchy reflects the class hierarchy. 85// Ensure that the token hierarchy reflects the class hierarchy.
85 86
diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp
new file mode 100644
index 000000000..d69f7ffb7
--- /dev/null
+++ b/src/core/hle/kernel/k_code_memory.cpp
@@ -0,0 +1,146 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6#include "core/device_memory.h"
7#include "core/hle/kernel/k_auto_object.h"
8#include "core/hle/kernel/k_code_memory.h"
9#include "core/hle/kernel/k_light_lock.h"
10#include "core/hle/kernel/k_memory_block.h"
11#include "core/hle/kernel/k_page_linked_list.h"
12#include "core/hle/kernel/k_page_table.h"
13#include "core/hle/kernel/k_process.h"
14#include "core/hle/kernel/slab_helpers.h"
15#include "core/hle/kernel/svc_types.h"
16#include "core/hle/result.h"
17
18namespace Kernel {
19
20KCodeMemory::KCodeMemory(KernelCore& kernel_)
21 : KAutoObjectWithSlabHeapAndContainer{kernel_}, m_lock(kernel_) {}
22
23ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, size_t size) {
24 // Set members.
25 m_owner = kernel.CurrentProcess();
26
27 // Get the owner page table.
28 auto& page_table = m_owner->PageTable();
29
30 // Construct the page group.
31 KMemoryInfo kBlockInfo = page_table.QueryInfo(addr);
32 m_page_group = KPageLinkedList(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages());
33
34 // Lock the memory.
35 R_TRY(page_table.LockForCodeMemory(addr, size))
36
37 // Clear the memory.
38 for (const auto& block : m_page_group.Nodes()) {
39 std::memset(device_memory.GetPointer(block.GetAddress()), 0xFF, block.GetSize());
40 }
41
42 // Set remaining tracking members.
43 m_address = addr;
44 m_is_initialized = true;
45 m_is_owner_mapped = false;
46 m_is_mapped = false;
47
48 // We succeeded.
49 return ResultSuccess;
50}
51
52void KCodeMemory::Finalize() {
53 // Unlock.
54 if (!m_is_mapped && !m_is_owner_mapped) {
55 const size_t size = m_page_group.GetNumPages() * PageSize;
56 m_owner->PageTable().UnlockForCodeMemory(m_address, size);
57 }
58}
59
60ResultCode KCodeMemory::Map(VAddr address, size_t size) {
61 // Validate the size.
62 R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
63
64 // Lock ourselves.
65 KScopedLightLock lk(m_lock);
66
67 // Ensure we're not already mapped.
68 R_UNLESS(!m_is_mapped, ResultInvalidState);
69
70 // Map the memory.
71 R_TRY(kernel.CurrentProcess()->PageTable().MapPages(
72 address, m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite));
73
74 // Mark ourselves as mapped.
75 m_is_mapped = true;
76
77 return ResultSuccess;
78}
79
80ResultCode KCodeMemory::Unmap(VAddr address, size_t size) {
81 // Validate the size.
82 R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
83
84 // Lock ourselves.
85 KScopedLightLock lk(m_lock);
86
87 // Unmap the memory.
88 R_TRY(kernel.CurrentProcess()->PageTable().UnmapPages(address, m_page_group,
89 KMemoryState::CodeOut));
90
91 // Mark ourselves as unmapped.
92 m_is_mapped = false;
93
94 return ResultSuccess;
95}
96
97ResultCode KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) {
98 // Validate the size.
99 R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
100
101 // Lock ourselves.
102 KScopedLightLock lk(m_lock);
103
104 // Ensure we're not already mapped.
105 R_UNLESS(!m_is_owner_mapped, ResultInvalidState);
106
107 // Convert the memory permission.
108 KMemoryPermission k_perm{};
109 switch (perm) {
110 case Svc::MemoryPermission::Read:
111 k_perm = KMemoryPermission::UserRead;
112 break;
113 case Svc::MemoryPermission::ReadExecute:
114 k_perm = KMemoryPermission::UserReadExecute;
115 break;
116 default:
117 break;
118 }
119
120 // Map the memory.
121 R_TRY(
122 m_owner->PageTable().MapPages(address, m_page_group, KMemoryState::GeneratedCode, k_perm));
123
124 // Mark ourselves as mapped.
125 m_is_owner_mapped = true;
126
127 return ResultSuccess;
128}
129
130ResultCode KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
131 // Validate the size.
132 R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
133
134 // Lock ourselves.
135 KScopedLightLock lk(m_lock);
136
137 // Unmap the memory.
138 R_TRY(m_owner->PageTable().UnmapPages(address, m_page_group, KMemoryState::GeneratedCode));
139
140 // Mark ourselves as unmapped.
141 m_is_owner_mapped = false;
142
143 return ResultSuccess;
144}
145
146} // namespace Kernel \ No newline at end of file
diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h
new file mode 100644
index 000000000..e0ba19a53
--- /dev/null
+++ b/src/core/hle/kernel/k_code_memory.h
@@ -0,0 +1,66 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "core/device_memory.h"
9#include "core/hle/kernel/k_auto_object.h"
10#include "core/hle/kernel/k_light_lock.h"
11#include "core/hle/kernel/k_page_linked_list.h"
12#include "core/hle/kernel/k_process.h"
13#include "core/hle/kernel/slab_helpers.h"
14#include "core/hle/kernel/svc_types.h"
15#include "core/hle/result.h"
16
17namespace Kernel {
18
19enum class CodeMemoryOperation : u32 {
20 Map = 0,
21 MapToOwner = 1,
22 Unmap = 2,
23 UnmapFromOwner = 3,
24};
25
26class KCodeMemory final
27 : public KAutoObjectWithSlabHeapAndContainer<KCodeMemory, KAutoObjectWithList> {
28 KERNEL_AUTOOBJECT_TRAITS(KCodeMemory, KAutoObject);
29
30public:
31 explicit KCodeMemory(KernelCore& kernel_);
32
33 ResultCode Initialize(Core::DeviceMemory& device_memory, VAddr address, size_t size);
34 void Finalize();
35
36 ResultCode Map(VAddr address, size_t size);
37 ResultCode Unmap(VAddr address, size_t size);
38 ResultCode MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm);
39 ResultCode UnmapFromOwner(VAddr address, size_t size);
40
41 bool IsInitialized() const {
42 return m_is_initialized;
43 }
44 static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
45
46 KProcess* GetOwner() const {
47 return m_owner;
48 }
49 VAddr GetSourceAddress() const {
50 return m_address;
51 }
52 size_t GetSize() const {
53 return m_is_initialized ? m_page_group.GetNumPages() * PageSize : 0;
54 }
55
56private:
57 KPageLinkedList m_page_group{};
58 KProcess* m_owner{};
59 VAddr m_address{};
60 KLightLock m_lock;
61 bool m_is_initialized{};
62 bool m_is_owner_mapped{};
63 bool m_is_mapped{};
64};
65
66} // namespace Kernel
diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp
index 7fa9b8cc3..aadcc297a 100644
--- a/src/core/hle/kernel/k_condition_variable.cpp
+++ b/src/core/hle/kernel/k_condition_variable.cpp
@@ -11,6 +11,7 @@
11#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" 11#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
12#include "core/hle/kernel/k_synchronization_object.h" 12#include "core/hle/kernel/k_synchronization_object.h"
13#include "core/hle/kernel/k_thread.h" 13#include "core/hle/kernel/k_thread.h"
14#include "core/hle/kernel/k_thread_queue.h"
14#include "core/hle/kernel/kernel.h" 15#include "core/hle/kernel/kernel.h"
15#include "core/hle/kernel/svc_common.h" 16#include "core/hle/kernel/svc_common.h"
16#include "core/hle/kernel/svc_results.h" 17#include "core/hle/kernel/svc_results.h"
@@ -33,7 +34,7 @@ bool WriteToUser(Core::System& system, VAddr address, const u32* p) {
33bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero, 34bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero,
34 u32 new_orr_mask) { 35 u32 new_orr_mask) {
35 auto& monitor = system.Monitor(); 36 auto& monitor = system.Monitor();
36 const auto current_core = system.CurrentCoreIndex(); 37 const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
37 38
38 // Load the value from the address. 39 // Load the value from the address.
39 const auto expected = monitor.ExclusiveRead32(current_core, address); 40 const auto expected = monitor.ExclusiveRead32(current_core, address);
@@ -57,6 +58,48 @@ bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero
57 return true; 58 return true;
58} 59}
59 60
61class ThreadQueueImplForKConditionVariableWaitForAddress final : public KThreadQueue {
62public:
63 explicit ThreadQueueImplForKConditionVariableWaitForAddress(KernelCore& kernel_)
64 : KThreadQueue(kernel_) {}
65
66 void CancelWait(KThread* waiting_thread, ResultCode wait_result,
67 bool cancel_timer_task) override {
68 // Remove the thread as a waiter from its owner.
69 waiting_thread->GetLockOwner()->RemoveWaiter(waiting_thread);
70
71 // Invoke the base cancel wait handler.
72 KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
73 }
74};
75
76class ThreadQueueImplForKConditionVariableWaitConditionVariable final : public KThreadQueue {
77private:
78 KConditionVariable::ThreadTree* m_tree;
79
80public:
81 explicit ThreadQueueImplForKConditionVariableWaitConditionVariable(
82 KernelCore& kernel_, KConditionVariable::ThreadTree* t)
83 : KThreadQueue(kernel_), m_tree(t) {}
84
85 void CancelWait(KThread* waiting_thread, ResultCode wait_result,
86 bool cancel_timer_task) override {
87 // Remove the thread as a waiter from its owner.
88 if (KThread* owner = waiting_thread->GetLockOwner(); owner != nullptr) {
89 owner->RemoveWaiter(waiting_thread);
90 }
91
92 // If the thread is waiting on a condvar, remove it from the tree.
93 if (waiting_thread->IsWaitingForConditionVariable()) {
94 m_tree->erase(m_tree->iterator_to(*waiting_thread));
95 waiting_thread->ClearConditionVariable();
96 }
97
98 // Invoke the base cancel wait handler.
99 KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
100 }
101};
102
60} // namespace 103} // namespace
61 104
62KConditionVariable::KConditionVariable(Core::System& system_) 105KConditionVariable::KConditionVariable(Core::System& system_)
@@ -78,84 +121,77 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) {
78 121
79 // Determine the next tag. 122 // Determine the next tag.
80 u32 next_value{}; 123 u32 next_value{};
81 if (next_owner_thread) { 124 if (next_owner_thread != nullptr) {
82 next_value = next_owner_thread->GetAddressKeyValue(); 125 next_value = next_owner_thread->GetAddressKeyValue();
83 if (num_waiters > 1) { 126 if (num_waiters > 1) {
84 next_value |= Svc::HandleWaitMask; 127 next_value |= Svc::HandleWaitMask;
85 } 128 }
86 129
87 next_owner_thread->SetSyncedObject(nullptr, ResultSuccess); 130 // Write the value to userspace.
88 next_owner_thread->Wakeup(); 131 ResultCode result{ResultSuccess};
89 } 132 if (WriteToUser(system, addr, std::addressof(next_value))) [[likely]] {
90 133 result = ResultSuccess;
91 // Write the value to userspace. 134 } else {
92 if (!WriteToUser(system, addr, std::addressof(next_value))) { 135 result = ResultInvalidCurrentMemory;
93 if (next_owner_thread) {
94 next_owner_thread->SetSyncedObject(nullptr, ResultInvalidCurrentMemory);
95 } 136 }
96 137
97 return ResultInvalidCurrentMemory; 138 // Signal the next owner thread.
139 next_owner_thread->EndWait(result);
140 return result;
141 } else {
142 // Just write the value to userspace.
143 R_UNLESS(WriteToUser(system, addr, std::addressof(next_value)),
144 ResultInvalidCurrentMemory);
145
146 return ResultSuccess;
98 } 147 }
99 } 148 }
100
101 return ResultSuccess;
102} 149}
103 150
104ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) { 151ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) {
105 KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); 152 KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
153 ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(kernel);
106 154
107 // Wait for the address. 155 // Wait for the address.
156 KThread* owner_thread{};
108 { 157 {
109 KScopedAutoObject<KThread> owner_thread; 158 KScopedSchedulerLock sl(kernel);
110 ASSERT(owner_thread.IsNull());
111 {
112 KScopedSchedulerLock sl(kernel);
113 cur_thread->SetSyncedObject(nullptr, ResultSuccess);
114 159
115 // Check if the thread should terminate. 160 // Check if the thread should terminate.
116 R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested); 161 R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested);
117 162
118 { 163 // Read the tag from userspace.
119 // Read the tag from userspace. 164 u32 test_tag{};
120 u32 test_tag{}; 165 R_UNLESS(ReadFromUser(system, std::addressof(test_tag), addr), ResultInvalidCurrentMemory);
121 R_UNLESS(ReadFromUser(system, std::addressof(test_tag), addr),
122 ResultInvalidCurrentMemory);
123
124 // If the tag isn't the handle (with wait mask), we're done.
125 R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), ResultSuccess);
126
127 // Get the lock owner thread.
128 owner_thread =
129 kernel.CurrentProcess()->GetHandleTable().GetObjectWithoutPseudoHandle<KThread>(
130 handle);
131 R_UNLESS(owner_thread.IsNotNull(), ResultInvalidHandle);
132
133 // Update the lock.
134 cur_thread->SetAddressKey(addr, value);
135 owner_thread->AddWaiter(cur_thread);
136 cur_thread->SetState(ThreadState::Waiting);
137 cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar);
138 cur_thread->SetMutexWaitAddressForDebugging(addr);
139 }
140 }
141 ASSERT(owner_thread.IsNotNull());
142 }
143 166
144 // Remove the thread as a waiter from the lock owner. 167 // If the tag isn't the handle (with wait mask), we're done.
145 { 168 R_SUCCEED_IF(test_tag != (handle | Svc::HandleWaitMask));
146 KScopedSchedulerLock sl(kernel); 169
147 KThread* owner_thread = cur_thread->GetLockOwner(); 170 // Get the lock owner thread.
148 if (owner_thread != nullptr) { 171 owner_thread = kernel.CurrentProcess()
149 owner_thread->RemoveWaiter(cur_thread); 172 ->GetHandleTable()
150 } 173 .GetObjectWithoutPseudoHandle<KThread>(handle)
174 .ReleasePointerUnsafe();
175 R_UNLESS(owner_thread != nullptr, ResultInvalidHandle);
176
177 // Update the lock.
178 cur_thread->SetAddressKey(addr, value);
179 owner_thread->AddWaiter(cur_thread);
180
181 // Begin waiting.
182 cur_thread->BeginWait(std::addressof(wait_queue));
183 cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar);
184 cur_thread->SetMutexWaitAddressForDebugging(addr);
151 } 185 }
152 186
187 // Close our reference to the owner thread, now that the wait is over.
188 owner_thread->Close();
189
153 // Get the wait result. 190 // Get the wait result.
154 KSynchronizationObject* dummy{}; 191 return cur_thread->GetWaitResult();
155 return cur_thread->GetWaitResult(std::addressof(dummy));
156} 192}
157 193
158KThread* KConditionVariable::SignalImpl(KThread* thread) { 194void KConditionVariable::SignalImpl(KThread* thread) {
159 // Check pre-conditions. 195 // Check pre-conditions.
160 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 196 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
161 197
@@ -169,18 +205,16 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) {
169 // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. 205 // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.
170 // TODO(bunnei): We should call CanAccessAtomic(..) here. 206 // TODO(bunnei): We should call CanAccessAtomic(..) here.
171 can_access = true; 207 can_access = true;
172 if (can_access) { 208 if (can_access) [[likely]] {
173 UpdateLockAtomic(system, std::addressof(prev_tag), address, own_tag, 209 UpdateLockAtomic(system, std::addressof(prev_tag), address, own_tag,
174 Svc::HandleWaitMask); 210 Svc::HandleWaitMask);
175 } 211 }
176 } 212 }
177 213
178 KThread* thread_to_close = nullptr; 214 if (can_access) [[likely]] {
179 if (can_access) {
180 if (prev_tag == Svc::InvalidHandle) { 215 if (prev_tag == Svc::InvalidHandle) {
181 // If nobody held the lock previously, we're all good. 216 // If nobody held the lock previously, we're all good.
182 thread->SetSyncedObject(nullptr, ResultSuccess); 217 thread->EndWait(ResultSuccess);
183 thread->Wakeup();
184 } else { 218 } else {
185 // Get the previous owner. 219 // Get the previous owner.
186 KThread* owner_thread = kernel.CurrentProcess() 220 KThread* owner_thread = kernel.CurrentProcess()
@@ -189,33 +223,22 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) {
189 static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask)) 223 static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask))
190 .ReleasePointerUnsafe(); 224 .ReleasePointerUnsafe();
191 225
192 if (owner_thread) { 226 if (owner_thread) [[likely]] {
193 // Add the thread as a waiter on the owner. 227 // Add the thread as a waiter on the owner.
194 owner_thread->AddWaiter(thread); 228 owner_thread->AddWaiter(thread);
195 thread_to_close = owner_thread; 229 owner_thread->Close();
196 } else { 230 } else {
197 // The lock was tagged with a thread that doesn't exist. 231 // The lock was tagged with a thread that doesn't exist.
198 thread->SetSyncedObject(nullptr, ResultInvalidState); 232 thread->EndWait(ResultInvalidState);
199 thread->Wakeup();
200 } 233 }
201 } 234 }
202 } else { 235 } else {
203 // If the address wasn't accessible, note so. 236 // If the address wasn't accessible, note so.
204 thread->SetSyncedObject(nullptr, ResultInvalidCurrentMemory); 237 thread->EndWait(ResultInvalidCurrentMemory);
205 thread->Wakeup();
206 } 238 }
207
208 return thread_to_close;
209} 239}
210 240
211void KConditionVariable::Signal(u64 cv_key, s32 count) { 241void KConditionVariable::Signal(u64 cv_key, s32 count) {
212 // Prepare for signaling.
213 constexpr int MaxThreads = 16;
214
215 KLinkedList<KThread> thread_list{kernel};
216 std::array<KThread*, MaxThreads> thread_array;
217 s32 num_to_close{};
218
219 // Perform signaling. 242 // Perform signaling.
220 s32 num_waiters{}; 243 s32 num_waiters{};
221 { 244 {
@@ -226,14 +249,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
226 (it->GetConditionVariableKey() == cv_key)) { 249 (it->GetConditionVariableKey() == cv_key)) {
227 KThread* target_thread = std::addressof(*it); 250 KThread* target_thread = std::addressof(*it);
228 251
229 if (KThread* thread = SignalImpl(target_thread); thread != nullptr) { 252 this->SignalImpl(target_thread);
230 if (num_to_close < MaxThreads) {
231 thread_array[num_to_close++] = thread;
232 } else {
233 thread_list.push_back(*thread);
234 }
235 }
236
237 it = thread_tree.erase(it); 253 it = thread_tree.erase(it);
238 target_thread->ClearConditionVariable(); 254 target_thread->ClearConditionVariable();
239 ++num_waiters; 255 ++num_waiters;
@@ -245,27 +261,16 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
245 WriteToUser(system, cv_key, std::addressof(has_waiter_flag)); 261 WriteToUser(system, cv_key, std::addressof(has_waiter_flag));
246 } 262 }
247 } 263 }
248
249 // Close threads in the array.
250 for (auto i = 0; i < num_to_close; ++i) {
251 thread_array[i]->Close();
252 }
253
254 // Close threads in the list.
255 for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) {
256 (*it).Close();
257 }
258} 264}
259 265
260ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { 266ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
261 // Prepare to wait. 267 // Prepare to wait.
262 KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); 268 KThread* cur_thread = GetCurrentThreadPointer(kernel);
269 ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue(
270 kernel, std::addressof(thread_tree));
263 271
264 { 272 {
265 KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; 273 KScopedSchedulerLockAndSleep slp(kernel, cur_thread, timeout);
266
267 // Set the synced object.
268 cur_thread->SetSyncedObject(nullptr, ResultTimedOut);
269 274
270 // Check that the thread isn't terminating. 275 // Check that the thread isn't terminating.
271 if (cur_thread->IsTerminationRequested()) { 276 if (cur_thread->IsTerminationRequested()) {
@@ -290,8 +295,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout)
290 } 295 }
291 296
292 // Wake up the next owner. 297 // Wake up the next owner.
293 next_owner_thread->SetSyncedObject(nullptr, ResultSuccess); 298 next_owner_thread->EndWait(ResultSuccess);
294 next_owner_thread->Wakeup();
295 } 299 }
296 300
297 // Write to the cv key. 301 // Write to the cv key.
@@ -308,40 +312,21 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout)
308 } 312 }
309 } 313 }
310 314
311 // Update condition variable tracking. 315 // If timeout is zero, time out.
312 { 316 R_UNLESS(timeout != 0, ResultTimedOut);
313 cur_thread->SetConditionVariable(std::addressof(thread_tree), addr, key, value);
314 thread_tree.insert(*cur_thread);
315 }
316 317
317 // If the timeout is non-zero, set the thread as waiting. 318 // Update condition variable tracking.
318 if (timeout != 0) { 319 cur_thread->SetConditionVariable(std::addressof(thread_tree), addr, key, value);
319 cur_thread->SetState(ThreadState::Waiting); 320 thread_tree.insert(*cur_thread);
320 cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar);
321 cur_thread->SetMutexWaitAddressForDebugging(addr);
322 }
323 }
324
325 // Cancel the timer wait.
326 kernel.TimeManager().UnscheduleTimeEvent(cur_thread);
327
328 // Remove from the condition variable.
329 {
330 KScopedSchedulerLock sl(kernel);
331
332 if (KThread* owner = cur_thread->GetLockOwner(); owner != nullptr) {
333 owner->RemoveWaiter(cur_thread);
334 }
335 321
336 if (cur_thread->IsWaitingForConditionVariable()) { 322 // Begin waiting.
337 thread_tree.erase(thread_tree.iterator_to(*cur_thread)); 323 cur_thread->BeginWait(std::addressof(wait_queue));
338 cur_thread->ClearConditionVariable(); 324 cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar);
339 } 325 cur_thread->SetMutexWaitAddressForDebugging(addr);
340 } 326 }
341 327
342 // Get the result. 328 // Get the wait result.
343 KSynchronizationObject* dummy{}; 329 return cur_thread->GetWaitResult();
344 return cur_thread->GetWaitResult(std::addressof(dummy));
345} 330}
346 331
347} // namespace Kernel 332} // namespace Kernel
diff --git a/src/core/hle/kernel/k_condition_variable.h b/src/core/hle/kernel/k_condition_variable.h
index 861dbd420..5e4815d08 100644
--- a/src/core/hle/kernel/k_condition_variable.h
+++ b/src/core/hle/kernel/k_condition_variable.h
@@ -34,7 +34,7 @@ public:
34 [[nodiscard]] ResultCode Wait(VAddr addr, u64 key, u32 value, s64 timeout); 34 [[nodiscard]] ResultCode Wait(VAddr addr, u64 key, u32 value, s64 timeout);
35 35
36private: 36private:
37 [[nodiscard]] KThread* SignalImpl(KThread* thread); 37 void SignalImpl(KThread* thread);
38 38
39 ThreadTree thread_tree; 39 ThreadTree thread_tree;
40 40
diff --git a/src/core/hle/kernel/k_handle_table.cpp b/src/core/hle/kernel/k_handle_table.cpp
index e90fc0628..cf95f0852 100644
--- a/src/core/hle/kernel/k_handle_table.cpp
+++ b/src/core/hle/kernel/k_handle_table.cpp
@@ -13,6 +13,7 @@ ResultCode KHandleTable::Finalize() {
13 // Get the table and clear our record of it. 13 // Get the table and clear our record of it.
14 u16 saved_table_size = 0; 14 u16 saved_table_size = 0;
15 { 15 {
16 KScopedDisableDispatch dd(kernel);
16 KScopedSpinLock lk(m_lock); 17 KScopedSpinLock lk(m_lock);
17 18
18 std::swap(m_table_size, saved_table_size); 19 std::swap(m_table_size, saved_table_size);
@@ -43,6 +44,7 @@ bool KHandleTable::Remove(Handle handle) {
43 // Find the object and free the entry. 44 // Find the object and free the entry.
44 KAutoObject* obj = nullptr; 45 KAutoObject* obj = nullptr;
45 { 46 {
47 KScopedDisableDispatch dd(kernel);
46 KScopedSpinLock lk(m_lock); 48 KScopedSpinLock lk(m_lock);
47 49
48 if (this->IsValidHandle(handle)) { 50 if (this->IsValidHandle(handle)) {
@@ -62,6 +64,7 @@ bool KHandleTable::Remove(Handle handle) {
62} 64}
63 65
64ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { 66ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) {
67 KScopedDisableDispatch dd(kernel);
65 KScopedSpinLock lk(m_lock); 68 KScopedSpinLock lk(m_lock);
66 69
67 // Never exceed our capacity. 70 // Never exceed our capacity.
@@ -84,6 +87,7 @@ ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) {
84} 87}
85 88
86ResultCode KHandleTable::Reserve(Handle* out_handle) { 89ResultCode KHandleTable::Reserve(Handle* out_handle) {
90 KScopedDisableDispatch dd(kernel);
87 KScopedSpinLock lk(m_lock); 91 KScopedSpinLock lk(m_lock);
88 92
89 // Never exceed our capacity. 93 // Never exceed our capacity.
@@ -94,6 +98,7 @@ ResultCode KHandleTable::Reserve(Handle* out_handle) {
94} 98}
95 99
96void KHandleTable::Unreserve(Handle handle) { 100void KHandleTable::Unreserve(Handle handle) {
101 KScopedDisableDispatch dd(kernel);
97 KScopedSpinLock lk(m_lock); 102 KScopedSpinLock lk(m_lock);
98 103
99 // Unpack the handle. 104 // Unpack the handle.
@@ -112,6 +117,7 @@ void KHandleTable::Unreserve(Handle handle) {
112} 117}
113 118
114void KHandleTable::Register(Handle handle, KAutoObject* obj, u16 type) { 119void KHandleTable::Register(Handle handle, KAutoObject* obj, u16 type) {
120 KScopedDisableDispatch dd(kernel);
115 KScopedSpinLock lk(m_lock); 121 KScopedSpinLock lk(m_lock);
116 122
117 // Unpack the handle. 123 // Unpack the handle.
diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h
index 95ec905ae..4b114ec2f 100644
--- a/src/core/hle/kernel/k_handle_table.h
+++ b/src/core/hle/kernel/k_handle_table.h
@@ -68,6 +68,7 @@ public:
68 template <typename T = KAutoObject> 68 template <typename T = KAutoObject>
69 KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const { 69 KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const {
70 // Lock and look up in table. 70 // Lock and look up in table.
71 KScopedDisableDispatch dd(kernel);
71 KScopedSpinLock lk(m_lock); 72 KScopedSpinLock lk(m_lock);
72 73
73 if constexpr (std::is_same_v<T, KAutoObject>) { 74 if constexpr (std::is_same_v<T, KAutoObject>) {
@@ -122,6 +123,7 @@ public:
122 size_t num_opened; 123 size_t num_opened;
123 { 124 {
124 // Lock the table. 125 // Lock the table.
126 KScopedDisableDispatch dd(kernel);
125 KScopedSpinLock lk(m_lock); 127 KScopedSpinLock lk(m_lock);
126 for (num_opened = 0; num_opened < num_handles; num_opened++) { 128 for (num_opened = 0; num_opened < num_handles; num_opened++) {
127 // Get the current handle. 129 // Get the current handle.
diff --git a/src/core/hle/kernel/k_light_condition_variable.cpp b/src/core/hle/kernel/k_light_condition_variable.cpp
new file mode 100644
index 000000000..a8001fffc
--- /dev/null
+++ b/src/core/hle/kernel/k_light_condition_variable.cpp
@@ -0,0 +1,80 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/k_light_condition_variable.h"
6#include "core/hle/kernel/k_scheduler.h"
7#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
8#include "core/hle/kernel/k_thread_queue.h"
9#include "core/hle/kernel/svc_results.h"
10
11namespace Kernel {
12
13namespace {
14
15class ThreadQueueImplForKLightConditionVariable final : public KThreadQueue {
16public:
17 ThreadQueueImplForKLightConditionVariable(KernelCore& kernel_, KThread::WaiterList* wl,
18 bool term)
19 : KThreadQueue(kernel_), m_wait_list(wl), m_allow_terminating_thread(term) {}
20
21 void CancelWait(KThread* waiting_thread, ResultCode wait_result,
22 bool cancel_timer_task) override {
23 // Only process waits if we're allowed to.
24 if (ResultTerminationRequested == wait_result && m_allow_terminating_thread) {
25 return;
26 }
27
28 // Remove the thread from the waiting thread from the light condition variable.
29 m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread));
30
31 // Invoke the base cancel wait handler.
32 KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
33 }
34
35private:
36 KThread::WaiterList* m_wait_list;
37 bool m_allow_terminating_thread;
38};
39
40} // namespace
41
42void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_terminating_thread) {
43 // Create thread queue.
44 KThread* owner = GetCurrentThreadPointer(kernel);
45
46 ThreadQueueImplForKLightConditionVariable wait_queue(kernel, std::addressof(wait_list),
47 allow_terminating_thread);
48
49 // Sleep the thread.
50 {
51 KScopedSchedulerLockAndSleep lk(kernel, owner, timeout);
52
53 if (!allow_terminating_thread && owner->IsTerminationRequested()) {
54 lk.CancelSleep();
55 return;
56 }
57
58 lock->Unlock();
59
60 // Add the thread to the queue.
61 wait_list.push_back(*owner);
62
63 // Begin waiting.
64 owner->BeginWait(std::addressof(wait_queue));
65 }
66
67 // Re-acquire the lock.
68 lock->Lock();
69}
70
71void KLightConditionVariable::Broadcast() {
72 KScopedSchedulerLock lk(kernel);
73
74 // Signal all threads.
75 for (auto it = wait_list.begin(); it != wait_list.end(); it = wait_list.erase(it)) {
76 it->EndWait(ResultSuccess);
77 }
78}
79
80} // namespace Kernel
diff --git a/src/core/hle/kernel/k_light_condition_variable.h b/src/core/hle/kernel/k_light_condition_variable.h
index fb0ad783a..5d6d7f128 100644
--- a/src/core/hle/kernel/k_light_condition_variable.h
+++ b/src/core/hle/kernel/k_light_condition_variable.h
@@ -2,72 +2,24 @@
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// This file references various implementation details from Atmosphere, an open-source firmware for
6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
7
8#pragma once 5#pragma once
9 6
10#include "common/common_types.h" 7#include "common/common_types.h"
11#include "core/hle/kernel/k_scheduler.h" 8#include "core/hle/kernel/k_thread.h"
12#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
13#include "core/hle/kernel/time_manager.h"
14 9
15namespace Kernel { 10namespace Kernel {
11
16class KernelCore; 12class KernelCore;
13class KLightLock;
17 14
18class KLightConditionVariable { 15class KLightConditionVariable {
19public: 16public:
20 explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {} 17 explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {}
21 18
22 void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true) { 19 void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true);
23 WaitImpl(lock, timeout, allow_terminating_thread); 20 void Broadcast();
24 }
25
26 void Broadcast() {
27 KScopedSchedulerLock lk{kernel};
28
29 // Signal all threads.
30 for (auto& thread : wait_list) {
31 thread.SetState(ThreadState::Runnable);
32 }
33 }
34 21
35private: 22private:
36 void WaitImpl(KLightLock* lock, s64 timeout, bool allow_terminating_thread) {
37 KThread* owner = GetCurrentThreadPointer(kernel);
38
39 // Sleep the thread.
40 {
41 KScopedSchedulerLockAndSleep lk{kernel, owner, timeout};
42
43 if (!allow_terminating_thread && owner->IsTerminationRequested()) {
44 lk.CancelSleep();
45 return;
46 }
47
48 lock->Unlock();
49
50 // Set the thread as waiting.
51 GetCurrentThread(kernel).SetState(ThreadState::Waiting);
52
53 // Add the thread to the queue.
54 wait_list.push_back(GetCurrentThread(kernel));
55 }
56
57 // Remove the thread from the wait list.
58 {
59 KScopedSchedulerLock sl{kernel};
60
61 wait_list.erase(wait_list.iterator_to(GetCurrentThread(kernel)));
62 }
63
64 // Cancel the task that the sleep setup.
65 kernel.TimeManager().UnscheduleTimeEvent(owner);
66
67 // Re-acquire the lock.
68 lock->Lock();
69 }
70
71 KernelCore& kernel; 23 KernelCore& kernel;
72 KThread::WaiterList wait_list{}; 24 KThread::WaiterList wait_list{};
73}; 25};
diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp
index 0896e705f..4620342eb 100644
--- a/src/core/hle/kernel/k_light_lock.cpp
+++ b/src/core/hle/kernel/k_light_lock.cpp
@@ -5,44 +5,59 @@
5#include "core/hle/kernel/k_light_lock.h" 5#include "core/hle/kernel/k_light_lock.h"
6#include "core/hle/kernel/k_scheduler.h" 6#include "core/hle/kernel/k_scheduler.h"
7#include "core/hle/kernel/k_thread.h" 7#include "core/hle/kernel/k_thread.h"
8#include "core/hle/kernel/k_thread_queue.h"
8#include "core/hle/kernel/kernel.h" 9#include "core/hle/kernel/kernel.h"
9 10
10namespace Kernel { 11namespace Kernel {
11 12
13namespace {
14
15class ThreadQueueImplForKLightLock final : public KThreadQueue {
16public:
17 explicit ThreadQueueImplForKLightLock(KernelCore& kernel_) : KThreadQueue(kernel_) {}
18
19 void CancelWait(KThread* waiting_thread, ResultCode wait_result,
20 bool cancel_timer_task) override {
21 // Remove the thread as a waiter from its owner.
22 if (KThread* owner = waiting_thread->GetLockOwner(); owner != nullptr) {
23 owner->RemoveWaiter(waiting_thread);
24 }
25
26 // Invoke the base cancel wait handler.
27 KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
28 }
29};
30
31} // namespace
32
12void KLightLock::Lock() { 33void KLightLock::Lock() {
13 const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)); 34 const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel));
14 const uintptr_t cur_thread_tag = (cur_thread | 1);
15 35
16 while (true) { 36 while (true) {
17 uintptr_t old_tag = tag.load(std::memory_order_relaxed); 37 uintptr_t old_tag = tag.load(std::memory_order_relaxed);
18 38
19 while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : old_tag | 1, 39 while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : (old_tag | 1),
20 std::memory_order_acquire)) { 40 std::memory_order_acquire)) {
21 if ((old_tag | 1) == cur_thread_tag) {
22 return;
23 }
24 } 41 }
25 42
26 if ((old_tag == 0) || ((old_tag | 1) == cur_thread_tag)) { 43 if (old_tag == 0 || this->LockSlowPath(old_tag | 1, cur_thread)) {
27 break; 44 break;
28 } 45 }
29
30 LockSlowPath(old_tag | 1, cur_thread);
31 } 46 }
32} 47}
33 48
34void KLightLock::Unlock() { 49void KLightLock::Unlock() {
35 const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)); 50 const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel));
51
36 uintptr_t expected = cur_thread; 52 uintptr_t expected = cur_thread;
37 do { 53 if (!tag.compare_exchange_strong(expected, 0, std::memory_order_release)) {
38 if (expected != cur_thread) { 54 this->UnlockSlowPath(cur_thread);
39 return UnlockSlowPath(cur_thread); 55 }
40 }
41 } while (!tag.compare_exchange_weak(expected, 0, std::memory_order_release));
42} 56}
43 57
44void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { 58bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
45 KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread); 59 KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread);
60 ThreadQueueImplForKLightLock wait_queue(kernel);
46 61
47 // Pend the current thread waiting on the owner thread. 62 // Pend the current thread waiting on the owner thread.
48 { 63 {
@@ -50,7 +65,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
50 65
51 // Ensure we actually have locking to do. 66 // Ensure we actually have locking to do.
52 if (tag.load(std::memory_order_relaxed) != _owner) { 67 if (tag.load(std::memory_order_relaxed) != _owner) {
53 return; 68 return false;
54 } 69 }
55 70
56 // Add the current thread as a waiter on the owner. 71 // Add the current thread as a waiter on the owner.
@@ -58,22 +73,15 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
58 cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag))); 73 cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));
59 owner_thread->AddWaiter(cur_thread); 74 owner_thread->AddWaiter(cur_thread);
60 75
61 // Set thread states. 76 // Begin waiting to hold the lock.
62 cur_thread->SetState(ThreadState::Waiting); 77 cur_thread->BeginWait(std::addressof(wait_queue));
63 78
64 if (owner_thread->IsSuspended()) { 79 if (owner_thread->IsSuspended()) {
65 owner_thread->ContinueIfHasKernelWaiters(); 80 owner_thread->ContinueIfHasKernelWaiters();
66 } 81 }
67 } 82 }
68 83
69 // We're no longer waiting on the lock owner. 84 return true;
70 {
71 KScopedSchedulerLock sl{kernel};
72
73 if (KThread* owner_thread = cur_thread->GetLockOwner(); owner_thread != nullptr) {
74 owner_thread->RemoveWaiter(cur_thread);
75 }
76 }
77} 85}
78 86
79void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { 87void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
@@ -81,22 +89,20 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
81 89
82 // Unlock. 90 // Unlock.
83 { 91 {
84 KScopedSchedulerLock sl{kernel}; 92 KScopedSchedulerLock sl(kernel);
85 93
86 // Get the next owner. 94 // Get the next owner.
87 s32 num_waiters = 0; 95 s32 num_waiters;
88 KThread* next_owner = owner_thread->RemoveWaiterByKey( 96 KThread* next_owner = owner_thread->RemoveWaiterByKey(
89 std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag))); 97 std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag)));
90 98
91 // Pass the lock to the next owner. 99 // Pass the lock to the next owner.
92 uintptr_t next_tag = 0; 100 uintptr_t next_tag = 0;
93 if (next_owner != nullptr) { 101 if (next_owner != nullptr) {
94 next_tag = reinterpret_cast<uintptr_t>(next_owner); 102 next_tag =
95 if (num_waiters > 1) { 103 reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(num_waiters > 1);
96 next_tag |= 0x1;
97 }
98 104
99 next_owner->SetState(ThreadState::Runnable); 105 next_owner->EndWait(ResultSuccess);
100 106
101 if (next_owner->IsSuspended()) { 107 if (next_owner->IsSuspended()) {
102 next_owner->ContinueIfHasKernelWaiters(); 108 next_owner->ContinueIfHasKernelWaiters();
@@ -110,7 +116,7 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
110 } 116 }
111 117
112 // Write the new tag value. 118 // Write the new tag value.
113 tag.store(next_tag); 119 tag.store(next_tag, std::memory_order_release);
114 } 120 }
115} 121}
116 122
diff --git a/src/core/hle/kernel/k_light_lock.h b/src/core/hle/kernel/k_light_lock.h
index ad853661d..4163b8a85 100644
--- a/src/core/hle/kernel/k_light_lock.h
+++ b/src/core/hle/kernel/k_light_lock.h
@@ -20,7 +20,7 @@ public:
20 20
21 void Unlock(); 21 void Unlock();
22 22
23 void LockSlowPath(uintptr_t owner, uintptr_t cur_thread); 23 bool LockSlowPath(uintptr_t owner, uintptr_t cur_thread);
24 24
25 void UnlockSlowPath(uintptr_t cur_thread); 25 void UnlockSlowPath(uintptr_t cur_thread);
26 26
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h
index a7fdb5fb8..fd491146f 100644
--- a/src/core/hle/kernel/k_memory_block.h
+++ b/src/core/hle/kernel/k_memory_block.h
@@ -131,6 +131,26 @@ enum class KMemoryPermission : u8 {
131 131
132 UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write | 132 UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write |
133 Svc::MemoryPermission::Execute), 133 Svc::MemoryPermission::Execute),
134
135 KernelShift = 3,
136
137 KernelRead = Read << KernelShift,
138 KernelWrite = Write << KernelShift,
139 KernelExecute = Execute << KernelShift,
140
141 NotMapped = (1 << (2 * KernelShift)),
142
143 KernelReadWrite = KernelRead | KernelWrite,
144 KernelReadExecute = KernelRead | KernelExecute,
145
146 UserRead = Read | KernelRead,
147 UserWrite = Write | KernelWrite,
148 UserExecute = Execute,
149
150 UserReadWrite = UserRead | UserWrite,
151 UserReadExecute = UserRead | UserExecute,
152
153 IpcLockChangeMask = NotMapped | UserReadWrite
134}; 154};
135DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); 155DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
136 156
diff --git a/src/core/hle/kernel/k_page_linked_list.h b/src/core/hle/kernel/k_page_linked_list.h
index 3362fb236..0e2ae582a 100644
--- a/src/core/hle/kernel/k_page_linked_list.h
+++ b/src/core/hle/kernel/k_page_linked_list.h
@@ -27,6 +27,10 @@ public:
27 return num_pages; 27 return num_pages;
28 } 28 }
29 29
30 constexpr std::size_t GetSize() const {
31 return GetNumPages() * PageSize;
32 }
33
30 private: 34 private:
31 u64 addr{}; 35 u64 addr{};
32 std::size_t num_pages{}; 36 std::size_t num_pages{};
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 9bda5c5b2..99982e5a3 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -368,6 +368,33 @@ ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, st
368 return ResultSuccess; 368 return ResultSuccess;
369} 369}
370 370
371ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
372 KPageTable& src_page_table, VAddr src_addr) {
373 std::lock_guard lock{page_table_lock};
374
375 const std::size_t num_pages{size / PageSize};
376
377 // Check that the memory is mapped in the destination process.
378 size_t num_allocator_blocks;
379 R_TRY(CheckMemoryState(&num_allocator_blocks, dst_addr, size, KMemoryState::All,
380 KMemoryState::SharedCode, KMemoryPermission::UserReadWrite,
381 KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
382 KMemoryAttribute::None));
383
384 // Check that the memory is mapped in the source process.
385 R_TRY(src_page_table.CheckMemoryState(src_addr, size, KMemoryState::FlagCanMapProcess,
386 KMemoryState::FlagCanMapProcess, KMemoryPermission::None,
387 KMemoryPermission::None, KMemoryAttribute::All,
388 KMemoryAttribute::None));
389
390 CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
391
392 // Apply the memory block update.
393 block_manager->Update(dst_addr, num_pages, KMemoryState::Free, KMemoryPermission::None,
394 KMemoryAttribute::None);
395
396 return ResultSuccess;
397}
371void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) { 398void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) {
372 auto node{page_linked_list.Nodes().begin()}; 399 auto node{page_linked_list.Nodes().begin()};
373 PAddr map_addr{node->GetAddress()}; 400 PAddr map_addr{node->GetAddress()};
@@ -942,6 +969,60 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
942 return ResultSuccess; 969 return ResultSuccess;
943} 970}
944 971
972ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) {
973 std::lock_guard lock{page_table_lock};
974
975 KMemoryPermission new_perm = KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite;
976
977 KMemoryPermission old_perm{};
978
979 if (const ResultCode result{CheckMemoryState(
980 nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
981 KMemoryState::FlagCanCodeMemory, KMemoryPermission::Mask,
982 KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)};
983 result.IsError()) {
984 return result;
985 }
986
987 new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
988
989 block_manager->UpdateLock(
990 addr, size / PageSize,
991 [](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
992 block->ShareToDevice(permission);
993 },
994 new_perm);
995
996 return ResultSuccess;
997}
998
999ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) {
1000 std::lock_guard lock{page_table_lock};
1001
1002 KMemoryPermission new_perm = KMemoryPermission::UserReadWrite;
1003
1004 KMemoryPermission old_perm{};
1005
1006 if (const ResultCode result{CheckMemoryState(
1007 nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
1008 KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, KMemoryPermission::None,
1009 KMemoryAttribute::All, KMemoryAttribute::Locked)};
1010 result.IsError()) {
1011 return result;
1012 }
1013
1014 new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
1015
1016 block_manager->UpdateLock(
1017 addr, size / PageSize,
1018 [](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
1019 block->UnshareToDevice(permission);
1020 },
1021 new_perm);
1022
1023 return ResultSuccess;
1024}
1025
945ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { 1026ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) {
946 block_manager = std::make_unique<KMemoryBlockManager>(start, end); 1027 block_manager = std::make_unique<KMemoryBlockManager>(start, end);
947 1028
@@ -1231,4 +1312,42 @@ ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermissi
1231 return ResultSuccess; 1312 return ResultSuccess;
1232} 1313}
1233 1314
1315ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size,
1316 KMemoryState state_mask, KMemoryState state,
1317 KMemoryPermission perm_mask, KMemoryPermission perm,
1318 KMemoryAttribute attr_mask, KMemoryAttribute attr) const {
1319 // Get information about the first block.
1320 const VAddr last_addr = addr + size - 1;
1321 KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)};
1322 KMemoryInfo info = it->GetMemoryInfo();
1323
1324 // If the start address isn't aligned, we need a block.
1325 const size_t blocks_for_start_align =
1326 (Common::AlignDown(addr, PageSize) != info.GetAddress()) ? 1 : 0;
1327
1328 while (true) {
1329 // Validate against the provided masks.
1330 R_TRY(CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr));
1331
1332 // Break once we're done.
1333 if (last_addr <= info.GetLastAddress()) {
1334 break;
1335 }
1336
1337 // Advance our iterator.
1338 it++;
1339 info = it->GetMemoryInfo();
1340 }
1341
1342 // If the end address isn't aligned, we need a block.
1343 const size_t blocks_for_end_align =
1344 (Common::AlignUp(addr + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
1345
1346 if (out_blocks_needed != nullptr) {
1347 *out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
1348 }
1349
1350 return ResultSuccess;
1351}
1352
1234} // namespace Kernel 1353} // namespace Kernel
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index b7ec38f06..d784aa67e 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -33,6 +33,8 @@ public:
33 KMemoryPermission perm); 33 KMemoryPermission perm);
34 ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); 34 ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
35 ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); 35 ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
36 ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table,
37 VAddr src_addr);
36 ResultCode MapPhysicalMemory(VAddr addr, std::size_t size); 38 ResultCode MapPhysicalMemory(VAddr addr, std::size_t size);
37 ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size); 39 ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size);
38 ResultCode UnmapMemory(VAddr addr, std::size_t size); 40 ResultCode UnmapMemory(VAddr addr, std::size_t size);
@@ -55,6 +57,8 @@ public:
55 KMemoryPermission perm, PAddr map_addr = 0); 57 KMemoryPermission perm, PAddr map_addr = 0);
56 ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); 58 ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size);
57 ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); 59 ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size);
60 ResultCode LockForCodeMemory(VAddr addr, std::size_t size);
61 ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size);
58 62
59 Common::PageTable& PageTableImpl() { 63 Common::PageTable& PageTableImpl() {
60 return page_table_impl; 64 return page_table_impl;
@@ -115,6 +119,10 @@ private:
115 return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask, 119 return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask,
116 perm, attr_mask, attr, ignore_attr); 120 perm, attr_mask, attr, ignore_attr);
117 } 121 }
122 ResultCode CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size,
123 KMemoryState state_mask, KMemoryState state,
124 KMemoryPermission perm_mask, KMemoryPermission perm,
125 KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
118 126
119 std::recursive_mutex page_table_lock; 127 std::recursive_mutex page_table_lock;
120 std::unique_ptr<KMemoryBlockManager> block_manager; 128 std::unique_ptr<KMemoryBlockManager> block_manager;
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 1aad061e1..90dda40dc 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -60,6 +60,7 @@ void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority
60 thread->GetContext64().cpu_registers[0] = 0; 60 thread->GetContext64().cpu_registers[0] = 0;
61 thread->GetContext32().cpu_registers[1] = thread_handle; 61 thread->GetContext32().cpu_registers[1] = thread_handle;
62 thread->GetContext64().cpu_registers[1] = thread_handle; 62 thread->GetContext64().cpu_registers[1] = thread_handle;
63 thread->DisableDispatch();
63 64
64 auto& kernel = system.Kernel(); 65 auto& kernel = system.Kernel();
65 // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires 66 // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires
@@ -227,12 +228,15 @@ void KProcess::PinCurrentThread() {
227 const s32 core_id = GetCurrentCoreId(kernel); 228 const s32 core_id = GetCurrentCoreId(kernel);
228 KThread* cur_thread = GetCurrentThreadPointer(kernel); 229 KThread* cur_thread = GetCurrentThreadPointer(kernel);
229 230
230 // Pin it. 231 // If the thread isn't terminated, pin it.
231 PinThread(core_id, cur_thread); 232 if (!cur_thread->IsTerminationRequested()) {
232 cur_thread->Pin(); 233 // Pin it.
234 PinThread(core_id, cur_thread);
235 cur_thread->Pin();
233 236
234 // An update is needed. 237 // An update is needed.
235 KScheduler::SetSchedulerUpdateNeeded(kernel); 238 KScheduler::SetSchedulerUpdateNeeded(kernel);
239 }
236} 240}
237 241
238void KProcess::UnpinCurrentThread() { 242void KProcess::UnpinCurrentThread() {
@@ -250,6 +254,20 @@ void KProcess::UnpinCurrentThread() {
250 KScheduler::SetSchedulerUpdateNeeded(kernel); 254 KScheduler::SetSchedulerUpdateNeeded(kernel);
251} 255}
252 256
257void KProcess::UnpinThread(KThread* thread) {
258 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
259
260 // Get the thread's core id.
261 const auto core_id = thread->GetActiveCore();
262
263 // Unpin it.
264 UnpinThread(core_id, thread);
265 thread->Unpin();
266
267 // An update is needed.
268 KScheduler::SetSchedulerUpdateNeeded(kernel);
269}
270
253ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address, 271ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,
254 [[maybe_unused]] size_t size) { 272 [[maybe_unused]] size_t size) {
255 // Lock ourselves, to prevent concurrent access. 273 // Lock ourselves, to prevent concurrent access.
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index 8a8c1fcbb..cb93c7e24 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -347,6 +347,7 @@ public:
347 347
348 void PinCurrentThread(); 348 void PinCurrentThread();
349 void UnpinCurrentThread(); 349 void UnpinCurrentThread();
350 void UnpinThread(KThread* thread);
350 351
351 KLightLock& GetStateLock() { 352 KLightLock& GetStateLock() {
352 return state_lock; 353 return state_lock;
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index 6a7d80d03..277201de4 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -240,8 +240,8 @@ void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s3
240 240
241 // If the thread is runnable, we want to change its priority in the queue. 241 // If the thread is runnable, we want to change its priority in the queue.
242 if (thread->GetRawState() == ThreadState::Runnable) { 242 if (thread->GetRawState() == ThreadState::Runnable) {
243 GetPriorityQueue(kernel).ChangePriority( 243 GetPriorityQueue(kernel).ChangePriority(old_priority,
244 old_priority, thread == kernel.CurrentScheduler()->GetCurrentThread(), thread); 244 thread == kernel.GetCurrentEmuThread(), thread);
245 IncrementScheduledCount(thread); 245 IncrementScheduledCount(thread);
246 SetSchedulerUpdateNeeded(kernel); 246 SetSchedulerUpdateNeeded(kernel);
247 } 247 }
@@ -360,7 +360,7 @@ void KScheduler::RotateScheduledQueue(s32 cpu_core_id, s32 priority) {
360} 360}
361 361
362bool KScheduler::CanSchedule(KernelCore& kernel) { 362bool KScheduler::CanSchedule(KernelCore& kernel) {
363 return kernel.CurrentScheduler()->GetCurrentThread()->GetDisableDispatchCount() <= 1; 363 return kernel.GetCurrentEmuThread()->GetDisableDispatchCount() <= 1;
364} 364}
365 365
366bool KScheduler::IsSchedulerUpdateNeeded(const KernelCore& kernel) { 366bool KScheduler::IsSchedulerUpdateNeeded(const KernelCore& kernel) {
@@ -376,20 +376,30 @@ void KScheduler::ClearSchedulerUpdateNeeded(KernelCore& kernel) {
376} 376}
377 377
378void KScheduler::DisableScheduling(KernelCore& kernel) { 378void KScheduler::DisableScheduling(KernelCore& kernel) {
379 if (auto* scheduler = kernel.CurrentScheduler(); scheduler) { 379 // If we are shutting down the kernel, none of this is relevant anymore.
380 ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 0); 380 if (kernel.IsShuttingDown()) {
381 scheduler->GetCurrentThread()->DisableDispatch(); 381 return;
382 } 382 }
383
384 ASSERT(GetCurrentThreadPointer(kernel)->GetDisableDispatchCount() >= 0);
385 GetCurrentThreadPointer(kernel)->DisableDispatch();
383} 386}
384 387
385void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling) { 388void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling) {
386 if (auto* scheduler = kernel.CurrentScheduler(); scheduler) { 389 // If we are shutting down the kernel, none of this is relevant anymore.
387 ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1); 390 if (kernel.IsShuttingDown()) {
388 if (scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1) { 391 return;
389 scheduler->GetCurrentThread()->EnableDispatch(); 392 }
390 } 393
394 auto* current_thread = GetCurrentThreadPointer(kernel);
395
396 ASSERT(current_thread->GetDisableDispatchCount() >= 1);
397
398 if (current_thread->GetDisableDispatchCount() > 1) {
399 current_thread->EnableDispatch();
400 } else {
401 RescheduleCores(kernel, cores_needing_scheduling);
391 } 402 }
392 RescheduleCores(kernel, cores_needing_scheduling);
393} 403}
394 404
395u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { 405u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) {
@@ -617,13 +627,17 @@ KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, c
617 state.highest_priority_thread = nullptr; 627 state.highest_priority_thread = nullptr;
618} 628}
619 629
620KScheduler::~KScheduler() { 630void KScheduler::Finalize() {
621 if (idle_thread) { 631 if (idle_thread) {
622 idle_thread->Close(); 632 idle_thread->Close();
623 idle_thread = nullptr; 633 idle_thread = nullptr;
624 } 634 }
625} 635}
626 636
637KScheduler::~KScheduler() {
638 ASSERT(!idle_thread);
639}
640
627KThread* KScheduler::GetCurrentThread() const { 641KThread* KScheduler::GetCurrentThread() const {
628 if (auto result = current_thread.load(); result) { 642 if (auto result = current_thread.load(); result) {
629 return result; 643 return result;
@@ -642,10 +656,12 @@ void KScheduler::RescheduleCurrentCore() {
642 if (phys_core.IsInterrupted()) { 656 if (phys_core.IsInterrupted()) {
643 phys_core.ClearInterrupt(); 657 phys_core.ClearInterrupt();
644 } 658 }
659
645 guard.Lock(); 660 guard.Lock();
646 if (state.needs_scheduling.load()) { 661 if (state.needs_scheduling.load()) {
647 Schedule(); 662 Schedule();
648 } else { 663 } else {
664 GetCurrentThread()->EnableDispatch();
649 guard.Unlock(); 665 guard.Unlock();
650 } 666 }
651} 667}
@@ -655,26 +671,33 @@ void KScheduler::OnThreadStart() {
655} 671}
656 672
657void KScheduler::Unload(KThread* thread) { 673void KScheduler::Unload(KThread* thread) {
674 ASSERT(thread);
675
658 LOG_TRACE(Kernel, "core {}, unload thread {}", core_id, thread ? thread->GetName() : "nullptr"); 676 LOG_TRACE(Kernel, "core {}, unload thread {}", core_id, thread ? thread->GetName() : "nullptr");
659 677
660 if (thread) { 678 if (thread->IsCallingSvc()) {
661 if (thread->IsCallingSvc()) { 679 thread->ClearIsCallingSvc();
662 thread->ClearIsCallingSvc(); 680 }
663 } 681
664 if (!thread->IsTerminationRequested()) { 682 auto& physical_core = system.Kernel().PhysicalCore(core_id);
665 prev_thread = thread; 683 if (!physical_core.IsInitialized()) {
666 684 return;
667 Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); 685 }
668 cpu_core.SaveContext(thread->GetContext32()); 686
669 cpu_core.SaveContext(thread->GetContext64()); 687 Core::ARM_Interface& cpu_core = physical_core.ArmInterface();
670 // Save the TPIDR_EL0 system register in case it was modified. 688 cpu_core.SaveContext(thread->GetContext32());
671 thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); 689 cpu_core.SaveContext(thread->GetContext64());
672 cpu_core.ClearExclusiveState(); 690 // Save the TPIDR_EL0 system register in case it was modified.
673 } else { 691 thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0());
674 prev_thread = nullptr; 692 cpu_core.ClearExclusiveState();
675 } 693
676 thread->context_guard.Unlock(); 694 if (!thread->IsTerminationRequested() && thread->GetActiveCore() == core_id) {
695 prev_thread = thread;
696 } else {
697 prev_thread = nullptr;
677 } 698 }
699
700 thread->context_guard.Unlock();
678} 701}
679 702
680void KScheduler::Reload(KThread* thread) { 703void KScheduler::Reload(KThread* thread) {
@@ -683,11 +706,6 @@ void KScheduler::Reload(KThread* thread) {
683 if (thread) { 706 if (thread) {
684 ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable."); 707 ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable.");
685 708
686 auto* const thread_owner_process = thread->GetOwnerProcess();
687 if (thread_owner_process != nullptr) {
688 system.Kernel().MakeCurrentProcess(thread_owner_process);
689 }
690
691 Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); 709 Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
692 cpu_core.LoadContext(thread->GetContext32()); 710 cpu_core.LoadContext(thread->GetContext32());
693 cpu_core.LoadContext(thread->GetContext64()); 711 cpu_core.LoadContext(thread->GetContext64());
@@ -705,7 +723,7 @@ void KScheduler::SwitchContextStep2() {
705} 723}
706 724
707void KScheduler::ScheduleImpl() { 725void KScheduler::ScheduleImpl() {
708 KThread* previous_thread = current_thread.load(); 726 KThread* previous_thread = GetCurrentThread();
709 KThread* next_thread = state.highest_priority_thread; 727 KThread* next_thread = state.highest_priority_thread;
710 728
711 state.needs_scheduling = false; 729 state.needs_scheduling = false;
@@ -717,10 +735,15 @@ void KScheduler::ScheduleImpl() {
717 735
718 // If we're not actually switching thread, there's nothing to do. 736 // If we're not actually switching thread, there's nothing to do.
719 if (next_thread == current_thread.load()) { 737 if (next_thread == current_thread.load()) {
738 previous_thread->EnableDispatch();
720 guard.Unlock(); 739 guard.Unlock();
721 return; 740 return;
722 } 741 }
723 742
743 if (next_thread->GetCurrentCore() != core_id) {
744 next_thread->SetCurrentCore(core_id);
745 }
746
724 current_thread.store(next_thread); 747 current_thread.store(next_thread);
725 748
726 KProcess* const previous_process = system.Kernel().CurrentProcess(); 749 KProcess* const previous_process = system.Kernel().CurrentProcess();
@@ -731,11 +754,7 @@ void KScheduler::ScheduleImpl() {
731 Unload(previous_thread); 754 Unload(previous_thread);
732 755
733 std::shared_ptr<Common::Fiber>* old_context; 756 std::shared_ptr<Common::Fiber>* old_context;
734 if (previous_thread != nullptr) { 757 old_context = &previous_thread->GetHostContext();
735 old_context = &previous_thread->GetHostContext();
736 } else {
737 old_context = &idle_thread->GetHostContext();
738 }
739 guard.Unlock(); 758 guard.Unlock();
740 759
741 Common::Fiber::YieldTo(*old_context, *switch_fiber); 760 Common::Fiber::YieldTo(*old_context, *switch_fiber);
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index 7df288438..82fcd99e7 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -33,6 +33,8 @@ public:
33 explicit KScheduler(Core::System& system_, s32 core_id_); 33 explicit KScheduler(Core::System& system_, s32 core_id_);
34 ~KScheduler(); 34 ~KScheduler();
35 35
36 void Finalize();
37
36 /// Reschedules to the next available thread (call after current thread is suspended) 38 /// Reschedules to the next available thread (call after current thread is suspended)
37 void RescheduleCurrentCore(); 39 void RescheduleCurrentCore();
38 40
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h
index c571f2992..93c47f1b1 100644
--- a/src/core/hle/kernel/k_scheduler_lock.h
+++ b/src/core/hle/kernel/k_scheduler_lock.h
@@ -23,6 +23,11 @@ public:
23 } 23 }
24 24
25 void Lock() { 25 void Lock() {
26 // If we are shutting down the kernel, none of this is relevant anymore.
27 if (kernel.IsShuttingDown()) {
28 return;
29 }
30
26 if (IsLockedByCurrentThread()) { 31 if (IsLockedByCurrentThread()) {
27 // If we already own the lock, we can just increment the count. 32 // If we already own the lock, we can just increment the count.
28 ASSERT(lock_count > 0); 33 ASSERT(lock_count > 0);
@@ -43,6 +48,11 @@ public:
43 } 48 }
44 49
45 void Unlock() { 50 void Unlock() {
51 // If we are shutting down the kernel, none of this is relevant anymore.
52 if (kernel.IsShuttingDown()) {
53 return;
54 }
55
46 ASSERT(IsLockedByCurrentThread()); 56 ASSERT(IsLockedByCurrentThread());
47 ASSERT(lock_count > 0); 57 ASSERT(lock_count > 0);
48 58
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
index 61dc2858f..2995c492d 100644
--- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
+++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
@@ -8,6 +8,7 @@
8#pragma once 8#pragma once
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/kernel/global_scheduler_context.h"
11#include "core/hle/kernel/k_thread.h" 12#include "core/hle/kernel/k_thread.h"
12#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/time_manager.h" 14#include "core/hle/kernel/time_manager.h"
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index 2bd53ccbd..d4e4a6b06 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -175,8 +175,7 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) {
175 { 175 {
176 KScopedSchedulerLock lock(kernel); 176 KScopedSchedulerLock lock(kernel);
177 if (!context.IsThreadWaiting()) { 177 if (!context.IsThreadWaiting()) {
178 context.GetThread().Wakeup(); 178 context.GetThread().EndWait(result);
179 context.GetThread().SetSyncedObject(nullptr, result);
180 } 179 }
181 } 180 }
182 181
diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp
index f168b4f21..e4c5eb74f 100644
--- a/src/core/hle/kernel/k_synchronization_object.cpp
+++ b/src/core/hle/kernel/k_synchronization_object.cpp
@@ -8,11 +8,66 @@
8#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" 8#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
9#include "core/hle/kernel/k_synchronization_object.h" 9#include "core/hle/kernel/k_synchronization_object.h"
10#include "core/hle/kernel/k_thread.h" 10#include "core/hle/kernel/k_thread.h"
11#include "core/hle/kernel/k_thread_queue.h"
11#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/svc_results.h" 13#include "core/hle/kernel/svc_results.h"
13 14
14namespace Kernel { 15namespace Kernel {
15 16
17namespace {
18
19class ThreadQueueImplForKSynchronizationObjectWait final : public KThreadQueueWithoutEndWait {
20public:
21 ThreadQueueImplForKSynchronizationObjectWait(KernelCore& kernel_, KSynchronizationObject** o,
22 KSynchronizationObject::ThreadListNode* n, s32 c)
23 : KThreadQueueWithoutEndWait(kernel_), m_objects(o), m_nodes(n), m_count(c) {}
24
25 void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object,
26 ResultCode wait_result) override {
27 // Determine the sync index, and unlink all nodes.
28 s32 sync_index = -1;
29 for (auto i = 0; i < m_count; ++i) {
30 // Check if this is the signaled object.
31 if (m_objects[i] == signaled_object && sync_index == -1) {
32 sync_index = i;
33 }
34
35 // Unlink the current node from the current object.
36 m_objects[i]->UnlinkNode(std::addressof(m_nodes[i]));
37 }
38
39 // Set the waiting thread's sync index.
40 waiting_thread->SetSyncedIndex(sync_index);
41
42 // Set the waiting thread as not cancellable.
43 waiting_thread->ClearCancellable();
44
45 // Invoke the base end wait handler.
46 KThreadQueue::EndWait(waiting_thread, wait_result);
47 }
48
49 void CancelWait(KThread* waiting_thread, ResultCode wait_result,
50 bool cancel_timer_task) override {
51 // Remove all nodes from our list.
52 for (auto i = 0; i < m_count; ++i) {
53 m_objects[i]->UnlinkNode(std::addressof(m_nodes[i]));
54 }
55
56 // Set the waiting thread as not cancellable.
57 waiting_thread->ClearCancellable();
58
59 // Invoke the base cancel wait handler.
60 KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
61 }
62
63private:
64 KSynchronizationObject** m_objects;
65 KSynchronizationObject::ThreadListNode* m_nodes;
66 s32 m_count;
67};
68
69} // namespace
70
16void KSynchronizationObject::Finalize() { 71void KSynchronizationObject::Finalize() {
17 this->OnFinalizeSynchronizationObject(); 72 this->OnFinalizeSynchronizationObject();
18 KAutoObject::Finalize(); 73 KAutoObject::Finalize();
@@ -25,11 +80,19 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,
25 std::vector<ThreadListNode> thread_nodes(num_objects); 80 std::vector<ThreadListNode> thread_nodes(num_objects);
26 81
27 // Prepare for wait. 82 // Prepare for wait.
28 KThread* thread = kernel_ctx.CurrentScheduler()->GetCurrentThread(); 83 KThread* thread = GetCurrentThreadPointer(kernel_ctx);
84 ThreadQueueImplForKSynchronizationObjectWait wait_queue(kernel_ctx, objects,
85 thread_nodes.data(), num_objects);
29 86
30 { 87 {
31 // Setup the scheduling lock and sleep. 88 // Setup the scheduling lock and sleep.
32 KScopedSchedulerLockAndSleep slp{kernel_ctx, thread, timeout}; 89 KScopedSchedulerLockAndSleep slp(kernel_ctx, thread, timeout);
90
91 // Check if the thread should terminate.
92 if (thread->IsTerminationRequested()) {
93 slp.CancelSleep();
94 return ResultTerminationRequested;
95 }
33 96
34 // Check if any of the objects are already signaled. 97 // Check if any of the objects are already signaled.
35 for (auto i = 0; i < num_objects; ++i) { 98 for (auto i = 0; i < num_objects; ++i) {
@@ -48,12 +111,6 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,
48 return ResultTimedOut; 111 return ResultTimedOut;
49 } 112 }
50 113
51 // Check if the thread should terminate.
52 if (thread->IsTerminationRequested()) {
53 slp.CancelSleep();
54 return ResultTerminationRequested;
55 }
56
57 // Check if waiting was canceled. 114 // Check if waiting was canceled.
58 if (thread->IsWaitCancelled()) { 115 if (thread->IsWaitCancelled()) {
59 slp.CancelSleep(); 116 slp.CancelSleep();
@@ -66,73 +123,25 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,
66 thread_nodes[i].thread = thread; 123 thread_nodes[i].thread = thread;
67 thread_nodes[i].next = nullptr; 124 thread_nodes[i].next = nullptr;
68 125
69 if (objects[i]->thread_list_tail == nullptr) { 126 objects[i]->LinkNode(std::addressof(thread_nodes[i]));
70 objects[i]->thread_list_head = std::addressof(thread_nodes[i]);
71 } else {
72 objects[i]->thread_list_tail->next = std::addressof(thread_nodes[i]);
73 }
74
75 objects[i]->thread_list_tail = std::addressof(thread_nodes[i]);
76 } 127 }
77 128
78 // For debugging only 129 // Mark the thread as cancellable.
79 thread->SetWaitObjectsForDebugging({objects, static_cast<std::size_t>(num_objects)});
80
81 // Mark the thread as waiting.
82 thread->SetCancellable(); 130 thread->SetCancellable();
83 thread->SetSyncedObject(nullptr, ResultTimedOut);
84 thread->SetState(ThreadState::Waiting);
85 thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization);
86 }
87 131
88 // The lock/sleep is done, so we should be able to get our result. 132 // Clear the thread's synced index.
133 thread->SetSyncedIndex(-1);
89 134
90 // Thread is no longer cancellable. 135 // Wait for an object to be signaled.
91 thread->ClearCancellable(); 136 thread->BeginWait(std::addressof(wait_queue));
92 137 thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization);
93 // For debugging only 138 }
94 thread->SetWaitObjectsForDebugging({});
95 139
96 // Cancel the timer as needed. 140 // Set the output index.
97 kernel_ctx.TimeManager().UnscheduleTimeEvent(thread); 141 *out_index = thread->GetSyncedIndex();
98 142
99 // Get the wait result. 143 // Get the wait result.
100 ResultCode wait_result{ResultSuccess}; 144 return thread->GetWaitResult();
101 s32 sync_index = -1;
102 {
103 KScopedSchedulerLock lock(kernel_ctx);
104 KSynchronizationObject* synced_obj;
105 wait_result = thread->GetWaitResult(std::addressof(synced_obj));
106
107 for (auto i = 0; i < num_objects; ++i) {
108 // Unlink the object from the list.
109 ThreadListNode* prev_ptr =
110 reinterpret_cast<ThreadListNode*>(std::addressof(objects[i]->thread_list_head));
111 ThreadListNode* prev_val = nullptr;
112 ThreadListNode *prev, *tail_prev;
113
114 do {
115 prev = prev_ptr;
116 prev_ptr = prev_ptr->next;
117 tail_prev = prev_val;
118 prev_val = prev_ptr;
119 } while (prev_ptr != std::addressof(thread_nodes[i]));
120
121 if (objects[i]->thread_list_tail == std::addressof(thread_nodes[i])) {
122 objects[i]->thread_list_tail = tail_prev;
123 }
124
125 prev->next = thread_nodes[i].next;
126
127 if (objects[i] == synced_obj) {
128 sync_index = i;
129 }
130 }
131 }
132
133 // Set output.
134 *out_index = sync_index;
135 return wait_result;
136} 145}
137 146
138KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) 147KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_)
@@ -141,7 +150,7 @@ KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_)
141KSynchronizationObject::~KSynchronizationObject() = default; 150KSynchronizationObject::~KSynchronizationObject() = default;
142 151
143void KSynchronizationObject::NotifyAvailable(ResultCode result) { 152void KSynchronizationObject::NotifyAvailable(ResultCode result) {
144 KScopedSchedulerLock lock(kernel); 153 KScopedSchedulerLock sl(kernel);
145 154
146 // If we're not signaled, we've nothing to notify. 155 // If we're not signaled, we've nothing to notify.
147 if (!this->IsSignaled()) { 156 if (!this->IsSignaled()) {
@@ -150,11 +159,7 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) {
150 159
151 // Iterate over each thread. 160 // Iterate over each thread.
152 for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { 161 for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) {
153 KThread* thread = cur_node->thread; 162 cur_node->thread->NotifyAvailable(this, result);
154 if (thread->GetState() == ThreadState::Waiting) {
155 thread->SetSyncedObject(this, result);
156 thread->SetState(ThreadState::Runnable);
157 }
158 } 163 }
159} 164}
160 165
diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h
index 898e58e16..ec235437b 100644
--- a/src/core/hle/kernel/k_synchronization_object.h
+++ b/src/core/hle/kernel/k_synchronization_object.h
@@ -35,6 +35,38 @@ public:
35 35
36 [[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const; 36 [[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const;
37 37
38 void LinkNode(ThreadListNode* node_) {
39 // Link the node to the list.
40 if (thread_list_tail == nullptr) {
41 thread_list_head = node_;
42 } else {
43 thread_list_tail->next = node_;
44 }
45
46 thread_list_tail = node_;
47 }
48
49 void UnlinkNode(ThreadListNode* node_) {
50 // Unlink the node from the list.
51 ThreadListNode* prev_ptr =
52 reinterpret_cast<ThreadListNode*>(std::addressof(thread_list_head));
53 ThreadListNode* prev_val = nullptr;
54 ThreadListNode *prev, *tail_prev;
55
56 do {
57 prev = prev_ptr;
58 prev_ptr = prev_ptr->next;
59 tail_prev = prev_val;
60 prev_val = prev_ptr;
61 } while (prev_ptr != node_);
62
63 if (thread_list_tail == node_) {
64 thread_list_tail = tail_prev;
65 }
66
67 prev->next = node_->next;
68 }
69
38protected: 70protected:
39 explicit KSynchronizationObject(KernelCore& kernel); 71 explicit KSynchronizationObject(KernelCore& kernel);
40 ~KSynchronizationObject() override; 72 ~KSynchronizationObject() override;
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index db65ce79a..752592e2e 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -13,6 +13,9 @@
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/fiber.h" 14#include "common/fiber.h"
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "common/scope_exit.h"
17#include "common/settings.h"
18#include "common/thread_queue_list.h"
16#include "core/core.h" 19#include "core/core.h"
17#include "core/cpu_manager.h" 20#include "core/cpu_manager.h"
18#include "core/hardware_properties.h" 21#include "core/hardware_properties.h"
@@ -56,6 +59,34 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context,
56 59
57namespace Kernel { 60namespace Kernel {
58 61
62namespace {
63
64class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait {
65public:
66 explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel_)
67 : KThreadQueueWithoutEndWait(kernel_) {}
68};
69
70class ThreadQueueImplForKThreadSetProperty final : public KThreadQueue {
71public:
72 explicit ThreadQueueImplForKThreadSetProperty(KernelCore& kernel_, KThread::WaiterList* wl)
73 : KThreadQueue(kernel_), m_wait_list(wl) {}
74
75 void CancelWait(KThread* waiting_thread, ResultCode wait_result,
76 bool cancel_timer_task) override {
77 // Remove the thread from the wait list.
78 m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread));
79
80 // Invoke the base cancel wait handler.
81 KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
82 }
83
84private:
85 KThread::WaiterList* m_wait_list;
86};
87
88} // namespace
89
59KThread::KThread(KernelCore& kernel_) 90KThread::KThread(KernelCore& kernel_)
60 : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {} 91 : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {}
61KThread::~KThread() = default; 92KThread::~KThread() = default;
@@ -82,6 +113,8 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
82 [[fallthrough]]; 113 [[fallthrough]];
83 case ThreadType::HighPriority: 114 case ThreadType::HighPriority:
84 [[fallthrough]]; 115 [[fallthrough]];
116 case ThreadType::Dummy:
117 [[fallthrough]];
85 case ThreadType::User: 118 case ThreadType::User:
86 ASSERT(((owner == nullptr) || 119 ASSERT(((owner == nullptr) ||
87 (owner->GetCoreMask() | (1ULL << virt_core)) == owner->GetCoreMask())); 120 (owner->GetCoreMask() | (1ULL << virt_core)) == owner->GetCoreMask()));
@@ -127,11 +160,8 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
127 priority = prio; 160 priority = prio;
128 base_priority = prio; 161 base_priority = prio;
129 162
130 // Set sync object and waiting lock to null.
131 synced_object = nullptr;
132
133 // Initialize sleeping queue. 163 // Initialize sleeping queue.
134 sleeping_queue = nullptr; 164 wait_queue = nullptr;
135 165
136 // Set suspend flags. 166 // Set suspend flags.
137 suspend_request_flags = 0; 167 suspend_request_flags = 0;
@@ -184,7 +214,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
184 // Setup the stack parameters. 214 // Setup the stack parameters.
185 StackParameters& sp = GetStackParameters(); 215 StackParameters& sp = GetStackParameters();
186 sp.cur_thread = this; 216 sp.cur_thread = this;
187 sp.disable_count = 1; 217 sp.disable_count = 0;
188 SetInExceptionHandler(); 218 SetInExceptionHandler();
189 219
190 // Set thread ID. 220 // Set thread ID.
@@ -211,15 +241,16 @@ ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uint
211 // Initialize the thread. 241 // Initialize the thread.
212 R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type)); 242 R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type));
213 243
214 // Initialize host context. 244 // Initialize emulation parameters.
215 thread->host_context = 245 thread->host_context =
216 std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter); 246 std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter);
247 thread->is_single_core = !Settings::values.use_multi_core.GetValue();
217 248
218 return ResultSuccess; 249 return ResultSuccess;
219} 250}
220 251
221ResultCode KThread::InitializeDummyThread(KThread* thread) { 252ResultCode KThread::InitializeDummyThread(KThread* thread) {
222 return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Main); 253 return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Dummy);
223} 254}
224 255
225ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { 256ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
@@ -273,11 +304,14 @@ void KThread::Finalize() {
273 304
274 auto it = waiter_list.begin(); 305 auto it = waiter_list.begin();
275 while (it != waiter_list.end()) { 306 while (it != waiter_list.end()) {
276 // The thread shouldn't be a kernel waiter. 307 // Clear the lock owner
277 it->SetLockOwner(nullptr); 308 it->SetLockOwner(nullptr);
278 it->SetSyncedObject(nullptr, ResultInvalidState); 309
279 it->Wakeup(); 310 // Erase the waiter from our list.
280 it = waiter_list.erase(it); 311 it = waiter_list.erase(it);
312
313 // Cancel the thread's wait.
314 it->CancelWait(ResultInvalidState, true);
281 } 315 }
282 } 316 }
283 317
@@ -294,15 +328,12 @@ bool KThread::IsSignaled() const {
294 return signaled; 328 return signaled;
295} 329}
296 330
297void KThread::Wakeup() { 331void KThread::OnTimer() {
298 KScopedSchedulerLock sl{kernel}; 332 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
299 333
334 // If we're waiting, cancel the wait.
300 if (GetState() == ThreadState::Waiting) { 335 if (GetState() == ThreadState::Waiting) {
301 if (sleeping_queue != nullptr) { 336 wait_queue->CancelWait(this, ResultTimedOut, false);
302 sleeping_queue->WakeupThread(this);
303 } else {
304 SetState(ThreadState::Runnable);
305 }
306 } 337 }
307} 338}
308 339
@@ -327,7 +358,7 @@ void KThread::StartTermination() {
327 358
328 // Signal. 359 // Signal.
329 signaled = true; 360 signaled = true;
330 NotifyAvailable(); 361 KSynchronizationObject::NotifyAvailable();
331 362
332 // Clear previous thread in KScheduler. 363 // Clear previous thread in KScheduler.
333 KScheduler::ClearPreviousThread(kernel, this); 364 KScheduler::ClearPreviousThread(kernel, this);
@@ -475,30 +506,32 @@ ResultCode KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_m
475 return ResultSuccess; 506 return ResultSuccess;
476} 507}
477 508
478ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { 509ResultCode KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) {
479 ASSERT(parent != nullptr); 510 ASSERT(parent != nullptr);
480 ASSERT(v_affinity_mask != 0); 511 ASSERT(v_affinity_mask != 0);
481 KScopedLightLock lk{activity_pause_lock}; 512 KScopedLightLock lk(activity_pause_lock);
482 513
483 // Set the core mask. 514 // Set the core mask.
484 u64 p_affinity_mask = 0; 515 u64 p_affinity_mask = 0;
485 { 516 {
486 KScopedSchedulerLock sl{kernel}; 517 KScopedSchedulerLock sl(kernel);
487 ASSERT(num_core_migration_disables >= 0); 518 ASSERT(num_core_migration_disables >= 0);
488 519
489 // If the core id is no-update magic, preserve the ideal core id. 520 // If we're updating, set our ideal virtual core.
490 if (cpu_core_id == Svc::IdealCoreNoUpdate) { 521 if (core_id_ != Svc::IdealCoreNoUpdate) {
491 cpu_core_id = virtual_ideal_core_id; 522 virtual_ideal_core_id = core_id_;
492 R_UNLESS(((1ULL << cpu_core_id) & v_affinity_mask) != 0, ResultInvalidCombination); 523 } else {
524 // Preserve our ideal core id.
525 core_id_ = virtual_ideal_core_id;
526 R_UNLESS(((1ULL << core_id_) & v_affinity_mask) != 0, ResultInvalidCombination);
493 } 527 }
494 528
495 // Set the virtual core/affinity mask. 529 // Set our affinity mask.
496 virtual_ideal_core_id = cpu_core_id;
497 virtual_affinity_mask = v_affinity_mask; 530 virtual_affinity_mask = v_affinity_mask;
498 531
499 // Translate the virtual core to a physical core. 532 // Translate the virtual core to a physical core.
500 if (cpu_core_id >= 0) { 533 if (core_id_ >= 0) {
501 cpu_core_id = Core::Hardware::VirtualToPhysicalCoreMap[cpu_core_id]; 534 core_id_ = Core::Hardware::VirtualToPhysicalCoreMap[core_id_];
502 } 535 }
503 536
504 // Translate the virtual affinity mask to a physical one. 537 // Translate the virtual affinity mask to a physical one.
@@ -513,7 +546,7 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) {
513 const KAffinityMask old_mask = physical_affinity_mask; 546 const KAffinityMask old_mask = physical_affinity_mask;
514 547
515 // Set our new ideals. 548 // Set our new ideals.
516 physical_ideal_core_id = cpu_core_id; 549 physical_ideal_core_id = core_id_;
517 physical_affinity_mask.SetAffinityMask(p_affinity_mask); 550 physical_affinity_mask.SetAffinityMask(p_affinity_mask);
518 551
519 if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { 552 if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) {
@@ -531,18 +564,18 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) {
531 } 564 }
532 } else { 565 } else {
533 // Otherwise, we edit the original affinity for restoration later. 566 // Otherwise, we edit the original affinity for restoration later.
534 original_physical_ideal_core_id = cpu_core_id; 567 original_physical_ideal_core_id = core_id_;
535 original_physical_affinity_mask.SetAffinityMask(p_affinity_mask); 568 original_physical_affinity_mask.SetAffinityMask(p_affinity_mask);
536 } 569 }
537 } 570 }
538 571
539 // Update the pinned waiter list. 572 // Update the pinned waiter list.
573 ThreadQueueImplForKThreadSetProperty wait_queue_(kernel, std::addressof(pinned_waiter_list));
540 { 574 {
541 bool retry_update{}; 575 bool retry_update{};
542 bool thread_is_pinned{};
543 do { 576 do {
544 // Lock the scheduler. 577 // Lock the scheduler.
545 KScopedSchedulerLock sl{kernel}; 578 KScopedSchedulerLock sl(kernel);
546 579
547 // Don't do any further management if our termination has been requested. 580 // Don't do any further management if our termination has been requested.
548 R_SUCCEED_IF(IsTerminationRequested()); 581 R_SUCCEED_IF(IsTerminationRequested());
@@ -570,12 +603,9 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) {
570 R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), 603 R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(),
571 ResultTerminationRequested); 604 ResultTerminationRequested);
572 605
573 // Note that the thread was pinned.
574 thread_is_pinned = true;
575
576 // Wait until the thread isn't pinned any more. 606 // Wait until the thread isn't pinned any more.
577 pinned_waiter_list.push_back(GetCurrentThread(kernel)); 607 pinned_waiter_list.push_back(GetCurrentThread(kernel));
578 GetCurrentThread(kernel).SetState(ThreadState::Waiting); 608 GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue_));
579 } else { 609 } else {
580 // If the thread isn't pinned, release the scheduler lock and retry until it's 610 // If the thread isn't pinned, release the scheduler lock and retry until it's
581 // not current. 611 // not current.
@@ -583,16 +613,6 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) {
583 } 613 }
584 } 614 }
585 } while (retry_update); 615 } while (retry_update);
586
587 // If the thread was pinned, it no longer is, and we should remove the current thread from
588 // our waiter list.
589 if (thread_is_pinned) {
590 // Lock the scheduler.
591 KScopedSchedulerLock sl{kernel};
592
593 // Remove from the list.
594 pinned_waiter_list.erase(pinned_waiter_list.iterator_to(GetCurrentThread(kernel)));
595 }
596 } 616 }
597 617
598 return ResultSuccess; 618 return ResultSuccess;
@@ -641,15 +661,9 @@ void KThread::WaitCancel() {
641 KScopedSchedulerLock sl{kernel}; 661 KScopedSchedulerLock sl{kernel};
642 662
643 // Check if we're waiting and cancellable. 663 // Check if we're waiting and cancellable.
644 if (GetState() == ThreadState::Waiting && cancellable) { 664 if (this->GetState() == ThreadState::Waiting && cancellable) {
645 if (sleeping_queue != nullptr) { 665 wait_cancelled = false;
646 sleeping_queue->WakeupThread(this); 666 wait_queue->CancelWait(this, ResultCancelled, true);
647 wait_cancelled = true;
648 } else {
649 SetSyncedObject(nullptr, ResultCancelled);
650 SetState(ThreadState::Runnable);
651 wait_cancelled = false;
652 }
653 } else { 667 } else {
654 // Otherwise, note that we cancelled a wait. 668 // Otherwise, note that we cancelled a wait.
655 wait_cancelled = true; 669 wait_cancelled = true;
@@ -700,60 +714,59 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) {
700 // Set the activity. 714 // Set the activity.
701 { 715 {
702 // Lock the scheduler. 716 // Lock the scheduler.
703 KScopedSchedulerLock sl{kernel}; 717 KScopedSchedulerLock sl(kernel);
704 718
705 // Verify our state. 719 // Verify our state.
706 const auto cur_state = GetState(); 720 const auto cur_state = this->GetState();
707 R_UNLESS((cur_state == ThreadState::Waiting || cur_state == ThreadState::Runnable), 721 R_UNLESS((cur_state == ThreadState::Waiting || cur_state == ThreadState::Runnable),
708 ResultInvalidState); 722 ResultInvalidState);
709 723
710 // Either pause or resume. 724 // Either pause or resume.
711 if (activity == Svc::ThreadActivity::Paused) { 725 if (activity == Svc::ThreadActivity::Paused) {
712 // Verify that we're not suspended. 726 // Verify that we're not suspended.
713 R_UNLESS(!IsSuspendRequested(SuspendType::Thread), ResultInvalidState); 727 R_UNLESS(!this->IsSuspendRequested(SuspendType::Thread), ResultInvalidState);
714 728
715 // Suspend. 729 // Suspend.
716 RequestSuspend(SuspendType::Thread); 730 this->RequestSuspend(SuspendType::Thread);
717 } else { 731 } else {
718 ASSERT(activity == Svc::ThreadActivity::Runnable); 732 ASSERT(activity == Svc::ThreadActivity::Runnable);
719 733
720 // Verify that we're suspended. 734 // Verify that we're suspended.
721 R_UNLESS(IsSuspendRequested(SuspendType::Thread), ResultInvalidState); 735 R_UNLESS(this->IsSuspendRequested(SuspendType::Thread), ResultInvalidState);
722 736
723 // Resume. 737 // Resume.
724 Resume(SuspendType::Thread); 738 this->Resume(SuspendType::Thread);
725 } 739 }
726 } 740 }
727 741
728 // If the thread is now paused, update the pinned waiter list. 742 // If the thread is now paused, update the pinned waiter list.
729 if (activity == Svc::ThreadActivity::Paused) { 743 if (activity == Svc::ThreadActivity::Paused) {
730 bool thread_is_pinned{}; 744 ThreadQueueImplForKThreadSetProperty wait_queue_(kernel,
731 bool thread_is_current{}; 745 std::addressof(pinned_waiter_list));
746
747 bool thread_is_current;
732 do { 748 do {
733 // Lock the scheduler. 749 // Lock the scheduler.
734 KScopedSchedulerLock sl{kernel}; 750 KScopedSchedulerLock sl(kernel);
735 751
736 // Don't do any further management if our termination has been requested. 752 // Don't do any further management if our termination has been requested.
737 R_SUCCEED_IF(IsTerminationRequested()); 753 R_SUCCEED_IF(this->IsTerminationRequested());
754
755 // By default, treat the thread as not current.
756 thread_is_current = false;
738 757
739 // Check whether the thread is pinned. 758 // Check whether the thread is pinned.
740 if (GetStackParameters().is_pinned) { 759 if (this->GetStackParameters().is_pinned) {
741 // Verify that the current thread isn't terminating. 760 // Verify that the current thread isn't terminating.
742 R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), 761 R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(),
743 ResultTerminationRequested); 762 ResultTerminationRequested);
744 763
745 // Note that the thread was pinned and not current.
746 thread_is_pinned = true;
747 thread_is_current = false;
748
749 // Wait until the thread isn't pinned any more. 764 // Wait until the thread isn't pinned any more.
750 pinned_waiter_list.push_back(GetCurrentThread(kernel)); 765 pinned_waiter_list.push_back(GetCurrentThread(kernel));
751 GetCurrentThread(kernel).SetState(ThreadState::Waiting); 766 GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue_));
752 } else { 767 } else {
753 // Check if the thread is currently running. 768 // Check if the thread is currently running.
754 // If it is, we'll need to retry. 769 // If it is, we'll need to retry.
755 thread_is_current = false;
756
757 for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { 770 for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
758 if (kernel.Scheduler(i).GetCurrentThread() == this) { 771 if (kernel.Scheduler(i).GetCurrentThread() == this) {
759 thread_is_current = true; 772 thread_is_current = true;
@@ -762,16 +775,6 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) {
762 } 775 }
763 } 776 }
764 } while (thread_is_current); 777 } while (thread_is_current);
765
766 // If the thread was pinned, it no longer is, and we should remove the current thread from
767 // our waiter list.
768 if (thread_is_pinned) {
769 // Lock the scheduler.
770 KScopedSchedulerLock sl{kernel};
771
772 // Remove from the list.
773 pinned_waiter_list.erase(pinned_waiter_list.iterator_to(GetCurrentThread(kernel)));
774 }
775 } 778 }
776 779
777 return ResultSuccess; 780 return ResultSuccess;
@@ -966,6 +969,9 @@ ResultCode KThread::Run() {
966 969
967 // Set our state and finish. 970 // Set our state and finish.
968 SetState(ThreadState::Runnable); 971 SetState(ThreadState::Runnable);
972
973 DisableDispatch();
974
969 return ResultSuccess; 975 return ResultSuccess;
970 } 976 }
971} 977}
@@ -996,27 +1002,61 @@ ResultCode KThread::Sleep(s64 timeout) {
996 ASSERT(this == GetCurrentThreadPointer(kernel)); 1002 ASSERT(this == GetCurrentThreadPointer(kernel));
997 ASSERT(timeout > 0); 1003 ASSERT(timeout > 0);
998 1004
1005 ThreadQueueImplForKThreadSleep wait_queue_(kernel);
999 { 1006 {
1000 // Setup the scheduling lock and sleep. 1007 // Setup the scheduling lock and sleep.
1001 KScopedSchedulerLockAndSleep slp{kernel, this, timeout}; 1008 KScopedSchedulerLockAndSleep slp(kernel, this, timeout);
1002 1009
1003 // Check if the thread should terminate. 1010 // Check if the thread should terminate.
1004 if (IsTerminationRequested()) { 1011 if (this->IsTerminationRequested()) {
1005 slp.CancelSleep(); 1012 slp.CancelSleep();
1006 return ResultTerminationRequested; 1013 return ResultTerminationRequested;
1007 } 1014 }
1008 1015
1009 // Mark the thread as waiting. 1016 // Wait for the sleep to end.
1010 SetState(ThreadState::Waiting); 1017 this->BeginWait(std::addressof(wait_queue_));
1011 SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep); 1018 SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep);
1012 } 1019 }
1013 1020
1014 // The lock/sleep is done. 1021 return ResultSuccess;
1022}
1015 1023
1016 // Cancel the timer. 1024void KThread::BeginWait(KThreadQueue* queue) {
1017 kernel.TimeManager().UnscheduleTimeEvent(this); 1025 // Set our state as waiting.
1026 SetState(ThreadState::Waiting);
1018 1027
1019 return ResultSuccess; 1028 // Set our wait queue.
1029 wait_queue = queue;
1030}
1031
1032void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) {
1033 // Lock the scheduler.
1034 KScopedSchedulerLock sl(kernel);
1035
1036 // If we're waiting, notify our queue that we're available.
1037 if (GetState() == ThreadState::Waiting) {
1038 wait_queue->NotifyAvailable(this, signaled_object, wait_result_);
1039 }
1040}
1041
1042void KThread::EndWait(ResultCode wait_result_) {
1043 // Lock the scheduler.
1044 KScopedSchedulerLock sl(kernel);
1045
1046 // If we're waiting, notify our queue that we're available.
1047 if (GetState() == ThreadState::Waiting) {
1048 wait_queue->EndWait(this, wait_result_);
1049 }
1050}
1051
1052void KThread::CancelWait(ResultCode wait_result_, bool cancel_timer_task) {
1053 // Lock the scheduler.
1054 KScopedSchedulerLock sl(kernel);
1055
1056 // If we're waiting, notify our queue that we're available.
1057 if (GetState() == ThreadState::Waiting) {
1058 wait_queue->CancelWait(this, wait_result_, cancel_timer_task);
1059 }
1020} 1060}
1021 1061
1022void KThread::SetState(ThreadState state) { 1062void KThread::SetState(ThreadState state) {
@@ -1050,4 +1090,26 @@ s32 GetCurrentCoreId(KernelCore& kernel) {
1050 return GetCurrentThread(kernel).GetCurrentCore(); 1090 return GetCurrentThread(kernel).GetCurrentCore();
1051} 1091}
1052 1092
1093KScopedDisableDispatch::~KScopedDisableDispatch() {
1094 // If we are shutting down the kernel, none of this is relevant anymore.
1095 if (kernel.IsShuttingDown()) {
1096 return;
1097 }
1098
1099 // Skip the reschedule if single-core, as dispatch tracking is disabled here.
1100 if (!Settings::values.use_multi_core.GetValue()) {
1101 return;
1102 }
1103
1104 if (GetCurrentThread(kernel).GetDisableDispatchCount() <= 1) {
1105 auto scheduler = kernel.CurrentScheduler();
1106
1107 if (scheduler) {
1108 scheduler->RescheduleCurrentCore();
1109 }
1110 } else {
1111 GetCurrentThread(kernel).EnableDispatch();
1112 }
1113}
1114
1053} // namespace Kernel 1115} // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index c77f44ad4..c8a08bd71 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -48,6 +48,7 @@ enum class ThreadType : u32 {
48 Kernel = 1, 48 Kernel = 1,
49 HighPriority = 2, 49 HighPriority = 2,
50 User = 3, 50 User = 3,
51 Dummy = 100, // Special thread type for emulation purposes only
51}; 52};
52DECLARE_ENUM_FLAG_OPERATORS(ThreadType); 53DECLARE_ENUM_FLAG_OPERATORS(ThreadType);
53 54
@@ -161,8 +162,6 @@ public:
161 } 162 }
162 } 163 }
163 164
164 void Wakeup();
165
166 void SetBasePriority(s32 value); 165 void SetBasePriority(s32 value);
167 166
168 [[nodiscard]] ResultCode Run(); 167 [[nodiscard]] ResultCode Run();
@@ -197,13 +196,19 @@ public:
197 196
198 void Suspend(); 197 void Suspend();
199 198
200 void SetSyncedObject(KSynchronizationObject* obj, ResultCode wait_res) { 199 constexpr void SetSyncedIndex(s32 index) {
201 synced_object = obj; 200 synced_index = index;
201 }
202
203 [[nodiscard]] constexpr s32 GetSyncedIndex() const {
204 return synced_index;
205 }
206
207 constexpr void SetWaitResult(ResultCode wait_res) {
202 wait_result = wait_res; 208 wait_result = wait_res;
203 } 209 }
204 210
205 [[nodiscard]] ResultCode GetWaitResult(KSynchronizationObject** out) const { 211 [[nodiscard]] constexpr ResultCode GetWaitResult() const {
206 *out = synced_object;
207 return wait_result; 212 return wait_result;
208 } 213 }
209 214
@@ -374,6 +379,8 @@ public:
374 379
375 [[nodiscard]] bool IsSignaled() const override; 380 [[nodiscard]] bool IsSignaled() const override;
376 381
382 void OnTimer();
383
377 static void PostDestroy(uintptr_t arg); 384 static void PostDestroy(uintptr_t arg);
378 385
379 [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread); 386 [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread);
@@ -446,20 +453,39 @@ public:
446 return per_core_priority_queue_entry[core]; 453 return per_core_priority_queue_entry[core];
447 } 454 }
448 455
449 void SetSleepingQueue(KThreadQueue* q) { 456 [[nodiscard]] bool IsKernelThread() const {
450 sleeping_queue = q; 457 return GetActiveCore() == 3;
458 }
459
460 [[nodiscard]] bool IsDispatchTrackingDisabled() const {
461 return is_single_core || IsKernelThread();
451 } 462 }
452 463
453 [[nodiscard]] s32 GetDisableDispatchCount() const { 464 [[nodiscard]] s32 GetDisableDispatchCount() const {
465 if (IsDispatchTrackingDisabled()) {
466 // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch.
467 return 1;
468 }
469
454 return this->GetStackParameters().disable_count; 470 return this->GetStackParameters().disable_count;
455 } 471 }
456 472
457 void DisableDispatch() { 473 void DisableDispatch() {
474 if (IsDispatchTrackingDisabled()) {
475 // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch.
476 return;
477 }
478
458 ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() >= 0); 479 ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() >= 0);
459 this->GetStackParameters().disable_count++; 480 this->GetStackParameters().disable_count++;
460 } 481 }
461 482
462 void EnableDispatch() { 483 void EnableDispatch() {
484 if (IsDispatchTrackingDisabled()) {
485 // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch.
486 return;
487 }
488
463 ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() > 0); 489 ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() > 0);
464 this->GetStackParameters().disable_count--; 490 this->GetStackParameters().disable_count--;
465 } 491 }
@@ -573,6 +599,15 @@ public:
573 address_key_value = val; 599 address_key_value = val;
574 } 600 }
575 601
602 void ClearWaitQueue() {
603 wait_queue = nullptr;
604 }
605
606 void BeginWait(KThreadQueue* queue);
607 void NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_);
608 void EndWait(ResultCode wait_result_);
609 void CancelWait(ResultCode wait_result_, bool cancel_timer_task);
610
576 [[nodiscard]] bool HasWaiters() const { 611 [[nodiscard]] bool HasWaiters() const {
577 return !waiter_list.empty(); 612 return !waiter_list.empty();
578 } 613 }
@@ -667,7 +702,6 @@ private:
667 KAffinityMask physical_affinity_mask{}; 702 KAffinityMask physical_affinity_mask{};
668 u64 thread_id{}; 703 u64 thread_id{};
669 std::atomic<s64> cpu_time{}; 704 std::atomic<s64> cpu_time{};
670 KSynchronizationObject* synced_object{};
671 VAddr address_key{}; 705 VAddr address_key{};
672 KProcess* parent{}; 706 KProcess* parent{};
673 VAddr kernel_stack_top{}; 707 VAddr kernel_stack_top{};
@@ -677,13 +711,14 @@ private:
677 s64 schedule_count{}; 711 s64 schedule_count{};
678 s64 last_scheduled_tick{}; 712 s64 last_scheduled_tick{};
679 std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{}; 713 std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{};
680 KThreadQueue* sleeping_queue{}; 714 KThreadQueue* wait_queue{};
681 WaiterList waiter_list{}; 715 WaiterList waiter_list{};
682 WaiterList pinned_waiter_list{}; 716 WaiterList pinned_waiter_list{};
683 KThread* lock_owner{}; 717 KThread* lock_owner{};
684 u32 address_key_value{}; 718 u32 address_key_value{};
685 u32 suspend_request_flags{}; 719 u32 suspend_request_flags{};
686 u32 suspend_allowed_flags{}; 720 u32 suspend_allowed_flags{};
721 s32 synced_index{};
687 ResultCode wait_result{ResultSuccess}; 722 ResultCode wait_result{ResultSuccess};
688 s32 base_priority{}; 723 s32 base_priority{};
689 s32 physical_ideal_core_id{}; 724 s32 physical_ideal_core_id{};
@@ -708,6 +743,7 @@ private:
708 743
709 // For emulation 744 // For emulation
710 std::shared_ptr<Common::Fiber> host_context{}; 745 std::shared_ptr<Common::Fiber> host_context{};
746 bool is_single_core{};
711 747
712 // For debugging 748 // For debugging
713 std::vector<KSynchronizationObject*> wait_objects_for_debugging; 749 std::vector<KSynchronizationObject*> wait_objects_for_debugging;
@@ -752,4 +788,20 @@ public:
752 } 788 }
753}; 789};
754 790
791class KScopedDisableDispatch {
792public:
793 [[nodiscard]] explicit KScopedDisableDispatch(KernelCore& kernel_) : kernel{kernel_} {
794 // If we are shutting down the kernel, none of this is relevant anymore.
795 if (kernel.IsShuttingDown()) {
796 return;
797 }
798 GetCurrentThread(kernel).DisableDispatch();
799 }
800
801 ~KScopedDisableDispatch();
802
803private:
804 KernelCore& kernel;
805};
806
755} // namespace Kernel 807} // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread_queue.cpp b/src/core/hle/kernel/k_thread_queue.cpp
new file mode 100644
index 000000000..d5248b547
--- /dev/null
+++ b/src/core/hle/kernel/k_thread_queue.cpp
@@ -0,0 +1,49 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/k_thread_queue.h"
6#include "core/hle/kernel/kernel.h"
7#include "core/hle/kernel/time_manager.h"
8
9namespace Kernel {
10
11void KThreadQueue::NotifyAvailable([[maybe_unused]] KThread* waiting_thread,
12 [[maybe_unused]] KSynchronizationObject* signaled_object,
13 [[maybe_unused]] ResultCode wait_result) {}
14
15void KThreadQueue::EndWait(KThread* waiting_thread, ResultCode wait_result) {
16 // Set the thread's wait result.
17 waiting_thread->SetWaitResult(wait_result);
18
19 // Set the thread as runnable.
20 waiting_thread->SetState(ThreadState::Runnable);
21
22 // Clear the thread's wait queue.
23 waiting_thread->ClearWaitQueue();
24
25 // Cancel the thread task.
26 kernel.TimeManager().UnscheduleTimeEvent(waiting_thread);
27}
28
29void KThreadQueue::CancelWait(KThread* waiting_thread, ResultCode wait_result,
30 bool cancel_timer_task) {
31 // Set the thread's wait result.
32 waiting_thread->SetWaitResult(wait_result);
33
34 // Set the thread as runnable.
35 waiting_thread->SetState(ThreadState::Runnable);
36
37 // Clear the thread's wait queue.
38 waiting_thread->ClearWaitQueue();
39
40 // Cancel the thread task.
41 if (cancel_timer_task) {
42 kernel.TimeManager().UnscheduleTimeEvent(waiting_thread);
43 }
44}
45
46void KThreadQueueWithoutEndWait::EndWait([[maybe_unused]] KThread* waiting_thread,
47 [[maybe_unused]] ResultCode wait_result) {}
48
49} // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread_queue.h b/src/core/hle/kernel/k_thread_queue.h
index 35d471dc5..ccb718e49 100644
--- a/src/core/hle/kernel/k_thread_queue.h
+++ b/src/core/hle/kernel/k_thread_queue.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/k_scheduler.h"
7#include "core/hle/kernel/k_thread.h" 8#include "core/hle/kernel/k_thread.h"
8 9
9namespace Kernel { 10namespace Kernel {
@@ -11,71 +12,24 @@ namespace Kernel {
11class KThreadQueue { 12class KThreadQueue {
12public: 13public:
13 explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {} 14 explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {}
15 virtual ~KThreadQueue() = default;
14 16
15 bool IsEmpty() const { 17 virtual void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object,
16 return wait_list.empty(); 18 ResultCode wait_result);
17 } 19 virtual void EndWait(KThread* waiting_thread, ResultCode wait_result);
18 20 virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result,
19 KThread::WaiterList::iterator begin() { 21 bool cancel_timer_task);
20 return wait_list.begin();
21 }
22 KThread::WaiterList::iterator end() {
23 return wait_list.end();
24 }
25
26 bool SleepThread(KThread* t) {
27 KScopedSchedulerLock sl{kernel};
28
29 // If the thread needs terminating, don't enqueue it.
30 if (t->IsTerminationRequested()) {
31 return false;
32 }
33
34 // Set the thread's queue and mark it as waiting.
35 t->SetSleepingQueue(this);
36 t->SetState(ThreadState::Waiting);
37
38 // Add the thread to the queue.
39 wait_list.push_back(*t);
40
41 return true;
42 }
43
44 void WakeupThread(KThread* t) {
45 KScopedSchedulerLock sl{kernel};
46
47 // Remove the thread from the queue.
48 wait_list.erase(wait_list.iterator_to(*t));
49
50 // Mark the thread as no longer sleeping.
51 t->SetState(ThreadState::Runnable);
52 t->SetSleepingQueue(nullptr);
53 }
54
55 KThread* WakeupFrontThread() {
56 KScopedSchedulerLock sl{kernel};
57
58 if (wait_list.empty()) {
59 return nullptr;
60 } else {
61 // Remove the thread from the queue.
62 auto it = wait_list.begin();
63 KThread* thread = std::addressof(*it);
64 wait_list.erase(it);
65
66 ASSERT(thread->GetState() == ThreadState::Waiting);
67
68 // Mark the thread as no longer sleeping.
69 thread->SetState(ThreadState::Runnable);
70 thread->SetSleepingQueue(nullptr);
71
72 return thread;
73 }
74 }
75 22
76private: 23private:
77 KernelCore& kernel; 24 KernelCore& kernel;
78 KThread::WaiterList wait_list{}; 25 KThread::WaiterList wait_list{};
79}; 26};
80 27
28class KThreadQueueWithoutEndWait : public KThreadQueue {
29public:
30 explicit KThreadQueueWithoutEndWait(KernelCore& kernel_) : KThreadQueue(kernel_) {}
31
32 void EndWait(KThread* waiting_thread, ResultCode wait_result) override final;
33};
34
81} // namespace Kernel 35} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 45e86a677..2e4e4cb1c 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -14,6 +14,7 @@
14#include "common/assert.h" 14#include "common/assert.h"
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "common/microprofile.h" 16#include "common/microprofile.h"
17#include "common/scope_exit.h"
17#include "common/thread.h" 18#include "common/thread.h"
18#include "common/thread_worker.h" 19#include "common/thread_worker.h"
19#include "core/arm/arm_interface.h" 20#include "core/arm/arm_interface.h"
@@ -83,12 +84,16 @@ struct KernelCore::Impl {
83 } 84 }
84 85
85 void InitializeCores() { 86 void InitializeCores() {
86 for (auto& core : cores) { 87 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
87 core.Initialize(current_process->Is64BitProcess()); 88 cores[core_id].Initialize(current_process->Is64BitProcess());
89 system.Memory().SetCurrentPageTable(*current_process, core_id);
88 } 90 }
89 } 91 }
90 92
91 void Shutdown() { 93 void Shutdown() {
94 is_shutting_down.store(true, std::memory_order_relaxed);
95 SCOPE_EXIT({ is_shutting_down.store(false, std::memory_order_relaxed); });
96
92 process_list.clear(); 97 process_list.clear();
93 98
94 // Close all open server ports. 99 // Close all open server ports.
@@ -123,15 +128,6 @@ struct KernelCore::Impl {
123 next_user_process_id = KProcess::ProcessIDMin; 128 next_user_process_id = KProcess::ProcessIDMin;
124 next_thread_id = 1; 129 next_thread_id = 1;
125 130
126 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
127 if (suspend_threads[core_id]) {
128 suspend_threads[core_id]->Close();
129 suspend_threads[core_id] = nullptr;
130 }
131
132 schedulers[core_id].reset();
133 }
134
135 cores.clear(); 131 cores.clear();
136 132
137 global_handle_table->Finalize(); 133 global_handle_table->Finalize();
@@ -159,6 +155,16 @@ struct KernelCore::Impl {
159 CleanupObject(time_shared_mem); 155 CleanupObject(time_shared_mem);
160 CleanupObject(system_resource_limit); 156 CleanupObject(system_resource_limit);
161 157
158 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
159 if (suspend_threads[core_id]) {
160 suspend_threads[core_id]->Close();
161 suspend_threads[core_id] = nullptr;
162 }
163
164 schedulers[core_id]->Finalize();
165 schedulers[core_id].reset();
166 }
167
162 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others 168 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
163 next_host_thread_id = Core::Hardware::NUM_CPU_CORES; 169 next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
164 170
@@ -245,13 +251,11 @@ struct KernelCore::Impl {
245 KScopedSchedulerLock lock(kernel); 251 KScopedSchedulerLock lock(kernel);
246 global_scheduler_context->PreemptThreads(); 252 global_scheduler_context->PreemptThreads();
247 } 253 }
248 const auto time_interval = std::chrono::nanoseconds{ 254 const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)};
249 Core::Timing::msToCycles(std::chrono::milliseconds(10))};
250 system.CoreTiming().ScheduleEvent(time_interval, preemption_event); 255 system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
251 }); 256 });
252 257
253 const auto time_interval = 258 const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)};
254 std::chrono::nanoseconds{Core::Timing::msToCycles(std::chrono::milliseconds(10))};
255 system.CoreTiming().ScheduleEvent(time_interval, preemption_event); 259 system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
256 } 260 }
257 261
@@ -267,14 +271,6 @@ struct KernelCore::Impl {
267 271
268 void MakeCurrentProcess(KProcess* process) { 272 void MakeCurrentProcess(KProcess* process) {
269 current_process = process; 273 current_process = process;
270 if (process == nullptr) {
271 return;
272 }
273
274 const u32 core_id = GetCurrentHostThreadID();
275 if (core_id < Core::Hardware::NUM_CPU_CORES) {
276 system.Memory().SetCurrentPageTable(*process, core_id);
277 }
278 } 274 }
279 275
280 static inline thread_local u32 host_thread_id = UINT32_MAX; 276 static inline thread_local u32 host_thread_id = UINT32_MAX;
@@ -344,7 +340,16 @@ struct KernelCore::Impl {
344 is_phantom_mode_for_singlecore = value; 340 is_phantom_mode_for_singlecore = value;
345 } 341 }
346 342
343 bool IsShuttingDown() const {
344 return is_shutting_down.load(std::memory_order_relaxed);
345 }
346
347 KThread* GetCurrentEmuThread() { 347 KThread* GetCurrentEmuThread() {
348 // If we are shutting down the kernel, none of this is relevant anymore.
349 if (IsShuttingDown()) {
350 return {};
351 }
352
348 const auto thread_id = GetCurrentHostThreadID(); 353 const auto thread_id = GetCurrentHostThreadID();
349 if (thread_id >= Core::Hardware::NUM_CPU_CORES) { 354 if (thread_id >= Core::Hardware::NUM_CPU_CORES) {
350 return GetHostDummyThread(); 355 return GetHostDummyThread();
@@ -760,6 +765,7 @@ struct KernelCore::Impl {
760 std::vector<std::unique_ptr<KThread>> dummy_threads; 765 std::vector<std::unique_ptr<KThread>> dummy_threads;
761 766
762 bool is_multicore{}; 767 bool is_multicore{};
768 std::atomic_bool is_shutting_down{};
763 bool is_phantom_mode_for_singlecore{}; 769 bool is_phantom_mode_for_singlecore{};
764 u32 single_core_thread_id{}; 770 u32 single_core_thread_id{};
765 771
@@ -845,16 +851,20 @@ const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
845 return impl->cores[id]; 851 return impl->cores[id];
846} 852}
847 853
854size_t KernelCore::CurrentPhysicalCoreIndex() const {
855 const u32 core_id = impl->GetCurrentHostThreadID();
856 if (core_id >= Core::Hardware::NUM_CPU_CORES) {
857 return Core::Hardware::NUM_CPU_CORES - 1;
858 }
859 return core_id;
860}
861
848Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() { 862Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() {
849 u32 core_id = impl->GetCurrentHostThreadID(); 863 return impl->cores[CurrentPhysicalCoreIndex()];
850 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
851 return impl->cores[core_id];
852} 864}
853 865
854const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { 866const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const {
855 u32 core_id = impl->GetCurrentHostThreadID(); 867 return impl->cores[CurrentPhysicalCoreIndex()];
856 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
857 return impl->cores[core_id];
858} 868}
859 869
860Kernel::KScheduler* KernelCore::CurrentScheduler() { 870Kernel::KScheduler* KernelCore::CurrentScheduler() {
@@ -1057,6 +1067,9 @@ void KernelCore::Suspend(bool in_suspention) {
1057 impl->suspend_threads[core_id]->SetState(state); 1067 impl->suspend_threads[core_id]->SetState(state);
1058 impl->suspend_threads[core_id]->SetWaitReasonForDebugging( 1068 impl->suspend_threads[core_id]->SetWaitReasonForDebugging(
1059 ThreadWaitReasonForDebugging::Suspended); 1069 ThreadWaitReasonForDebugging::Suspended);
1070 if (!should_suspend) {
1071 impl->suspend_threads[core_id]->DisableDispatch();
1072 }
1060 } 1073 }
1061 } 1074 }
1062} 1075}
@@ -1065,19 +1078,21 @@ bool KernelCore::IsMulticore() const {
1065 return impl->is_multicore; 1078 return impl->is_multicore;
1066} 1079}
1067 1080
1081bool KernelCore::IsShuttingDown() const {
1082 return impl->IsShuttingDown();
1083}
1084
1068void KernelCore::ExceptionalExit() { 1085void KernelCore::ExceptionalExit() {
1069 exception_exited = true; 1086 exception_exited = true;
1070 Suspend(true); 1087 Suspend(true);
1071} 1088}
1072 1089
1073void KernelCore::EnterSVCProfile() { 1090void KernelCore::EnterSVCProfile() {
1074 std::size_t core = impl->GetCurrentHostThreadID(); 1091 impl->svc_ticks[CurrentPhysicalCoreIndex()] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC));
1075 impl->svc_ticks[core] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC));
1076} 1092}
1077 1093
1078void KernelCore::ExitSVCProfile() { 1094void KernelCore::ExitSVCProfile() {
1079 std::size_t core = impl->GetCurrentHostThreadID(); 1095 MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[CurrentPhysicalCoreIndex()]);
1080 MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]);
1081} 1096}
1082 1097
1083std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) { 1098std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index d2ceae950..b9b423908 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -53,6 +53,7 @@ class KSharedMemoryInfo;
53class KThread; 53class KThread;
54class KTransferMemory; 54class KTransferMemory;
55class KWritableEvent; 55class KWritableEvent;
56class KCodeMemory;
56class PhysicalCore; 57class PhysicalCore;
57class ServiceThread; 58class ServiceThread;
58class Synchronization; 59class Synchronization;
@@ -148,6 +149,9 @@ public:
148 /// Gets the an instance of the respective physical CPU core. 149 /// Gets the an instance of the respective physical CPU core.
149 const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; 150 const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const;
150 151
152 /// Gets the current physical core index for the running host thread.
153 std::size_t CurrentPhysicalCoreIndex() const;
154
151 /// Gets the sole instance of the Scheduler at the current running core. 155 /// Gets the sole instance of the Scheduler at the current running core.
152 Kernel::KScheduler* CurrentScheduler(); 156 Kernel::KScheduler* CurrentScheduler();
153 157
@@ -271,6 +275,8 @@ public:
271 275
272 bool IsMulticore() const; 276 bool IsMulticore() const;
273 277
278 bool IsShuttingDown() const;
279
274 void EnterSVCProfile(); 280 void EnterSVCProfile();
275 281
276 void ExitSVCProfile(); 282 void ExitSVCProfile();
@@ -326,6 +332,8 @@ public:
326 return slab_heap_container->transfer_memory; 332 return slab_heap_container->transfer_memory;
327 } else if constexpr (std::is_same_v<T, KWritableEvent>) { 333 } else if constexpr (std::is_same_v<T, KWritableEvent>) {
328 return slab_heap_container->writeable_event; 334 return slab_heap_container->writeable_event;
335 } else if constexpr (std::is_same_v<T, KCodeMemory>) {
336 return slab_heap_container->code_memory;
329 } 337 }
330 } 338 }
331 339
@@ -377,6 +385,7 @@ private:
377 KSlabHeap<KThread> thread; 385 KSlabHeap<KThread> thread;
378 KSlabHeap<KTransferMemory> transfer_memory; 386 KSlabHeap<KTransferMemory> transfer_memory;
379 KSlabHeap<KWritableEvent> writeable_event; 387 KSlabHeap<KWritableEvent> writeable_event;
388 KSlabHeap<KCodeMemory> code_memory;
380 }; 389 };
381 390
382 std::unique_ptr<SlabHeapContainer> slab_heap_container; 391 std::unique_ptr<SlabHeapContainer> slab_heap_container;
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp
index 6721b6276..03f3dec10 100644
--- a/src/core/hle/kernel/service_thread.cpp
+++ b/src/core/hle/kernel/service_thread.cpp
@@ -25,24 +25,27 @@ public:
25 void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context); 25 void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context);
26 26
27private: 27private:
28 std::vector<std::thread> threads; 28 std::vector<std::jthread> threads;
29 std::queue<std::function<void()>> requests; 29 std::queue<std::function<void()>> requests;
30 std::mutex queue_mutex; 30 std::mutex queue_mutex;
31 std::condition_variable condition; 31 std::condition_variable_any condition;
32 const std::string service_name; 32 const std::string service_name;
33 bool stop{};
34}; 33};
35 34
36ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name) 35ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name)
37 : service_name{name} { 36 : service_name{name} {
38 for (std::size_t i = 0; i < num_threads; ++i) 37 for (std::size_t i = 0; i < num_threads; ++i) {
39 threads.emplace_back([this, &kernel] { 38 threads.emplace_back([this, &kernel](std::stop_token stop_token) {
40 Common::SetCurrentThreadName(std::string{"yuzu:HleService:" + service_name}.c_str()); 39 Common::SetCurrentThreadName(std::string{"yuzu:HleService:" + service_name}.c_str());
41 40
42 // Wait for first request before trying to acquire a render context 41 // Wait for first request before trying to acquire a render context
43 { 42 {
44 std::unique_lock lock{queue_mutex}; 43 std::unique_lock lock{queue_mutex};
45 condition.wait(lock, [this] { return stop || !requests.empty(); }); 44 condition.wait(lock, stop_token, [this] { return !requests.empty(); });
45 }
46
47 if (stop_token.stop_requested()) {
48 return;
46 } 49 }
47 50
48 kernel.RegisterHostThread(); 51 kernel.RegisterHostThread();
@@ -52,10 +55,16 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std
52 55
53 { 56 {
54 std::unique_lock lock{queue_mutex}; 57 std::unique_lock lock{queue_mutex};
55 condition.wait(lock, [this] { return stop || !requests.empty(); }); 58 condition.wait(lock, stop_token, [this] { return !requests.empty(); });
56 if (stop || requests.empty()) { 59
60 if (stop_token.stop_requested()) {
57 return; 61 return;
58 } 62 }
63
64 if (requests.empty()) {
65 continue;
66 }
67
59 task = std::move(requests.front()); 68 task = std::move(requests.front());
60 requests.pop(); 69 requests.pop();
61 } 70 }
@@ -63,6 +72,7 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std
63 task(); 72 task();
64 } 73 }
65 }); 74 });
75 }
66} 76}
67 77
68void ServiceThread::Impl::QueueSyncRequest(KSession& session, 78void ServiceThread::Impl::QueueSyncRequest(KSession& session,
@@ -88,12 +98,9 @@ void ServiceThread::Impl::QueueSyncRequest(KSession& session,
88} 98}
89 99
90ServiceThread::Impl::~Impl() { 100ServiceThread::Impl::~Impl() {
91 {
92 std::unique_lock lock{queue_mutex};
93 stop = true;
94 }
95 condition.notify_all(); 101 condition.notify_all();
96 for (std::thread& thread : threads) { 102 for (auto& thread : threads) {
103 thread.request_stop();
97 thread.join(); 104 thread.join();
98 } 105 }
99} 106}
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index f0cd8471e..a9f7438ea 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -18,6 +18,7 @@
18#include "core/core_timing.h" 18#include "core/core_timing.h"
19#include "core/hle/kernel/k_client_port.h" 19#include "core/hle/kernel/k_client_port.h"
20#include "core/hle/kernel/k_client_session.h" 20#include "core/hle/kernel/k_client_session.h"
21#include "core/hle/kernel/k_code_memory.h"
21#include "core/hle/kernel/k_event.h" 22#include "core/hle/kernel/k_event.h"
22#include "core/hle/kernel/k_handle_table.h" 23#include "core/hle/kernel/k_handle_table.h"
23#include "core/hle/kernel/k_memory_block.h" 24#include "core/hle/kernel/k_memory_block.h"
@@ -31,6 +32,7 @@
31#include "core/hle/kernel/k_shared_memory.h" 32#include "core/hle/kernel/k_shared_memory.h"
32#include "core/hle/kernel/k_synchronization_object.h" 33#include "core/hle/kernel/k_synchronization_object.h"
33#include "core/hle/kernel/k_thread.h" 34#include "core/hle/kernel/k_thread.h"
35#include "core/hle/kernel/k_thread_queue.h"
34#include "core/hle/kernel/k_transfer_memory.h" 36#include "core/hle/kernel/k_transfer_memory.h"
35#include "core/hle/kernel/k_writable_event.h" 37#include "core/hle/kernel/k_writable_event.h"
36#include "core/hle/kernel/kernel.h" 38#include "core/hle/kernel/kernel.h"
@@ -307,26 +309,29 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle,
307 309
308/// Makes a blocking IPC call to an OS service. 310/// Makes a blocking IPC call to an OS service.
309static ResultCode SendSyncRequest(Core::System& system, Handle handle) { 311static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
310
311 auto& kernel = system.Kernel(); 312 auto& kernel = system.Kernel();
312 313
314 // Create the wait queue.
315 KThreadQueue wait_queue(kernel);
316
317 // Get the client session from its handle.
318 KScopedAutoObject session =
319 kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle);
320 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
321
322 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
323
313 auto thread = kernel.CurrentScheduler()->GetCurrentThread(); 324 auto thread = kernel.CurrentScheduler()->GetCurrentThread();
314 { 325 {
315 KScopedSchedulerLock lock(kernel); 326 KScopedSchedulerLock lock(kernel);
316 thread->SetState(ThreadState::Waiting); 327
317 thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); 328 // This is a synchronous request, so we should wait for our request to complete.
318 329 GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue));
319 { 330 GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
320 KScopedAutoObject session = 331 session->SendSyncRequest(&GetCurrentThread(kernel), system.Memory(), system.CoreTiming());
321 kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle);
322 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
323 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
324 session->SendSyncRequest(thread, system.Memory(), system.CoreTiming());
325 }
326 } 332 }
327 333
328 KSynchronizationObject* dummy{}; 334 return thread->GetWaitResult();
329 return thread->GetWaitResult(std::addressof(dummy));
330} 335}
331 336
332static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { 337static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
@@ -873,7 +878,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle
873 const u64 thread_ticks = current_thread->GetCpuTime(); 878 const u64 thread_ticks = current_thread->GetCpuTime();
874 879
875 out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); 880 out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks);
876 } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { 881 } else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) {
877 out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks; 882 out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks;
878 } 883 }
879 884
@@ -887,7 +892,8 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle
887 return ResultInvalidHandle; 892 return ResultInvalidHandle;
888 } 893 }
889 894
890 if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id != system.CurrentCoreIndex()) { 895 if (info_sub_id != 0xFFFFFFFFFFFFFFFF &&
896 info_sub_id != system.Kernel().CurrentPhysicalCoreIndex()) {
891 LOG_ERROR(Kernel_SVC, "Core is not the current core, got {}", info_sub_id); 897 LOG_ERROR(Kernel_SVC, "Core is not the current core, got {}", info_sub_id);
892 return ResultInvalidCombination; 898 return ResultInvalidCombination;
893 } 899 }
@@ -1197,6 +1203,22 @@ constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
1197 } 1203 }
1198} 1204}
1199 1205
1206constexpr bool IsValidMapCodeMemoryPermission(Svc::MemoryPermission perm) {
1207 return perm == Svc::MemoryPermission::ReadWrite;
1208}
1209
1210constexpr bool IsValidMapToOwnerCodeMemoryPermission(Svc::MemoryPermission perm) {
1211 return perm == Svc::MemoryPermission::Read || perm == Svc::MemoryPermission::ReadExecute;
1212}
1213
1214constexpr bool IsValidUnmapCodeMemoryPermission(Svc::MemoryPermission perm) {
1215 return perm == Svc::MemoryPermission::None;
1216}
1217
1218constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(Svc::MemoryPermission perm) {
1219 return perm == Svc::MemoryPermission::None;
1220}
1221
1200} // Anonymous namespace 1222} // Anonymous namespace
1201 1223
1202static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, 1224static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
@@ -1306,6 +1328,195 @@ static ResultCode SetProcessMemoryPermission(Core::System& system, Handle proces
1306 return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm)); 1328 return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm));
1307} 1329}
1308 1330
1331static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
1332 VAddr src_address, u64 size) {
1333 LOG_TRACE(Kernel_SVC,
1334 "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
1335 dst_address, process_handle, src_address, size);
1336
1337 // Validate the address/size.
1338 R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
1339 R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
1340 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1341 R_UNLESS(size > 0, ResultInvalidSize);
1342 R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
1343 R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
1344
1345 // Get the processes.
1346 KProcess* dst_process = system.CurrentProcess();
1347 KScopedAutoObject src_process =
1348 dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
1349 R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
1350
1351 // Get the page tables.
1352 auto& dst_pt = dst_process->PageTable();
1353 auto& src_pt = src_process->PageTable();
1354
1355 // Validate that the mapping is in range.
1356 R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
1357 R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
1358 ResultInvalidMemoryRegion);
1359
1360 // Create a new page group.
1361 KMemoryInfo kBlockInfo = dst_pt.QueryInfo(dst_address);
1362 KPageLinkedList pg(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages());
1363
1364 // Map the group.
1365 R_TRY(dst_pt.MapPages(dst_address, pg, KMemoryState::SharedCode,
1366 KMemoryPermission::UserReadWrite));
1367
1368 return ResultSuccess;
1369}
1370
1371static ResultCode UnmapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
1372 VAddr src_address, u64 size) {
1373 LOG_TRACE(Kernel_SVC,
1374 "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
1375 dst_address, process_handle, src_address, size);
1376
1377 // Validate the address/size.
1378 R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
1379 R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
1380 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1381 R_UNLESS(size > 0, ResultInvalidSize);
1382 R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
1383 R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
1384
1385 // Get the processes.
1386 KProcess* dst_process = system.CurrentProcess();
1387 KScopedAutoObject src_process =
1388 dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
1389 R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
1390
1391 // Get the page tables.
1392 auto& dst_pt = dst_process->PageTable();
1393 auto& src_pt = src_process->PageTable();
1394
1395 // Validate that the mapping is in range.
1396 R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
1397 R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
1398 ResultInvalidMemoryRegion);
1399
1400 // Unmap the memory.
1401 R_TRY(dst_pt.UnmapProcessMemory(dst_address, size, src_pt, src_address));
1402
1403 return ResultSuccess;
1404}
1405
1406static ResultCode CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) {
1407 LOG_TRACE(Kernel_SVC, "called, handle_out=0x{:X}, address=0x{:X}, size=0x{:X}",
1408 static_cast<void*>(out), address, size);
1409 // Get kernel instance.
1410 auto& kernel = system.Kernel();
1411
1412 // Validate address / size.
1413 R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
1414 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1415 R_UNLESS(size > 0, ResultInvalidSize);
1416 R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
1417
1418 // Create the code memory.
1419
1420 KCodeMemory* code_mem = KCodeMemory::Create(kernel);
1421 R_UNLESS(code_mem != nullptr, ResultOutOfResource);
1422
1423 // Verify that the region is in range.
1424 R_UNLESS(system.CurrentProcess()->PageTable().Contains(address, size),
1425 ResultInvalidCurrentMemory);
1426
1427 // Initialize the code memory.
1428 R_TRY(code_mem->Initialize(system.DeviceMemory(), address, size));
1429
1430 // Register the code memory.
1431 KCodeMemory::Register(kernel, code_mem);
1432
1433 // Add the code memory to the handle table.
1434 R_TRY(system.CurrentProcess()->GetHandleTable().Add(out, code_mem));
1435
1436 code_mem->Close();
1437
1438 return ResultSuccess;
1439}
1440
1441static ResultCode ControlCodeMemory(Core::System& system, Handle code_memory_handle, u32 operation,
1442 VAddr address, size_t size, Svc::MemoryPermission perm) {
1443
1444 LOG_TRACE(Kernel_SVC,
1445 "called, code_memory_handle=0x{:X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, "
1446 "permission=0x{:X}",
1447 code_memory_handle, operation, address, size, perm);
1448
1449 // Validate the address / size.
1450 R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
1451 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1452 R_UNLESS(size > 0, ResultInvalidSize);
1453 R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
1454
1455 // Get the code memory from its handle.
1456 KScopedAutoObject code_mem =
1457 system.CurrentProcess()->GetHandleTable().GetObject<KCodeMemory>(code_memory_handle);
1458 R_UNLESS(code_mem.IsNotNull(), ResultInvalidHandle);
1459
1460 // NOTE: Here, Atmosphere extends the SVC to allow code memory operations on one's own process.
1461 // This enables homebrew usage of these SVCs for JIT.
1462
1463 // Perform the operation.
1464 switch (static_cast<CodeMemoryOperation>(operation)) {
1465 case CodeMemoryOperation::Map: {
1466 // Check that the region is in range.
1467 R_UNLESS(
1468 system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut),
1469 ResultInvalidMemoryRegion);
1470
1471 // Check the memory permission.
1472 R_UNLESS(IsValidMapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
1473
1474 // Map the memory.
1475 R_TRY(code_mem->Map(address, size));
1476 } break;
1477 case CodeMemoryOperation::Unmap: {
1478 // Check that the region is in range.
1479 R_UNLESS(
1480 system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut),
1481 ResultInvalidMemoryRegion);
1482
1483 // Check the memory permission.
1484 R_UNLESS(IsValidUnmapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
1485
1486 // Unmap the memory.
1487 R_TRY(code_mem->Unmap(address, size));
1488 } break;
1489 case CodeMemoryOperation::MapToOwner: {
1490 // Check that the region is in range.
1491 R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
1492 KMemoryState::GeneratedCode),
1493 ResultInvalidMemoryRegion);
1494
1495 // Check the memory permission.
1496 R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
1497
1498 // Map the memory to its owner.
1499 R_TRY(code_mem->MapToOwner(address, size, perm));
1500 } break;
1501 case CodeMemoryOperation::UnmapFromOwner: {
1502 // Check that the region is in range.
1503 R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
1504 KMemoryState::GeneratedCode),
1505 ResultInvalidMemoryRegion);
1506
1507 // Check the memory permission.
1508 R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
1509
1510 // Unmap the memory from its owner.
1511 R_TRY(code_mem->UnmapFromOwner(address, size));
1512 } break;
1513 default:
1514 return ResultInvalidEnumValue;
1515 }
1516
1517 return ResultSuccess;
1518}
1519
1309static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, 1520static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
1310 VAddr page_info_address, Handle process_handle, 1521 VAddr page_info_address, Handle process_handle,
1311 VAddr address) { 1522 VAddr address) {
@@ -2600,8 +2811,8 @@ static const FunctionDef SVC_Table_64[] = {
2600 {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, 2811 {0x48, nullptr, "MapPhysicalMemoryUnsafe"},
2601 {0x49, nullptr, "UnmapPhysicalMemoryUnsafe"}, 2812 {0x49, nullptr, "UnmapPhysicalMemoryUnsafe"},
2602 {0x4A, nullptr, "SetUnsafeLimit"}, 2813 {0x4A, nullptr, "SetUnsafeLimit"},
2603 {0x4B, nullptr, "CreateCodeMemory"}, 2814 {0x4B, SvcWrap64<CreateCodeMemory>, "CreateCodeMemory"},
2604 {0x4C, nullptr, "ControlCodeMemory"}, 2815 {0x4C, SvcWrap64<ControlCodeMemory>, "ControlCodeMemory"},
2605 {0x4D, nullptr, "SleepSystem"}, 2816 {0x4D, nullptr, "SleepSystem"},
2606 {0x4E, nullptr, "ReadWriteRegister"}, 2817 {0x4E, nullptr, "ReadWriteRegister"},
2607 {0x4F, nullptr, "SetProcessActivity"}, 2818 {0x4F, nullptr, "SetProcessActivity"},
@@ -2641,8 +2852,8 @@ static const FunctionDef SVC_Table_64[] = {
2641 {0x71, nullptr, "ManageNamedPort"}, 2852 {0x71, nullptr, "ManageNamedPort"},
2642 {0x72, nullptr, "ConnectToPort"}, 2853 {0x72, nullptr, "ConnectToPort"},
2643 {0x73, SvcWrap64<SetProcessMemoryPermission>, "SetProcessMemoryPermission"}, 2854 {0x73, SvcWrap64<SetProcessMemoryPermission>, "SetProcessMemoryPermission"},
2644 {0x74, nullptr, "MapProcessMemory"}, 2855 {0x74, SvcWrap64<MapProcessMemory>, "MapProcessMemory"},
2645 {0x75, nullptr, "UnmapProcessMemory"}, 2856 {0x75, SvcWrap64<UnmapProcessMemory>, "UnmapProcessMemory"},
2646 {0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"}, 2857 {0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"},
2647 {0x77, SvcWrap64<MapProcessCodeMemory>, "MapProcessCodeMemory"}, 2858 {0x77, SvcWrap64<MapProcessCodeMemory>, "MapProcessCodeMemory"},
2648 {0x78, SvcWrap64<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"}, 2859 {0x78, SvcWrap64<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"},
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 6e62e656f..86255fe6d 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -73,6 +73,23 @@ void SvcWrap64(Core::System& system) {
73 .raw); 73 .raw);
74} 74}
75 75
76// Used by MapProcessMemory and UnmapProcessMemory
77template <ResultCode func(Core::System&, u64, u32, u64, u64)>
78void SvcWrap64(Core::System& system) {
79 FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)),
80 Param(system, 2), Param(system, 3))
81 .raw);
82}
83
84// Used by ControlCodeMemory
85template <ResultCode func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)>
86void SvcWrap64(Core::System& system) {
87 FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
88 static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3),
89 static_cast<Svc::MemoryPermission>(Param(system, 4)))
90 .raw);
91}
92
76template <ResultCode func(Core::System&, u32*)> 93template <ResultCode func(Core::System&, u32*)>
77void SvcWrap64(Core::System& system) { 94void SvcWrap64(Core::System& system) {
78 u32 param = 0; 95 u32 param = 0;
@@ -301,6 +318,16 @@ void SvcWrap64(Core::System& system) {
301 FuncReturn(system, retval); 318 FuncReturn(system, retval);
302} 319}
303 320
321// Used by CreateCodeMemory
322template <ResultCode func(Core::System&, Handle*, u64, u64)>
323void SvcWrap64(Core::System& system) {
324 u32 param_1 = 0;
325 const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2)).raw;
326
327 system.CurrentArmInterface().SetReg(1, param_1);
328 FuncReturn(system, retval);
329}
330
304template <ResultCode func(Core::System&, Handle*, u64, u32, u32)> 331template <ResultCode func(Core::System&, Handle*, u64, u32, u32)>
305void SvcWrap64(Core::System& system) { 332void SvcWrap64(Core::System& system) {
306 u32 param_1 = 0; 333 u32 param_1 = 0;
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index 8cd7279a3..aa985d820 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -5,6 +5,7 @@
5#include "common/assert.h" 5#include "common/assert.h"
6#include "core/core.h" 6#include "core/core.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/hle/kernel/k_scheduler.h"
8#include "core/hle/kernel/k_thread.h" 9#include "core/hle/kernel/k_thread.h"
9#include "core/hle/kernel/time_manager.h" 10#include "core/hle/kernel/time_manager.h"
10 11
@@ -15,7 +16,10 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} {
15 Core::Timing::CreateEvent("Kernel::TimeManagerCallback", 16 Core::Timing::CreateEvent("Kernel::TimeManagerCallback",
16 [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { 17 [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {
17 KThread* thread = reinterpret_cast<KThread*>(thread_handle); 18 KThread* thread = reinterpret_cast<KThread*>(thread_handle);
18 thread->Wakeup(); 19 {
20 KScopedSchedulerLock sl(system.Kernel());
21 thread->OnTimer();
22 }
19 }); 23 });
20} 24}
21 25
diff --git a/src/core/hle/service/glue/glue.cpp b/src/core/hle/service/glue/glue.cpp
index a08dc9758..b24d469cf 100644
--- a/src/core/hle/service/glue/glue.cpp
+++ b/src/core/hle/service/glue/glue.cpp
@@ -8,6 +8,7 @@
8#include "core/hle/service/glue/bgtc.h" 8#include "core/hle/service/glue/bgtc.h"
9#include "core/hle/service/glue/ectx.h" 9#include "core/hle/service/glue/ectx.h"
10#include "core/hle/service/glue/glue.h" 10#include "core/hle/service/glue/glue.h"
11#include "core/hle/service/glue/notif.h"
11 12
12namespace Service::Glue { 13namespace Service::Glue {
13 14
@@ -24,6 +25,9 @@ void InstallInterfaces(Core::System& system) {
24 25
25 // Error Context 26 // Error Context
26 std::make_shared<ECTX_AW>(system)->InstallAsService(system.ServiceManager()); 27 std::make_shared<ECTX_AW>(system)->InstallAsService(system.ServiceManager());
28
29 // Notification Services for application
30 std::make_shared<NOTIF_A>(system)->InstallAsService(system.ServiceManager());
27} 31}
28 32
29} // namespace Service::Glue 33} // namespace Service::Glue
diff --git a/src/core/hle/service/glue/notif.cpp b/src/core/hle/service/glue/notif.cpp
new file mode 100644
index 000000000..c559ec9df
--- /dev/null
+++ b/src/core/hle/service/glue/notif.cpp
@@ -0,0 +1,44 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/ipc_helpers.h"
6#include "core/hle/service/glue/notif.h"
7
8namespace Service::Glue {
9
10NOTIF_A::NOTIF_A(Core::System& system_) : ServiceFramework{system_, "notif:a"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {500, nullptr, "RegisterAlarmSetting"},
14 {510, nullptr, "UpdateAlarmSetting"},
15 {520, &NOTIF_A::ListAlarmSettings, "ListAlarmSettings"},
16 {530, nullptr, "LoadApplicationParameter"},
17 {540, nullptr, "DeleteAlarmSetting"},
18 {1000, &NOTIF_A::Initialize, "Initialize"},
19 };
20 // clang-format on
21
22 RegisterHandlers(functions);
23}
24
25NOTIF_A::~NOTIF_A() = default;
26
27void NOTIF_A::ListAlarmSettings(Kernel::HLERequestContext& ctx) {
28 // Returns an array of AlarmSetting
29 constexpr s32 alarm_count = 0;
30
31 LOG_WARNING(Service_NOTIF, "(STUBBED) called");
32
33 IPC::ResponseBuilder rb{ctx, 3};
34 rb.Push(ResultSuccess);
35 rb.Push(alarm_count);
36}
37
38void NOTIF_A::Initialize(Kernel::HLERequestContext& ctx) {
39 LOG_WARNING(Service_NOTIF, "(STUBBED) called");
40 IPC::ResponseBuilder rb{ctx, 2};
41 rb.Push(ResultSuccess);
42}
43
44} // namespace Service::Glue
diff --git a/src/core/hle/service/glue/notif.h b/src/core/hle/service/glue/notif.h
new file mode 100644
index 000000000..6ecf2015c
--- /dev/null
+++ b/src/core/hle/service/glue/notif.h
@@ -0,0 +1,25 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::Glue {
14
15class NOTIF_A final : public ServiceFramework<NOTIF_A> {
16public:
17 explicit NOTIF_A(Core::System& system_);
18 ~NOTIF_A() override;
19
20private:
21 void ListAlarmSettings(Kernel::HLERequestContext& ctx);
22 void Initialize(Kernel::HLERequestContext& ctx);
23};
24
25} // namespace Service::Glue
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index ae56f10cf..2705e9dcb 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -110,7 +110,7 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type,
110 UpdateControllerAt(npad_type, npad_id, is_connected); 110 UpdateControllerAt(npad_type, npad_id, is_connected);
111 break; 111 break;
112 case Core::HID::ControllerTriggerType::Battery: { 112 case Core::HID::ControllerTriggerType::Battery: {
113 if (!controller.is_connected) { 113 if (!controller.device->IsConnected()) {
114 return; 114 return;
115 } 115 }
116 auto& shared_memory = controller.shared_memory_entry; 116 auto& shared_memory = controller.shared_memory_entry;
@@ -150,7 +150,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
150 shared_memory.system_properties.is_vertical.Assign(1); 150 shared_memory.system_properties.is_vertical.Assign(1);
151 shared_memory.system_properties.use_plus.Assign(1); 151 shared_memory.system_properties.use_plus.Assign(1);
152 shared_memory.system_properties.use_minus.Assign(1); 152 shared_memory.system_properties.use_minus.Assign(1);
153 shared_memory.assignment_mode = NpadJoyAssignmentMode::Single;
154 shared_memory.applet_footer.type = AppletFooterUiType::SwitchProController; 153 shared_memory.applet_footer.type = AppletFooterUiType::SwitchProController;
155 break; 154 break;
156 case Core::HID::NpadStyleIndex::Handheld: 155 case Core::HID::NpadStyleIndex::Handheld:
@@ -166,21 +165,30 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
166 break; 165 break;
167 case Core::HID::NpadStyleIndex::JoyconDual: 166 case Core::HID::NpadStyleIndex::JoyconDual:
168 shared_memory.style_tag.joycon_dual.Assign(1); 167 shared_memory.style_tag.joycon_dual.Assign(1);
169 shared_memory.device_type.joycon_left.Assign(1); 168 if (controller.is_dual_left_connected) {
170 shared_memory.device_type.joycon_right.Assign(1); 169 shared_memory.device_type.joycon_left.Assign(1);
171 shared_memory.system_properties.is_vertical.Assign(1); 170 shared_memory.system_properties.use_minus.Assign(1);
172 shared_memory.system_properties.use_plus.Assign(1); 171 }
173 shared_memory.system_properties.use_minus.Assign(1); 172 if (controller.is_dual_right_connected) {
173 shared_memory.device_type.joycon_right.Assign(1);
174 shared_memory.system_properties.use_plus.Assign(1);
175 }
174 shared_memory.system_properties.use_directional_buttons.Assign(1); 176 shared_memory.system_properties.use_directional_buttons.Assign(1);
177 shared_memory.system_properties.is_vertical.Assign(1);
175 shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; 178 shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual;
176 shared_memory.applet_footer.type = AppletFooterUiType::JoyDual; 179 if (controller.is_dual_left_connected && controller.is_dual_right_connected) {
180 shared_memory.applet_footer.type = AppletFooterUiType::JoyDual;
181 } else if (controller.is_dual_left_connected) {
182 shared_memory.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly;
183 } else {
184 shared_memory.applet_footer.type = AppletFooterUiType::JoyDualRightOnly;
185 }
177 break; 186 break;
178 case Core::HID::NpadStyleIndex::JoyconLeft: 187 case Core::HID::NpadStyleIndex::JoyconLeft:
179 shared_memory.style_tag.joycon_left.Assign(1); 188 shared_memory.style_tag.joycon_left.Assign(1);
180 shared_memory.device_type.joycon_left.Assign(1); 189 shared_memory.device_type.joycon_left.Assign(1);
181 shared_memory.system_properties.is_horizontal.Assign(1); 190 shared_memory.system_properties.is_horizontal.Assign(1);
182 shared_memory.system_properties.use_minus.Assign(1); 191 shared_memory.system_properties.use_minus.Assign(1);
183 shared_memory.assignment_mode = NpadJoyAssignmentMode::Single;
184 shared_memory.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; 192 shared_memory.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal;
185 break; 193 break;
186 case Core::HID::NpadStyleIndex::JoyconRight: 194 case Core::HID::NpadStyleIndex::JoyconRight:
@@ -188,7 +196,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
188 shared_memory.device_type.joycon_right.Assign(1); 196 shared_memory.device_type.joycon_right.Assign(1);
189 shared_memory.system_properties.is_horizontal.Assign(1); 197 shared_memory.system_properties.is_horizontal.Assign(1);
190 shared_memory.system_properties.use_plus.Assign(1); 198 shared_memory.system_properties.use_plus.Assign(1);
191 shared_memory.assignment_mode = NpadJoyAssignmentMode::Single;
192 shared_memory.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; 199 shared_memory.applet_footer.type = AppletFooterUiType::JoyRightHorizontal;
193 break; 200 break;
194 case Core::HID::NpadStyleIndex::GameCube: 201 case Core::HID::NpadStyleIndex::GameCube:
@@ -200,7 +207,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
200 case Core::HID::NpadStyleIndex::Pokeball: 207 case Core::HID::NpadStyleIndex::Pokeball:
201 shared_memory.style_tag.palma.Assign(1); 208 shared_memory.style_tag.palma.Assign(1);
202 shared_memory.device_type.palma.Assign(1); 209 shared_memory.device_type.palma.Assign(1);
203 shared_memory.assignment_mode = NpadJoyAssignmentMode::Single;
204 break; 210 break;
205 case Core::HID::NpadStyleIndex::NES: 211 case Core::HID::NpadStyleIndex::NES:
206 shared_memory.style_tag.lark.Assign(1); 212 shared_memory.style_tag.lark.Assign(1);
@@ -443,11 +449,15 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
443 case Core::HID::NpadStyleIndex::JoyconDual: 449 case Core::HID::NpadStyleIndex::JoyconDual:
444 pad_state.connection_status.raw = 0; 450 pad_state.connection_status.raw = 0;
445 pad_state.connection_status.is_connected.Assign(1); 451 pad_state.connection_status.is_connected.Assign(1);
446 pad_state.connection_status.is_left_connected.Assign(1); 452 if (controller.is_dual_left_connected) {
447 pad_state.connection_status.is_right_connected.Assign(1); 453 pad_state.connection_status.is_left_connected.Assign(1);
454 libnx_state.connection_status.is_left_connected.Assign(1);
455 }
456 if (controller.is_dual_right_connected) {
457 pad_state.connection_status.is_right_connected.Assign(1);
458 libnx_state.connection_status.is_right_connected.Assign(1);
459 }
448 460
449 libnx_state.connection_status.is_left_connected.Assign(1);
450 libnx_state.connection_status.is_right_connected.Assign(1);
451 pad_state.sampling_number = 461 pad_state.sampling_number =
452 npad.joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; 462 npad.joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1;
453 npad.joy_dual_lifo.WriteNextEntry(pad_state); 463 npad.joy_dual_lifo.WriteNextEntry(pad_state);
@@ -687,7 +697,7 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode
687 return communication_mode; 697 return communication_mode;
688} 698}
689 699
690void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, 700void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type,
691 NpadJoyAssignmentMode assignment_mode) { 701 NpadJoyAssignmentMode assignment_mode) {
692 if (!IsNpadIdValid(npad_id)) { 702 if (!IsNpadIdValid(npad_id)) {
693 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); 703 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
@@ -698,6 +708,62 @@ void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id,
698 if (controller.shared_memory_entry.assignment_mode != assignment_mode) { 708 if (controller.shared_memory_entry.assignment_mode != assignment_mode) {
699 controller.shared_memory_entry.assignment_mode = assignment_mode; 709 controller.shared_memory_entry.assignment_mode = assignment_mode;
700 } 710 }
711
712 if (!controller.device->IsConnected()) {
713 return;
714 }
715
716 if (assignment_mode == NpadJoyAssignmentMode::Dual) {
717 if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft) {
718 DisconnectNpad(npad_id);
719 controller.is_dual_left_connected = true;
720 controller.is_dual_right_connected = false;
721 UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true);
722 return;
723 }
724 if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) {
725 DisconnectNpad(npad_id);
726 controller.is_dual_left_connected = false;
727 controller.is_dual_right_connected = true;
728 UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true);
729 return;
730 }
731 return;
732 }
733
734 // This is for NpadJoyAssignmentMode::Single
735
736 // Only JoyconDual get affected by this function
737 if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) {
738 return;
739 }
740
741 if (controller.is_dual_left_connected && !controller.is_dual_right_connected) {
742 DisconnectNpad(npad_id);
743 UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true);
744 return;
745 }
746 if (!controller.is_dual_left_connected && controller.is_dual_right_connected) {
747 DisconnectNpad(npad_id);
748 UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true);
749 return;
750 }
751
752 // We have two controllers connected to the same npad_id we need to split them
753 const auto npad_id_2 = hid_core.GetFirstDisconnectedNpadId();
754 auto& controller_2 = GetControllerFromNpadIdType(npad_id_2);
755 DisconnectNpad(npad_id);
756 if (npad_device_type == NpadJoyDeviceType::Left) {
757 UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true);
758 controller_2.is_dual_left_connected = false;
759 controller_2.is_dual_right_connected = true;
760 UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true);
761 } else {
762 UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true);
763 controller_2.is_dual_left_connected = true;
764 controller_2.is_dual_right_connected = false;
765 UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true);
766 }
701} 767}
702 768
703bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, 769bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
@@ -907,6 +973,7 @@ void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
907 } 973 }
908 974
909 auto& shared_memory_entry = controller.shared_memory_entry; 975 auto& shared_memory_entry = controller.shared_memory_entry;
976 // Don't reset shared_memory_entry.assignment_mode this value is persistent
910 shared_memory_entry.style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out 977 shared_memory_entry.style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out
911 shared_memory_entry.device_type.raw = 0; 978 shared_memory_entry.device_type.raw = 0;
912 shared_memory_entry.system_properties.raw = 0; 979 shared_memory_entry.system_properties.raw = 0;
@@ -923,9 +990,10 @@ void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
923 .left = {}, 990 .left = {},
924 .right = {}, 991 .right = {},
925 }; 992 };
926 shared_memory_entry.assignment_mode = NpadJoyAssignmentMode::Dual;
927 shared_memory_entry.applet_footer.type = AppletFooterUiType::None; 993 shared_memory_entry.applet_footer.type = AppletFooterUiType::None;
928 994
995 controller.is_dual_left_connected = true;
996 controller.is_dual_right_connected = true;
929 controller.is_connected = false; 997 controller.is_connected = false;
930 controller.device->Disconnect(); 998 controller.device->Disconnect();
931 SignalStyleSetChangedEvent(npad_id); 999 SignalStyleSetChangedEvent(npad_id);
@@ -1022,19 +1090,70 @@ void Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
1022 npad_id_2); 1090 npad_id_2);
1023 return; 1091 return;
1024 } 1092 }
1025 auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device; 1093 auto& controller_1 = GetControllerFromNpadIdType(npad_id_1);
1026 auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device; 1094 auto& controller_2 = GetControllerFromNpadIdType(npad_id_2);
1095 const auto controller_style_1 = controller_1.device->GetNpadStyleIndex();
1096 const auto controller_style_2 = controller_2.device->GetNpadStyleIndex();
1097 bool merge_controllers = false;
1027 1098
1028 // If the controllers at both npad indices form a pair of left and right joycons, merge them. 1099 // If the controllers at both npad indices form a pair of left and right joycons, merge them.
1029 // Otherwise, do nothing. 1100 // Otherwise, do nothing.
1030 if ((controller_1->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && 1101 if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft &&
1031 controller_2->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) || 1102 controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight) {
1032 (controller_2->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && 1103 merge_controllers = true;
1033 controller_1->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight)) { 1104 }
1105 if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft &&
1106 controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight) {
1107 merge_controllers = true;
1108 }
1109 if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
1110 controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight &&
1111 controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) {
1112 merge_controllers = true;
1113 }
1114 if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
1115 controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft &&
1116 !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) {
1117 merge_controllers = true;
1118 }
1119 if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
1120 controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight &&
1121 controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) {
1122 merge_controllers = true;
1123 }
1124 if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
1125 controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft &&
1126 !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) {
1127 merge_controllers = true;
1128 }
1129 if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
1130 controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
1131 controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected &&
1132 !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) {
1133 merge_controllers = true;
1134 }
1135 if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
1136 controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
1137 !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected &&
1138 controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) {
1139 merge_controllers = true;
1140 }
1141
1142 if (merge_controllers) {
1034 // Disconnect the joycon at the second id and connect the dual joycon at the first index. 1143 // Disconnect the joycon at the second id and connect the dual joycon at the first index.
1035 DisconnectNpad(npad_id_2); 1144 DisconnectNpad(npad_id_2);
1145 controller_1.is_dual_left_connected = true;
1146 controller_1.is_dual_right_connected = true;
1036 AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1); 1147 AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1);
1148 return;
1037 } 1149 }
1150 LOG_WARNING(Service_HID,
1151 "Controllers can't be merged npad_id_1:{}, npad_id_2:{}, type_1:{}, type_2:{}, "
1152 "dual_1(left/right):{}/{}, dual_2(left/right):{}/{}",
1153 npad_id_1, npad_id_2, controller_1.device->GetNpadStyleIndex(),
1154 controller_2.device->GetNpadStyleIndex(), controller_1.is_dual_left_connected,
1155 controller_1.is_dual_right_connected, controller_2.is_dual_left_connected,
1156 controller_2.is_dual_right_connected);
1038} 1157}
1039 1158
1040void Controller_NPad::StartLRAssignmentMode() { 1159void Controller_NPad::StartLRAssignmentMode() {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index de5fa5a64..63281cb35 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -113,7 +113,8 @@ public:
113 void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); 113 void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_);
114 NpadCommunicationMode GetNpadCommunicationMode() const; 114 NpadCommunicationMode GetNpadCommunicationMode() const;
115 115
116 void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyAssignmentMode assignment_mode); 116 void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type,
117 NpadJoyAssignmentMode assignment_mode);
117 118
118 bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, 119 bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index,
119 const Core::HID::VibrationValue& vibration_value); 120 const Core::HID::VibrationValue& vibration_value);
@@ -464,7 +465,10 @@ private:
464 std::array<VibrationData, 2> vibration{}; 465 std::array<VibrationData, 2> vibration{};
465 bool unintended_home_button_input_protection{}; 466 bool unintended_home_button_input_protection{};
466 bool is_connected{}; 467 bool is_connected{};
467 Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None}; 468
469 // Dual joycons can have only one side connected
470 bool is_dual_left_connected{true};
471 bool is_dual_right_connected{true};
468 472
469 // Motion parameters 473 // Motion parameters
470 bool sixaxis_at_rest{true}; 474 bool sixaxis_at_rest{true};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 14f737d39..7163e1a4e 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -975,35 +975,35 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx
975 const auto parameters{rp.PopRaw<Parameters>()}; 975 const auto parameters{rp.PopRaw<Parameters>()};
976 976
977 applet_resource->GetController<Controller_NPad>(HidController::NPad) 977 applet_resource->GetController<Controller_NPad>(HidController::NPad)
978 .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single); 978 .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left,
979 Controller_NPad::NpadJoyAssignmentMode::Single);
979 980
980 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", 981 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
981 parameters.npad_id, parameters.applet_resource_user_id); 982 parameters.applet_resource_user_id);
982 983
983 IPC::ResponseBuilder rb{ctx, 2}; 984 IPC::ResponseBuilder rb{ctx, 2};
984 rb.Push(ResultSuccess); 985 rb.Push(ResultSuccess);
985} 986}
986 987
987void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { 988void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
988 // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault
989 IPC::RequestParser rp{ctx}; 989 IPC::RequestParser rp{ctx};
990 struct Parameters { 990 struct Parameters {
991 Core::HID::NpadIdType npad_id; 991 Core::HID::NpadIdType npad_id;
992 INSERT_PADDING_WORDS_NOINIT(1); 992 INSERT_PADDING_WORDS_NOINIT(1);
993 u64 applet_resource_user_id; 993 u64 applet_resource_user_id;
994 u64 npad_joy_device_type; 994 Controller_NPad::NpadJoyDeviceType npad_joy_device_type;
995 }; 995 };
996 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); 996 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
997 997
998 const auto parameters{rp.PopRaw<Parameters>()}; 998 const auto parameters{rp.PopRaw<Parameters>()};
999 999
1000 applet_resource->GetController<Controller_NPad>(HidController::NPad) 1000 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1001 .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single); 1001 .SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type,
1002 Controller_NPad::NpadJoyAssignmentMode::Single);
1002 1003
1003 LOG_WARNING(Service_HID, 1004 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
1004 "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", 1005 parameters.npad_id, parameters.applet_resource_user_id,
1005 parameters.npad_id, parameters.applet_resource_user_id, 1006 parameters.npad_joy_device_type);
1006 parameters.npad_joy_device_type);
1007 1007
1008 IPC::ResponseBuilder rb{ctx, 2}; 1008 IPC::ResponseBuilder rb{ctx, 2};
1009 rb.Push(ResultSuccess); 1009 rb.Push(ResultSuccess);
@@ -1021,10 +1021,10 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
1021 const auto parameters{rp.PopRaw<Parameters>()}; 1021 const auto parameters{rp.PopRaw<Parameters>()};
1022 1022
1023 applet_resource->GetController<Controller_NPad>(HidController::NPad) 1023 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1024 .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Dual); 1024 .SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual);
1025 1025
1026 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", 1026 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1027 parameters.npad_id, parameters.applet_resource_user_id); 1027 parameters.applet_resource_user_id);
1028 1028
1029 IPC::ResponseBuilder rb{ctx, 2}; 1029 IPC::ResponseBuilder rb{ctx, 2};
1030 rb.Push(ResultSuccess); 1030 rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index 0d7d4ad03..8314d1ec2 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -20,8 +20,12 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>&
20 switch (command.group) { 20 switch (command.group) {
21 case 0x0: 21 case 0x0:
22 switch (command.cmd) { 22 switch (command.cmd) {
23 case 0x1: 23 case 0x1: {
24 return Submit(input, output); 24 if (!fd_to_id.contains(fd)) {
25 fd_to_id[fd] = next_id++;
26 }
27 return Submit(fd, input, output);
28 }
25 case 0x2: 29 case 0x2:
26 return GetSyncpoint(input, output); 30 return GetSyncpoint(input, output);
27 case 0x3: 31 case 0x3:
@@ -66,7 +70,10 @@ void nvhost_nvdec::OnOpen(DeviceFD fd) {}
66 70
67void nvhost_nvdec::OnClose(DeviceFD fd) { 71void nvhost_nvdec::OnClose(DeviceFD fd) {
68 LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); 72 LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
69 system.GPU().ClearCdmaInstance(); 73 const auto iter = fd_to_id.find(fd);
74 if (iter != fd_to_id.end()) {
75 system.GPU().ClearCdmaInstance(iter->second);
76 }
70} 77}
71 78
72} // namespace Service::Nvidia::Devices 79} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index 523d96e3a..a507c4d0a 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -24,6 +24,9 @@ public:
24 24
25 void OnOpen(DeviceFD fd) override; 25 void OnOpen(DeviceFD fd) override;
26 void OnClose(DeviceFD fd) override; 26 void OnClose(DeviceFD fd) override;
27
28private:
29 u32 next_id{};
27}; 30};
28 31
29} // namespace Service::Nvidia::Devices 32} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
index e61261f98..8a05f0668 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -59,7 +59,8 @@ NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
59 return NvResult::Success; 59 return NvResult::Success;
60} 60}
61 61
62NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) { 62NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector<u8>& input,
63 std::vector<u8>& output) {
63 IoctlSubmit params{}; 64 IoctlSubmit params{};
64 std::memcpy(&params, input.data(), sizeof(IoctlSubmit)); 65 std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
65 LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); 66 LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
@@ -93,7 +94,7 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u
93 Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); 94 Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
94 system.Memory().ReadBlock(object->addr + cmd_buffer.offset, cmdlist.data(), 95 system.Memory().ReadBlock(object->addr + cmd_buffer.offset, cmdlist.data(),
95 cmdlist.size() * sizeof(u32)); 96 cmdlist.size() * sizeof(u32));
96 gpu.PushCommandBuffer(cmdlist); 97 gpu.PushCommandBuffer(fd_to_id[fd], cmdlist);
97 } 98 }
98 std::memcpy(output.data(), &params, sizeof(IoctlSubmit)); 99 std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
99 // Some games expect command_buffers to be written back 100 // Some games expect command_buffers to be written back
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
index 351625c17..e28c54df6 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -104,13 +104,14 @@ protected:
104 104
105 /// Ioctl command implementations 105 /// Ioctl command implementations
106 NvResult SetNVMAPfd(const std::vector<u8>& input); 106 NvResult SetNVMAPfd(const std::vector<u8>& input);
107 NvResult Submit(const std::vector<u8>& input, std::vector<u8>& output); 107 NvResult Submit(DeviceFD fd, const std::vector<u8>& input, std::vector<u8>& output);
108 NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); 108 NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
109 NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); 109 NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
110 NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); 110 NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
111 NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); 111 NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
112 NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); 112 NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
113 113
114 std::unordered_map<DeviceFD, u32> fd_to_id{};
114 s32_le nvmap_fd{}; 115 s32_le nvmap_fd{};
115 u32_le submit_timeout{}; 116 u32_le submit_timeout{};
116 std::shared_ptr<nvmap> nvmap_dev; 117 std::shared_ptr<nvmap> nvmap_dev;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index eac4dd530..76b39806f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -21,7 +21,10 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& i
21 case 0x0: 21 case 0x0:
22 switch (command.cmd) { 22 switch (command.cmd) {
23 case 0x1: 23 case 0x1:
24 return Submit(input, output); 24 if (!fd_to_id.contains(fd)) {
25 fd_to_id[fd] = next_id++;
26 }
27 return Submit(fd, input, output);
25 case 0x2: 28 case 0x2:
26 return GetSyncpoint(input, output); 29 return GetSyncpoint(input, output);
27 case 0x3: 30 case 0x3:
@@ -65,7 +68,10 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& i
65void nvhost_vic::OnOpen(DeviceFD fd) {} 68void nvhost_vic::OnOpen(DeviceFD fd) {}
66 69
67void nvhost_vic::OnClose(DeviceFD fd) { 70void nvhost_vic::OnClose(DeviceFD fd) {
68 system.GPU().ClearCdmaInstance(); 71 const auto iter = fd_to_id.find(fd);
72 if (iter != fd_to_id.end()) {
73 system.GPU().ClearCdmaInstance(iter->second);
74 }
69} 75}
70 76
71} // namespace Service::Nvidia::Devices 77} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index 6d7fda9d1..c9732c037 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -23,5 +23,8 @@ public:
23 23
24 void OnOpen(DeviceFD fd) override; 24 void OnOpen(DeviceFD fd) override;
25 void OnClose(DeviceFD fd) override; 25 void OnClose(DeviceFD fd) override;
26
27private:
28 u32 next_id{};
26}; 29};
27} // namespace Service::Nvidia::Devices 30} // namespace Service::Nvidia::Devices
diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp
index 8b6574223..7ab4540a8 100644
--- a/src/input_common/drivers/gc_adapter.cpp
+++ b/src/input_common/drivers/gc_adapter.cpp
@@ -69,7 +69,7 @@ private:
69 libusb_device_handle* handle{}; 69 libusb_device_handle* handle{};
70}; 70};
71 71
72GCAdapter::GCAdapter(const std::string& input_engine_) : InputEngine(input_engine_) { 72GCAdapter::GCAdapter(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
73 if (usb_adapter_handle) { 73 if (usb_adapter_handle) {
74 return; 74 return;
75 } 75 }
@@ -325,8 +325,8 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) {
325 return true; 325 return true;
326} 326}
327 327
328Common::Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, 328Common::Input::VibrationError GCAdapter::SetRumble(
329 const Common::Input::VibrationStatus vibration) { 329 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
330 const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; 330 const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f;
331 const auto processed_amplitude = 331 const auto processed_amplitude =
332 static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); 332 static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8);
diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h
index 8dc51d2e5..7ce1912a3 100644
--- a/src/input_common/drivers/gc_adapter.h
+++ b/src/input_common/drivers/gc_adapter.h
@@ -22,13 +22,13 @@ namespace InputCommon {
22class LibUSBContext; 22class LibUSBContext;
23class LibUSBDeviceHandle; 23class LibUSBDeviceHandle;
24 24
25class GCAdapter : public InputCommon::InputEngine { 25class GCAdapter : public InputEngine {
26public: 26public:
27 explicit GCAdapter(const std::string& input_engine_); 27 explicit GCAdapter(std::string input_engine_);
28 ~GCAdapter(); 28 ~GCAdapter() override;
29 29
30 Common::Input::VibrationError SetRumble( 30 Common::Input::VibrationError SetRumble(
31 const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; 31 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
32 32
33 /// Used for automapping features 33 /// Used for automapping features
34 std::vector<Common::ParamPackage> GetInputDevices() const override; 34 std::vector<Common::ParamPackage> GetInputDevices() const override;
diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp
index 23b0c0ccf..4c1e5bbec 100644
--- a/src/input_common/drivers/keyboard.cpp
+++ b/src/input_common/drivers/keyboard.cpp
@@ -24,7 +24,7 @@ constexpr PadIdentifier keyboard_modifier_identifier = {
24 .pad = 1, 24 .pad = 1,
25}; 25};
26 26
27Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { 27Keyboard::Keyboard(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
28 // Keyboard is broken into 3 diferent sets: 28 // Keyboard is broken into 3 diferent sets:
29 // key: Unfiltered intended for controllers. 29 // key: Unfiltered intended for controllers.
30 // keyboard_key: Allows only Settings::NativeKeyboard::Keys intended for keyboard emulation. 30 // keyboard_key: Allows only Settings::NativeKeyboard::Keys intended for keyboard emulation.
diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h
index ad123b136..3856c882c 100644
--- a/src/input_common/drivers/keyboard.h
+++ b/src/input_common/drivers/keyboard.h
@@ -12,9 +12,9 @@ namespace InputCommon {
12 * A button device factory representing a keyboard. It receives keyboard events and forward them 12 * A button device factory representing a keyboard. It receives keyboard events and forward them
13 * to all button devices it created. 13 * to all button devices it created.
14 */ 14 */
15class Keyboard final : public InputCommon::InputEngine { 15class Keyboard final : public InputEngine {
16public: 16public:
17 explicit Keyboard(const std::string& input_engine_); 17 explicit Keyboard(std::string input_engine_);
18 18
19 /** 19 /**
20 * Sets the status of all buttons bound with the key to pressed 20 * Sets the status of all buttons bound with the key to pressed
diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp
index 752118e97..aa69216c8 100644
--- a/src/input_common/drivers/mouse.cpp
+++ b/src/input_common/drivers/mouse.cpp
@@ -24,7 +24,7 @@ constexpr PadIdentifier identifier = {
24 .pad = 0, 24 .pad = 0,
25}; 25};
26 26
27Mouse::Mouse(const std::string& input_engine_) : InputEngine(input_engine_) { 27Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
28 PreSetController(identifier); 28 PreSetController(identifier);
29 PreSetAxis(identifier, mouse_axis_x); 29 PreSetAxis(identifier, mouse_axis_x);
30 PreSetAxis(identifier, mouse_axis_y); 30 PreSetAxis(identifier, mouse_axis_y);
diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h
index 4a1fd2fd9..040446178 100644
--- a/src/input_common/drivers/mouse.h
+++ b/src/input_common/drivers/mouse.h
@@ -27,9 +27,9 @@ enum class MouseButton {
27 * A button device factory representing a keyboard. It receives keyboard events and forward them 27 * A button device factory representing a keyboard. It receives keyboard events and forward them
28 * to all button devices it created. 28 * to all button devices it created.
29 */ 29 */
30class Mouse final : public InputCommon::InputEngine { 30class Mouse final : public InputEngine {
31public: 31public:
32 explicit Mouse(const std::string& input_engine_); 32 explicit Mouse(std::string input_engine_);
33 33
34 /** 34 /**
35 * Signals that mouse has moved. 35 * Signals that mouse has moved.
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 1052ed394..0cda9df62 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -88,7 +88,7 @@ public:
88 return true; 88 return true;
89 } 89 }
90 90
91 BasicMotion GetMotion() { 91 const BasicMotion& GetMotion() const {
92 return motion; 92 return motion;
93 } 93 }
94 94
@@ -367,7 +367,7 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
367 if (joystick->UpdateMotion(event.csensor)) { 367 if (joystick->UpdateMotion(event.csensor)) {
368 const PadIdentifier identifier = joystick->GetPadIdentifier(); 368 const PadIdentifier identifier = joystick->GetPadIdentifier();
369 SetMotion(identifier, 0, joystick->GetMotion()); 369 SetMotion(identifier, 0, joystick->GetMotion());
370 }; 370 }
371 } 371 }
372 break; 372 break;
373 } 373 }
@@ -387,7 +387,7 @@ void SDLDriver::CloseJoysticks() {
387 joystick_map.clear(); 387 joystick_map.clear();
388} 388}
389 389
390SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engine_) { 390SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
391 if (!Settings::values.enable_raw_input) { 391 if (!Settings::values.enable_raw_input) {
392 // Disable raw input. When enabled this setting causes SDL to die when a web applet opens 392 // Disable raw input. When enabled this setting causes SDL to die when a web applet opens
393 SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); 393 SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
@@ -403,10 +403,11 @@ SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engin
403 403
404 // Use hidapi driver for joycons. This will allow joycons to be detected as a GameController and 404 // Use hidapi driver for joycons. This will allow joycons to be detected as a GameController and
405 // not a generic one 405 // not a generic one
406 SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1"); 406 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
407 407
408 // Turn off Pro controller home led 408 // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native
409 SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0"); 409 // driver on Linux.
410 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0");
410 411
411 // If the frontend is going to manage the event loop, then we don't start one here 412 // If the frontend is going to manage the event loop, then we don't start one here
412 start_thread = SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == 0; 413 start_thread = SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == 0;
@@ -491,8 +492,9 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
491 } 492 }
492 return devices; 493 return devices;
493} 494}
494Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, 495
495 const Common::Input::VibrationStatus vibration) { 496Common::Input::VibrationError SDLDriver::SetRumble(
497 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
496 const auto joystick = 498 const auto joystick =
497 GetSDLJoystickByGUID(identifier.guid.Format(), static_cast<int>(identifier.port)); 499 GetSDLJoystickByGUID(identifier.guid.Format(), static_cast<int>(identifier.port));
498 const auto process_amplitude_exp = [](f32 amplitude, f32 factor) { 500 const auto process_amplitude_exp = [](f32 amplitude, f32 factor) {
@@ -526,6 +528,7 @@ Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifi
526 528
527 return Common::Input::VibrationError::None; 529 return Common::Input::VibrationError::None;
528} 530}
531
529Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, 532Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid,
530 s32 axis, float value) const { 533 s32 axis, float value) const {
531 Common::ParamPackage params{}; 534 Common::ParamPackage params{};
diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h
index d03ff4b84..e9a5d2e26 100644
--- a/src/input_common/drivers/sdl_driver.h
+++ b/src/input_common/drivers/sdl_driver.h
@@ -19,19 +19,19 @@ using SDL_GameController = struct _SDL_GameController;
19using SDL_Joystick = struct _SDL_Joystick; 19using SDL_Joystick = struct _SDL_Joystick;
20using SDL_JoystickID = s32; 20using SDL_JoystickID = s32;
21 21
22namespace InputCommon {
23
24class SDLJoystick;
25
22using ButtonBindings = 26using ButtonBindings =
23 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>; 27 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
24using ZButtonBindings = 28using ZButtonBindings =
25 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>; 29 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
26 30
27namespace InputCommon { 31class SDLDriver : public InputEngine {
28
29class SDLJoystick;
30
31class SDLDriver : public InputCommon::InputEngine {
32public: 32public:
33 /// Initializes and registers SDL device factories 33 /// Initializes and registers SDL device factories
34 SDLDriver(const std::string& input_engine_); 34 explicit SDLDriver(std::string input_engine_);
35 35
36 /// Unregisters SDL device factories and shut them down. 36 /// Unregisters SDL device factories and shut them down.
37 ~SDLDriver() override; 37 ~SDLDriver() override;
@@ -59,7 +59,7 @@ public:
59 u8 GetHatButtonId(const std::string& direction_name) const override; 59 u8 GetHatButtonId(const std::string& direction_name) const override;
60 60
61 Common::Input::VibrationError SetRumble( 61 Common::Input::VibrationError SetRumble(
62 const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; 62 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
63 63
64private: 64private:
65 void InitJoystick(int joystick_index); 65 void InitJoystick(int joystick_index);
diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp
index 0e01fb0d9..5bdd5dac3 100644
--- a/src/input_common/drivers/tas_input.cpp
+++ b/src/input_common/drivers/tas_input.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring> 5#include <cstring>
6#include <regex>
7#include <fmt/format.h> 6#include <fmt/format.h>
8 7
9#include "common/fs/file.h" 8#include "common/fs/file.h"
@@ -15,7 +14,7 @@
15 14
16namespace InputCommon::TasInput { 15namespace InputCommon::TasInput {
17 16
18enum TasAxes : u8 { 17enum class Tas::TasAxis : u8 {
19 StickX, 18 StickX,
20 StickY, 19 StickY,
21 SubstickX, 20 SubstickX,
@@ -47,7 +46,7 @@ constexpr std::array<std::pair<std::string_view, TasButton>, 20> text_to_tas_but
47 {"KEY_ZR", TasButton::TRIGGER_ZR}, 46 {"KEY_ZR", TasButton::TRIGGER_ZR},
48}; 47};
49 48
50Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engine_) { 49Tas::Tas(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
51 for (size_t player_index = 0; player_index < PLAYER_NUMBER; player_index++) { 50 for (size_t player_index = 0; player_index < PLAYER_NUMBER; player_index++) {
52 PadIdentifier identifier{ 51 PadIdentifier identifier{
53 .guid = Common::UUID{}, 52 .guid = Common::UUID{},
@@ -66,7 +65,7 @@ Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engi
66 65
67Tas::~Tas() { 66Tas::~Tas() {
68 Stop(); 67 Stop();
69}; 68}
70 69
71void Tas::LoadTasFiles() { 70void Tas::LoadTasFiles() {
72 script_length = 0; 71 script_length = 0;
@@ -79,43 +78,43 @@ void Tas::LoadTasFiles() {
79} 78}
80 79
81void Tas::LoadTasFile(size_t player_index, size_t file_index) { 80void Tas::LoadTasFile(size_t player_index, size_t file_index) {
82 if (!commands[player_index].empty()) { 81 commands[player_index].clear();
83 commands[player_index].clear(); 82
84 }
85 std::string file = Common::FS::ReadStringFromFile( 83 std::string file = Common::FS::ReadStringFromFile(
86 Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / 84 Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) /
87 fmt::format("script{}-{}.txt", file_index, player_index + 1), 85 fmt::format("script{}-{}.txt", file_index, player_index + 1),
88 Common::FS::FileType::BinaryFile); 86 Common::FS::FileType::BinaryFile);
89 std::stringstream command_line(file); 87 std::istringstream command_line(file);
90 std::string line; 88 std::string line;
91 int frame_no = 0; 89 int frame_no = 0;
92 while (std::getline(command_line, line, '\n')) { 90 while (std::getline(command_line, line, '\n')) {
93 if (line.empty()) { 91 if (line.empty()) {
94 continue; 92 continue;
95 } 93 }
96 std::smatch m;
97 94
98 std::stringstream linestream(line); 95 std::vector<std::string> seg_list;
99 std::string segment; 96 {
100 std::vector<std::string> seglist; 97 std::istringstream line_stream(line);
101 98 std::string segment;
102 while (std::getline(linestream, segment, ' ')) { 99 while (std::getline(line_stream, segment, ' ')) {
103 seglist.push_back(segment); 100 seg_list.push_back(std::move(segment));
101 }
104 } 102 }
105 103
106 if (seglist.size() < 4) { 104 if (seg_list.size() < 4) {
107 continue; 105 continue;
108 } 106 }
109 107
110 while (frame_no < std::stoi(seglist.at(0))) { 108 const auto num_frames = std::stoi(seg_list[0]);
111 commands[player_index].push_back({}); 109 while (frame_no < num_frames) {
110 commands[player_index].emplace_back();
112 frame_no++; 111 frame_no++;
113 } 112 }
114 113
115 TASCommand command = { 114 TASCommand command = {
116 .buttons = ReadCommandButtons(seglist.at(1)), 115 .buttons = ReadCommandButtons(seg_list[1]),
117 .l_axis = ReadCommandAxis(seglist.at(2)), 116 .l_axis = ReadCommandAxis(seg_list[2]),
118 .r_axis = ReadCommandAxis(seglist.at(3)), 117 .r_axis = ReadCommandAxis(seg_list[3]),
119 }; 118 };
120 commands[player_index].push_back(command); 119 commands[player_index].push_back(command);
121 frame_no++; 120 frame_no++;
@@ -123,16 +122,17 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) {
123 LOG_INFO(Input, "TAS file loaded! {} frames", frame_no); 122 LOG_INFO(Input, "TAS file loaded! {} frames", frame_no);
124} 123}
125 124
126void Tas::WriteTasFile(std::u8string file_name) { 125void Tas::WriteTasFile(std::u8string_view file_name) {
127 std::string output_text; 126 std::string output_text;
128 for (size_t frame = 0; frame < record_commands.size(); frame++) { 127 for (size_t frame = 0; frame < record_commands.size(); frame++) {
129 const TASCommand& line = record_commands[frame]; 128 const TASCommand& line = record_commands[frame];
130 output_text += fmt::format("{} {} {} {}\n", frame, WriteCommandButtons(line.buttons), 129 output_text += fmt::format("{} {} {} {}\n", frame, WriteCommandButtons(line.buttons),
131 WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis)); 130 WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis));
132 } 131 }
133 const auto bytes_written = Common::FS::WriteStringToFile( 132
134 Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name, 133 const auto tas_file_name = Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name;
135 Common::FS::FileType::TextFile, output_text); 134 const auto bytes_written =
135 Common::FS::WriteStringToFile(tas_file_name, Common::FS::FileType::TextFile, output_text);
136 if (bytes_written == output_text.size()) { 136 if (bytes_written == output_text.size()) {
137 LOG_INFO(Input, "TAS file written to file!"); 137 LOG_INFO(Input, "TAS file written to file!");
138 } else { 138 } else {
@@ -205,10 +205,10 @@ void Tas::UpdateThread() {
205 const int button = static_cast<int>(i); 205 const int button = static_cast<int>(i);
206 SetButton(identifier, button, button_status); 206 SetButton(identifier, button, button_status);
207 } 207 }
208 SetAxis(identifier, TasAxes::StickX, command.l_axis.x); 208 SetTasAxis(identifier, TasAxis::StickX, command.l_axis.x);
209 SetAxis(identifier, TasAxes::StickY, command.l_axis.y); 209 SetTasAxis(identifier, TasAxis::StickY, command.l_axis.y);
210 SetAxis(identifier, TasAxes::SubstickX, command.r_axis.x); 210 SetTasAxis(identifier, TasAxis::SubstickX, command.r_axis.x);
211 SetAxis(identifier, TasAxes::SubstickY, command.r_axis.y); 211 SetTasAxis(identifier, TasAxis::SubstickY, command.r_axis.y);
212 } 212 }
213 } else { 213 } else {
214 is_running = Settings::values.tas_loop.GetValue(); 214 is_running = Settings::values.tas_loop.GetValue();
@@ -224,27 +224,28 @@ void Tas::ClearInput() {
224} 224}
225 225
226TasAnalog Tas::ReadCommandAxis(const std::string& line) const { 226TasAnalog Tas::ReadCommandAxis(const std::string& line) const {
227 std::stringstream linestream(line); 227 std::vector<std::string> seg_list;
228 std::string segment; 228 {
229 std::vector<std::string> seglist; 229 std::istringstream line_stream(line);
230 230 std::string segment;
231 while (std::getline(linestream, segment, ';')) { 231 while (std::getline(line_stream, segment, ';')) {
232 seglist.push_back(segment); 232 seg_list.push_back(std::move(segment));
233 }
233 } 234 }
234 235
235 const float x = std::stof(seglist.at(0)) / 32767.0f; 236 const float x = std::stof(seg_list.at(0)) / 32767.0f;
236 const float y = std::stof(seglist.at(1)) / 32767.0f; 237 const float y = std::stof(seg_list.at(1)) / 32767.0f;
237 238
238 return {x, y}; 239 return {x, y};
239} 240}
240 241
241u64 Tas::ReadCommandButtons(const std::string& data) const { 242u64 Tas::ReadCommandButtons(const std::string& line) const {
242 std::stringstream button_text(data); 243 std::istringstream button_text(line);
243 std::string line; 244 std::string button_line;
244 u64 buttons = 0; 245 u64 buttons = 0;
245 while (std::getline(button_text, line, ';')) { 246 while (std::getline(button_text, button_line, ';')) {
246 for (auto [text, tas_button] : text_to_tas_button) { 247 for (const auto& [text, tas_button] : text_to_tas_button) {
247 if (text == line) { 248 if (text == button_line) {
248 buttons |= static_cast<u64>(tas_button); 249 buttons |= static_cast<u64>(tas_button);
249 break; 250 break;
250 } 251 }
@@ -254,8 +255,8 @@ u64 Tas::ReadCommandButtons(const std::string& data) const {
254} 255}
255 256
256std::string Tas::WriteCommandButtons(u64 buttons) const { 257std::string Tas::WriteCommandButtons(u64 buttons) const {
257 std::string returns = ""; 258 std::string returns;
258 for (auto [text_button, tas_button] : text_to_tas_button) { 259 for (const auto& [text_button, tas_button] : text_to_tas_button) {
259 if ((buttons & static_cast<u64>(tas_button)) != 0) { 260 if ((buttons & static_cast<u64>(tas_button)) != 0) {
260 returns += fmt::format("{};", text_button); 261 returns += fmt::format("{};", text_button);
261 } 262 }
@@ -267,6 +268,10 @@ std::string Tas::WriteCommandAxis(TasAnalog analog) const {
267 return fmt::format("{};{}", analog.x * 32767, analog.y * 32767); 268 return fmt::format("{};{}", analog.x * 32767, analog.y * 32767);
268} 269}
269 270
271void Tas::SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value) {
272 SetAxis(identifier, static_cast<int>(axis), value);
273}
274
270void Tas::StartStop() { 275void Tas::StartStop() {
271 if (!Settings::values.tas_enable) { 276 if (!Settings::values.tas_enable) {
272 return; 277 return;
diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h
index c95a130fc..4b4e6c417 100644
--- a/src/input_common/drivers/tas_input.h
+++ b/src/input_common/drivers/tas_input.h
@@ -5,11 +5,11 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <string>
9#include <vector>
8 10
9#include "common/common_types.h" 11#include "common/common_types.h"
10#include "common/settings_input.h"
11#include "input_common/input_engine.h" 12#include "input_common/input_engine.h"
12#include "input_common/main.h"
13 13
14/* 14/*
15To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below 15To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below
@@ -81,46 +81,46 @@ enum class TasState {
81 Stopped, 81 Stopped,
82}; 82};
83 83
84class Tas final : public InputCommon::InputEngine { 84class Tas final : public InputEngine {
85public: 85public:
86 explicit Tas(const std::string& input_engine_); 86 explicit Tas(std::string input_engine_);
87 ~Tas(); 87 ~Tas() override;
88 88
89 /** 89 /**
90 * Changes the input status that will be stored in each frame 90 * Changes the input status that will be stored in each frame
91 * @param buttons: bitfield with the status of the buttons 91 * @param buttons Bitfield with the status of the buttons
92 * @param left_axis: value of the left axis 92 * @param left_axis Value of the left axis
93 * @param right_axis: value of the right axis 93 * @param right_axis Value of the right axis
94 */ 94 */
95 void RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis); 95 void RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis);
96 96
97 // Main loop that records or executes input 97 // Main loop that records or executes input
98 void UpdateThread(); 98 void UpdateThread();
99 99
100 // Sets the flag to start or stop the TAS command excecution and swaps controllers profiles 100 // Sets the flag to start or stop the TAS command execution and swaps controllers profiles
101 void StartStop(); 101 void StartStop();
102 102
103 // Stop the TAS and reverts any controller profile 103 // Stop the TAS and reverts any controller profile
104 void Stop(); 104 void Stop();
105 105
106 // Sets the flag to reload the file and start from the begining in the next update 106 // Sets the flag to reload the file and start from the beginning in the next update
107 void Reset(); 107 void Reset();
108 108
109 /** 109 /**
110 * Sets the flag to enable or disable recording of inputs 110 * Sets the flag to enable or disable recording of inputs
111 * @return Returns true if the current recording status is enabled 111 * @returns true if the current recording status is enabled
112 */ 112 */
113 bool Record(); 113 bool Record();
114 114
115 /** 115 /**
116 * Saves contents of record_commands on a file 116 * Saves contents of record_commands on a file
117 * @param overwrite_file: Indicates if player 1 should be overwritten 117 * @param overwrite_file Indicates if player 1 should be overwritten
118 */ 118 */
119 void SaveRecording(bool overwrite_file); 119 void SaveRecording(bool overwrite_file);
120 120
121 /** 121 /**
122 * Returns the current status values of TAS playback/recording 122 * Returns the current status values of TAS playback/recording
123 * @return Tuple of 123 * @returns A Tuple of
124 * TasState indicating the current state out of Running ; 124 * TasState indicating the current state out of Running ;
125 * Current playback progress ; 125 * Current playback progress ;
126 * Total length of script file currently loaded or being recorded 126 * Total length of script file currently loaded or being recorded
@@ -128,6 +128,8 @@ public:
128 std::tuple<TasState, size_t, size_t> GetStatus() const; 128 std::tuple<TasState, size_t, size_t> GetStatus() const;
129 129
130private: 130private:
131 enum class TasAxis : u8;
132
131 struct TASCommand { 133 struct TASCommand {
132 u64 buttons{}; 134 u64 buttons{};
133 TasAnalog l_axis{}; 135 TasAnalog l_axis{};
@@ -137,29 +139,31 @@ private:
137 /// Loads TAS files from all players 139 /// Loads TAS files from all players
138 void LoadTasFiles(); 140 void LoadTasFiles();
139 141
140 /** Loads TAS file from the specified player 142 /**
141 * @param player_index: player number to save the script 143 * Loads TAS file from the specified player
142 * @param file_index: script number of the file 144 * @param player_index Player number to save the script
145 * @param file_index Script number of the file
143 */ 146 */
144 void LoadTasFile(size_t player_index, size_t file_index); 147 void LoadTasFile(size_t player_index, size_t file_index);
145 148
146 /** Writes a TAS file from the recorded commands 149 /**
147 * @param file_name: name of the file to be written 150 * Writes a TAS file from the recorded commands
151 * @param file_name Name of the file to be written
148 */ 152 */
149 void WriteTasFile(std::u8string file_name); 153 void WriteTasFile(std::u8string_view file_name);
150 154
151 /** 155 /**
152 * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 156 * Parses a string containing the axis values. X and Y have a range from -32767 to 32767
153 * @param line: string containing axis values with the following format "x;y" 157 * @param line String containing axis values with the following format "x;y"
154 * @return Returns a TAS analog object with axis values with range from -1.0 to 1.0 158 * @returns A TAS analog object with axis values with range from -1.0 to 1.0
155 */ 159 */
156 TasAnalog ReadCommandAxis(const std::string& line) const; 160 TasAnalog ReadCommandAxis(const std::string& line) const;
157 161
158 /** 162 /**
159 * Parses a string containing the button values. Each button is represented by it's text format 163 * Parses a string containing the button values. Each button is represented by it's text format
160 * specified in text_to_tas_button array 164 * specified in text_to_tas_button array
161 * @param line: string containing button name with the following format "a;b;c;d..." 165 * @param line string containing button name with the following format "a;b;c;d..."
162 * @return Returns a u64 with each bit representing the status of a button 166 * @returns A u64 with each bit representing the status of a button
163 */ 167 */
164 u64 ReadCommandButtons(const std::string& line) const; 168 u64 ReadCommandButtons(const std::string& line) const;
165 169
@@ -170,17 +174,20 @@ private:
170 174
171 /** 175 /**
172 * Converts an u64 containing the button status into the text equivalent 176 * Converts an u64 containing the button status into the text equivalent
173 * @param buttons: bitfield with the status of the buttons 177 * @param buttons Bitfield with the status of the buttons
174 * @return Returns a string with the name of the buttons to be written to the file 178 * @returns A string with the name of the buttons to be written to the file
175 */ 179 */
176 std::string WriteCommandButtons(u64 buttons) const; 180 std::string WriteCommandButtons(u64 buttons) const;
177 181
178 /** 182 /**
179 * Converts an TAS analog object containing the axis status into the text equivalent 183 * Converts an TAS analog object containing the axis status into the text equivalent
180 * @param data: value of the axis 184 * @param analog Value of the axis
181 * @return A string with the value of the axis to be written to the file 185 * @returns A string with the value of the axis to be written to the file
182 */ 186 */
183 std::string WriteCommandAxis(TasAnalog data) const; 187 std::string WriteCommandAxis(TasAnalog analog) const;
188
189 /// Sets an axis for a particular pad to the given value.
190 void SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value);
184 191
185 size_t script_length{0}; 192 size_t script_length{0};
186 bool is_recording{false}; 193 bool is_recording{false};
diff --git a/src/input_common/drivers/touch_screen.cpp b/src/input_common/drivers/touch_screen.cpp
index 45b3086f6..880781825 100644
--- a/src/input_common/drivers/touch_screen.cpp
+++ b/src/input_common/drivers/touch_screen.cpp
@@ -13,7 +13,7 @@ constexpr PadIdentifier identifier = {
13 .pad = 0, 13 .pad = 0,
14}; 14};
15 15
16TouchScreen::TouchScreen(const std::string& input_engine_) : InputEngine(input_engine_) { 16TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
17 PreSetController(identifier); 17 PreSetController(identifier);
18} 18}
19 19
diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h
index 25c11e8bf..bf395c40b 100644
--- a/src/input_common/drivers/touch_screen.h
+++ b/src/input_common/drivers/touch_screen.h
@@ -12,9 +12,9 @@ namespace InputCommon {
12 * A button device factory representing a keyboard. It receives keyboard events and forward them 12 * A button device factory representing a keyboard. It receives keyboard events and forward them
13 * to all button devices it created. 13 * to all button devices it created.
14 */ 14 */
15class TouchScreen final : public InputCommon::InputEngine { 15class TouchScreen final : public InputEngine {
16public: 16public:
17 explicit TouchScreen(const std::string& input_engine_); 17 explicit TouchScreen(std::string input_engine_);
18 18
19 /** 19 /**
20 * Signals that mouse has moved. 20 * Signals that mouse has moved.
diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp
index fdee0f2d5..4ab991a7d 100644
--- a/src/input_common/drivers/udp_client.cpp
+++ b/src/input_common/drivers/udp_client.cpp
@@ -136,7 +136,7 @@ static void SocketLoop(Socket* socket) {
136 socket->Loop(); 136 socket->Loop();
137} 137}
138 138
139UDPClient::UDPClient(const std::string& input_engine_) : InputEngine(input_engine_) { 139UDPClient::UDPClient(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
140 LOG_INFO(Input, "Udp Initialization started"); 140 LOG_INFO(Input, "Udp Initialization started");
141 ReloadSockets(); 141 ReloadSockets();
142} 142}
diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h
index 5d483f26b..1adc947c4 100644
--- a/src/input_common/drivers/udp_client.h
+++ b/src/input_common/drivers/udp_client.h
@@ -49,10 +49,10 @@ struct DeviceStatus {
49 * A button device factory representing a keyboard. It receives keyboard events and forward them 49 * A button device factory representing a keyboard. It receives keyboard events and forward them
50 * to all button devices it created. 50 * to all button devices it created.
51 */ 51 */
52class UDPClient final : public InputCommon::InputEngine { 52class UDPClient final : public InputEngine {
53public: 53public:
54 explicit UDPClient(const std::string& input_engine_); 54 explicit UDPClient(std::string input_engine_);
55 ~UDPClient(); 55 ~UDPClient() override;
56 56
57 void ReloadSockets(); 57 void ReloadSockets();
58 58
diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp
index 77fcd655e..e23394f5f 100644
--- a/src/input_common/helpers/stick_from_buttons.cpp
+++ b/src/input_common/helpers/stick_from_buttons.cpp
@@ -19,23 +19,36 @@ public:
19 : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), 19 : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)),
20 right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), 20 right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_),
21 modifier_angle(modifier_angle_) { 21 modifier_angle(modifier_angle_) {
22 Common::Input::InputCallback button_up_callback{ 22 up->SetCallback({
23 [this](Common::Input::CallbackStatus callback_) { UpdateUpButtonStatus(callback_); }}; 23 .on_change =
24 Common::Input::InputCallback button_down_callback{ 24 [this](const Common::Input::CallbackStatus& callback_) {
25 [this](Common::Input::CallbackStatus callback_) { UpdateDownButtonStatus(callback_); }}; 25 UpdateUpButtonStatus(callback_);
26 Common::Input::InputCallback button_left_callback{ 26 },
27 [this](Common::Input::CallbackStatus callback_) { UpdateLeftButtonStatus(callback_); }}; 27 });
28 Common::Input::InputCallback button_right_callback{ 28 down->SetCallback({
29 [this](Common::Input::CallbackStatus callback_) { 29 .on_change =
30 UpdateRightButtonStatus(callback_); 30 [this](const Common::Input::CallbackStatus& callback_) {
31 }}; 31 UpdateDownButtonStatus(callback_);
32 Common::Input::InputCallback button_modifier_callback{ 32 },
33 [this](Common::Input::CallbackStatus callback_) { UpdateModButtonStatus(callback_); }}; 33 });
34 up->SetCallback(button_up_callback); 34 left->SetCallback({
35 down->SetCallback(button_down_callback); 35 .on_change =
36 left->SetCallback(button_left_callback); 36 [this](const Common::Input::CallbackStatus& callback_) {
37 right->SetCallback(button_right_callback); 37 UpdateLeftButtonStatus(callback_);
38 modifier->SetCallback(button_modifier_callback); 38 },
39 });
40 right->SetCallback({
41 .on_change =
42 [this](const Common::Input::CallbackStatus& callback_) {
43 UpdateRightButtonStatus(callback_);
44 },
45 });
46 modifier->SetCallback({
47 .on_change =
48 [this](const Common::Input::CallbackStatus& callback_) {
49 UpdateModButtonStatus(callback_);
50 },
51 });
39 last_x_axis_value = 0.0f; 52 last_x_axis_value = 0.0f;
40 last_y_axis_value = 0.0f; 53 last_y_axis_value = 0.0f;
41 } 54 }
@@ -133,27 +146,27 @@ public:
133 } 146 }
134 } 147 }
135 148
136 void UpdateUpButtonStatus(Common::Input::CallbackStatus button_callback) { 149 void UpdateUpButtonStatus(const Common::Input::CallbackStatus& button_callback) {
137 up_status = button_callback.button_status.value; 150 up_status = button_callback.button_status.value;
138 UpdateStatus(); 151 UpdateStatus();
139 } 152 }
140 153
141 void UpdateDownButtonStatus(Common::Input::CallbackStatus button_callback) { 154 void UpdateDownButtonStatus(const Common::Input::CallbackStatus& button_callback) {
142 down_status = button_callback.button_status.value; 155 down_status = button_callback.button_status.value;
143 UpdateStatus(); 156 UpdateStatus();
144 } 157 }
145 158
146 void UpdateLeftButtonStatus(Common::Input::CallbackStatus button_callback) { 159 void UpdateLeftButtonStatus(const Common::Input::CallbackStatus& button_callback) {
147 left_status = button_callback.button_status.value; 160 left_status = button_callback.button_status.value;
148 UpdateStatus(); 161 UpdateStatus();
149 } 162 }
150 163
151 void UpdateRightButtonStatus(Common::Input::CallbackStatus button_callback) { 164 void UpdateRightButtonStatus(const Common::Input::CallbackStatus& button_callback) {
152 right_status = button_callback.button_status.value; 165 right_status = button_callback.button_status.value;
153 UpdateStatus(); 166 UpdateStatus();
154 } 167 }
155 168
156 void UpdateModButtonStatus(Common::Input::CallbackStatus button_callback) { 169 void UpdateModButtonStatus(const Common::Input::CallbackStatus& button_callback) {
157 modifier_status = button_callback.button_status.value; 170 modifier_status = button_callback.button_status.value;
158 UpdateStatus(); 171 UpdateStatus();
159 } 172 }
@@ -265,18 +278,18 @@ private:
265 Button left; 278 Button left;
266 Button right; 279 Button right;
267 Button modifier; 280 Button modifier;
268 float modifier_scale; 281 float modifier_scale{};
269 float modifier_angle; 282 float modifier_angle{};
270 float angle{}; 283 float angle{};
271 float goal_angle{}; 284 float goal_angle{};
272 float amplitude{}; 285 float amplitude{};
273 bool up_status; 286 bool up_status{};
274 bool down_status; 287 bool down_status{};
275 bool left_status; 288 bool left_status{};
276 bool right_status; 289 bool right_status{};
277 bool modifier_status; 290 bool modifier_status{};
278 float last_x_axis_value; 291 float last_x_axis_value{};
279 float last_y_axis_value; 292 float last_y_axis_value{};
280 const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; 293 const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false};
281 std::chrono::time_point<std::chrono::steady_clock> last_update; 294 std::chrono::time_point<std::chrono::steady_clock> last_update;
282}; 295};
diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp
index 35d60bc90..ece1e3b32 100644
--- a/src/input_common/helpers/touch_from_buttons.cpp
+++ b/src/input_common/helpers/touch_from_buttons.cpp
@@ -14,10 +14,13 @@ public:
14 using Button = std::unique_ptr<Common::Input::InputDevice>; 14 using Button = std::unique_ptr<Common::Input::InputDevice>;
15 TouchFromButtonDevice(Button button_, int touch_id_, float x_, float y_) 15 TouchFromButtonDevice(Button button_, int touch_id_, float x_, float y_)
16 : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { 16 : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) {
17 Common::Input::InputCallback button_up_callback{
18 [this](Common::Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }};
19 last_button_value = false; 17 last_button_value = false;
20 button->SetCallback(button_up_callback); 18 button->SetCallback({
19 .on_change =
20 [this](const Common::Input::CallbackStatus& callback_) {
21 UpdateButtonStatus(callback_);
22 },
23 });
21 button->ForceUpdate(); 24 button->ForceUpdate();
22 } 25 }
23 26
@@ -47,7 +50,7 @@ public:
47 return status; 50 return status;
48 } 51 }
49 52
50 void UpdateButtonStatus(Common::Input::CallbackStatus button_callback) { 53 void UpdateButtonStatus(const Common::Input::CallbackStatus& button_callback) {
51 const Common::Input::CallbackStatus status{ 54 const Common::Input::CallbackStatus status{
52 .type = Common::Input::InputType::Touch, 55 .type = Common::Input::InputType::Touch,
53 .touch_status = GetStatus(button_callback.button_status.value), 56 .touch_status = GetStatus(button_callback.button_status.value),
diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp
index 2b2105376..9c17ca4f7 100644
--- a/src/input_common/input_engine.cpp
+++ b/src/input_common/input_engine.cpp
@@ -10,41 +10,31 @@ namespace InputCommon {
10 10
11void InputEngine::PreSetController(const PadIdentifier& identifier) { 11void InputEngine::PreSetController(const PadIdentifier& identifier) {
12 std::lock_guard lock{mutex}; 12 std::lock_guard lock{mutex};
13 if (!controller_list.contains(identifier)) { 13 controller_list.try_emplace(identifier);
14 controller_list.insert_or_assign(identifier, ControllerData{});
15 }
16} 14}
17 15
18void InputEngine::PreSetButton(const PadIdentifier& identifier, int button) { 16void InputEngine::PreSetButton(const PadIdentifier& identifier, int button) {
19 std::lock_guard lock{mutex}; 17 std::lock_guard lock{mutex};
20 ControllerData& controller = controller_list.at(identifier); 18 ControllerData& controller = controller_list.at(identifier);
21 if (!controller.buttons.contains(button)) { 19 controller.buttons.try_emplace(button, false);
22 controller.buttons.insert_or_assign(button, false);
23 }
24} 20}
25 21
26void InputEngine::PreSetHatButton(const PadIdentifier& identifier, int button) { 22void InputEngine::PreSetHatButton(const PadIdentifier& identifier, int button) {
27 std::lock_guard lock{mutex}; 23 std::lock_guard lock{mutex};
28 ControllerData& controller = controller_list.at(identifier); 24 ControllerData& controller = controller_list.at(identifier);
29 if (!controller.hat_buttons.contains(button)) { 25 controller.hat_buttons.try_emplace(button, u8{0});
30 controller.hat_buttons.insert_or_assign(button, u8{0});
31 }
32} 26}
33 27
34void InputEngine::PreSetAxis(const PadIdentifier& identifier, int axis) { 28void InputEngine::PreSetAxis(const PadIdentifier& identifier, int axis) {
35 std::lock_guard lock{mutex}; 29 std::lock_guard lock{mutex};
36 ControllerData& controller = controller_list.at(identifier); 30 ControllerData& controller = controller_list.at(identifier);
37 if (!controller.axes.contains(axis)) { 31 controller.axes.try_emplace(axis, 0.0f);
38 controller.axes.insert_or_assign(axis, 0.0f);
39 }
40} 32}
41 33
42void InputEngine::PreSetMotion(const PadIdentifier& identifier, int motion) { 34void InputEngine::PreSetMotion(const PadIdentifier& identifier, int motion) {
43 std::lock_guard lock{mutex}; 35 std::lock_guard lock{mutex};
44 ControllerData& controller = controller_list.at(identifier); 36 ControllerData& controller = controller_list.at(identifier);
45 if (!controller.motions.contains(motion)) { 37 controller.motions.try_emplace(motion);
46 controller.motions.insert_or_assign(motion, BasicMotion{});
47 }
48} 38}
49 39
50void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool value) { 40void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool value) {
@@ -91,7 +81,7 @@ void InputEngine::SetBattery(const PadIdentifier& identifier, BatteryLevel value
91 TriggerOnBatteryChange(identifier, value); 81 TriggerOnBatteryChange(identifier, value);
92} 82}
93 83
94void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value) { 84void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value) {
95 { 85 {
96 std::lock_guard lock{mutex}; 86 std::lock_guard lock{mutex};
97 ControllerData& controller = controller_list.at(identifier); 87 ControllerData& controller = controller_list.at(identifier);
@@ -104,85 +94,93 @@ void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, BasicMo
104 94
105bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const { 95bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const {
106 std::lock_guard lock{mutex}; 96 std::lock_guard lock{mutex};
107 if (!controller_list.contains(identifier)) { 97 const auto controller_iter = controller_list.find(identifier);
98 if (controller_iter == controller_list.cend()) {
108 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), 99 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
109 identifier.pad, identifier.port); 100 identifier.pad, identifier.port);
110 return false; 101 return false;
111 } 102 }
112 ControllerData controller = controller_list.at(identifier); 103 const ControllerData& controller = controller_iter->second;
113 if (!controller.buttons.contains(button)) { 104 const auto button_iter = controller.buttons.find(button);
105 if (button_iter == controller.buttons.cend()) {
114 LOG_ERROR(Input, "Invalid button {}", button); 106 LOG_ERROR(Input, "Invalid button {}", button);
115 return false; 107 return false;
116 } 108 }
117 return controller.buttons.at(button); 109 return button_iter->second;
118} 110}
119 111
120bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const { 112bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const {
121 std::lock_guard lock{mutex}; 113 std::lock_guard lock{mutex};
122 if (!controller_list.contains(identifier)) { 114 const auto controller_iter = controller_list.find(identifier);
115 if (controller_iter == controller_list.cend()) {
123 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), 116 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
124 identifier.pad, identifier.port); 117 identifier.pad, identifier.port);
125 return false; 118 return false;
126 } 119 }
127 ControllerData controller = controller_list.at(identifier); 120 const ControllerData& controller = controller_iter->second;
128 if (!controller.hat_buttons.contains(button)) { 121 const auto hat_iter = controller.hat_buttons.find(button);
122 if (hat_iter == controller.hat_buttons.cend()) {
129 LOG_ERROR(Input, "Invalid hat button {}", button); 123 LOG_ERROR(Input, "Invalid hat button {}", button);
130 return false; 124 return false;
131 } 125 }
132 return (controller.hat_buttons.at(button) & direction) != 0; 126 return (hat_iter->second & direction) != 0;
133} 127}
134 128
135f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const { 129f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const {
136 std::lock_guard lock{mutex}; 130 std::lock_guard lock{mutex};
137 if (!controller_list.contains(identifier)) { 131 const auto controller_iter = controller_list.find(identifier);
132 if (controller_iter == controller_list.cend()) {
138 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), 133 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
139 identifier.pad, identifier.port); 134 identifier.pad, identifier.port);
140 return 0.0f; 135 return 0.0f;
141 } 136 }
142 ControllerData controller = controller_list.at(identifier); 137 const ControllerData& controller = controller_iter->second;
143 if (!controller.axes.contains(axis)) { 138 const auto axis_iter = controller.axes.find(axis);
139 if (axis_iter == controller.axes.cend()) {
144 LOG_ERROR(Input, "Invalid axis {}", axis); 140 LOG_ERROR(Input, "Invalid axis {}", axis);
145 return 0.0f; 141 return 0.0f;
146 } 142 }
147 return controller.axes.at(axis); 143 return axis_iter->second;
148} 144}
149 145
150BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const { 146BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const {
151 std::lock_guard lock{mutex}; 147 std::lock_guard lock{mutex};
152 if (!controller_list.contains(identifier)) { 148 const auto controller_iter = controller_list.find(identifier);
149 if (controller_iter == controller_list.cend()) {
153 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), 150 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
154 identifier.pad, identifier.port); 151 identifier.pad, identifier.port);
155 return BatteryLevel::Charging; 152 return BatteryLevel::Charging;
156 } 153 }
157 ControllerData controller = controller_list.at(identifier); 154 const ControllerData& controller = controller_iter->second;
158 return controller.battery; 155 return controller.battery;
159} 156}
160 157
161BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const { 158BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const {
162 std::lock_guard lock{mutex}; 159 std::lock_guard lock{mutex};
163 if (!controller_list.contains(identifier)) { 160 const auto controller_iter = controller_list.find(identifier);
161 if (controller_iter == controller_list.cend()) {
164 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(), 162 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
165 identifier.pad, identifier.port); 163 identifier.pad, identifier.port);
166 return {}; 164 return {};
167 } 165 }
168 ControllerData controller = controller_list.at(identifier); 166 const ControllerData& controller = controller_iter->second;
169 return controller.motions.at(motion); 167 return controller.motions.at(motion);
170} 168}
171 169
172void InputEngine::ResetButtonState() { 170void InputEngine::ResetButtonState() {
173 for (std::pair<PadIdentifier, ControllerData> controller : controller_list) { 171 for (const auto& controller : controller_list) {
174 for (std::pair<int, bool> button : controller.second.buttons) { 172 for (const auto& button : controller.second.buttons) {
175 SetButton(controller.first, button.first, false); 173 SetButton(controller.first, button.first, false);
176 } 174 }
177 for (std::pair<int, bool> button : controller.second.hat_buttons) { 175 for (const auto& button : controller.second.hat_buttons) {
178 SetHatButton(controller.first, button.first, false); 176 SetHatButton(controller.first, button.first, false);
179 } 177 }
180 } 178 }
181} 179}
182 180
183void InputEngine::ResetAnalogState() { 181void InputEngine::ResetAnalogState() {
184 for (std::pair<PadIdentifier, ControllerData> controller : controller_list) { 182 for (const auto& controller : controller_list) {
185 for (std::pair<int, float> axis : controller.second.axes) { 183 for (const auto& axis : controller.second.axes) {
186 SetAxis(controller.first, axis.first, 0.0); 184 SetAxis(controller.first, axis.first, 0.0);
187 } 185 }
188 } 186 }
@@ -190,7 +188,7 @@ void InputEngine::ResetAnalogState() {
190 188
191void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value) { 189void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value) {
192 std::lock_guard lock{mutex_callback}; 190 std::lock_guard lock{mutex_callback};
193 for (const std::pair<int, InputIdentifier> poller_pair : callback_list) { 191 for (const auto& poller_pair : callback_list) {
194 const InputIdentifier& poller = poller_pair.second; 192 const InputIdentifier& poller = poller_pair.second;
195 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Button, button)) { 193 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Button, button)) {
196 continue; 194 continue;
@@ -218,7 +216,7 @@ void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int but
218 216
219void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value) { 217void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value) {
220 std::lock_guard lock{mutex_callback}; 218 std::lock_guard lock{mutex_callback};
221 for (const std::pair<int, InputIdentifier> poller_pair : callback_list) { 219 for (const auto& poller_pair : callback_list) {
222 const InputIdentifier& poller = poller_pair.second; 220 const InputIdentifier& poller = poller_pair.second;
223 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::HatButton, button)) { 221 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::HatButton, button)) {
224 continue; 222 continue;
@@ -247,7 +245,7 @@ void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int
247 245
248void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value) { 246void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value) {
249 std::lock_guard lock{mutex_callback}; 247 std::lock_guard lock{mutex_callback};
250 for (const std::pair<int, InputIdentifier> poller_pair : callback_list) { 248 for (const auto& poller_pair : callback_list) {
251 const InputIdentifier& poller = poller_pair.second; 249 const InputIdentifier& poller = poller_pair.second;
252 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Analog, axis)) { 250 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Analog, axis)) {
253 continue; 251 continue;
@@ -274,7 +272,7 @@ void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis,
274void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier, 272void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,
275 [[maybe_unused]] BatteryLevel value) { 273 [[maybe_unused]] BatteryLevel value) {
276 std::lock_guard lock{mutex_callback}; 274 std::lock_guard lock{mutex_callback};
277 for (const std::pair<int, InputIdentifier> poller_pair : callback_list) { 275 for (const auto& poller_pair : callback_list) {
278 const InputIdentifier& poller = poller_pair.second; 276 const InputIdentifier& poller = poller_pair.second;
279 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Battery, 0)) { 277 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Battery, 0)) {
280 continue; 278 continue;
@@ -286,9 +284,9 @@ void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,
286} 284}
287 285
288void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion, 286void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion,
289 BasicMotion value) { 287 const BasicMotion& value) {
290 std::lock_guard lock{mutex_callback}; 288 std::lock_guard lock{mutex_callback};
291 for (const std::pair<int, InputIdentifier> poller_pair : callback_list) { 289 for (const auto& poller_pair : callback_list) {
292 const InputIdentifier& poller = poller_pair.second; 290 const InputIdentifier& poller = poller_pair.second;
293 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Motion, motion)) { 291 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Motion, motion)) {
294 continue; 292 continue;
@@ -342,7 +340,7 @@ const std::string& InputEngine::GetEngineName() const {
342 340
343int InputEngine::SetCallback(InputIdentifier input_identifier) { 341int InputEngine::SetCallback(InputIdentifier input_identifier) {
344 std::lock_guard lock{mutex_callback}; 342 std::lock_guard lock{mutex_callback};
345 callback_list.insert_or_assign(last_callback_key, input_identifier); 343 callback_list.insert_or_assign(last_callback_key, std::move(input_identifier));
346 return last_callback_key++; 344 return last_callback_key++;
347} 345}
348 346
diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h
index 02272b3f8..390581c94 100644
--- a/src/input_common/input_engine.h
+++ b/src/input_common/input_engine.h
@@ -23,15 +23,15 @@ struct PadIdentifier {
23 friend constexpr bool operator==(const PadIdentifier&, const PadIdentifier&) = default; 23 friend constexpr bool operator==(const PadIdentifier&, const PadIdentifier&) = default;
24}; 24};
25 25
26// Basic motion data containing data from the sensors and a timestamp in microsecons 26// Basic motion data containing data from the sensors and a timestamp in microseconds
27struct BasicMotion { 27struct BasicMotion {
28 float gyro_x; 28 float gyro_x{};
29 float gyro_y; 29 float gyro_y{};
30 float gyro_z; 30 float gyro_z{};
31 float accel_x; 31 float accel_x{};
32 float accel_y; 32 float accel_y{};
33 float accel_z; 33 float accel_z{};
34 u64 delta_timestamp; 34 u64 delta_timestamp{};
35}; 35};
36 36
37// Stages of a battery charge 37// Stages of a battery charge
@@ -102,9 +102,7 @@ struct InputIdentifier {
102 102
103class InputEngine { 103class InputEngine {
104public: 104public:
105 explicit InputEngine(const std::string& input_engine_) : input_engine(input_engine_) { 105 explicit InputEngine(std::string input_engine_) : input_engine{std::move(input_engine_)} {}
106 callback_list.clear();
107 }
108 106
109 virtual ~InputEngine() = default; 107 virtual ~InputEngine() = default;
110 108
@@ -116,14 +114,12 @@ public:
116 114
117 // Sets a led pattern for a controller 115 // Sets a led pattern for a controller
118 virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier, 116 virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier,
119 [[maybe_unused]] const Common::Input::LedStatus led_status) { 117 [[maybe_unused]] const Common::Input::LedStatus& led_status) {}
120 return;
121 }
122 118
123 // Sets rumble to a controller 119 // Sets rumble to a controller
124 virtual Common::Input::VibrationError SetRumble( 120 virtual Common::Input::VibrationError SetRumble(
125 [[maybe_unused]] const PadIdentifier& identifier, 121 [[maybe_unused]] const PadIdentifier& identifier,
126 [[maybe_unused]] const Common::Input::VibrationStatus vibration) { 122 [[maybe_unused]] const Common::Input::VibrationStatus& vibration) {
127 return Common::Input::VibrationError::NotSupported; 123 return Common::Input::VibrationError::NotSupported;
128 } 124 }
129 125
@@ -140,36 +136,36 @@ public:
140 /// Used for automapping features 136 /// Used for automapping features
141 virtual std::vector<Common::ParamPackage> GetInputDevices() const { 137 virtual std::vector<Common::ParamPackage> GetInputDevices() const {
142 return {}; 138 return {};
143 }; 139 }
144 140
145 /// Retrieves the button mappings for the given device 141 /// Retrieves the button mappings for the given device
146 virtual InputCommon::ButtonMapping GetButtonMappingForDevice( 142 virtual ButtonMapping GetButtonMappingForDevice(
147 [[maybe_unused]] const Common::ParamPackage& params) { 143 [[maybe_unused]] const Common::ParamPackage& params) {
148 return {}; 144 return {};
149 }; 145 }
150 146
151 /// Retrieves the analog mappings for the given device 147 /// Retrieves the analog mappings for the given device
152 virtual InputCommon::AnalogMapping GetAnalogMappingForDevice( 148 virtual AnalogMapping GetAnalogMappingForDevice(
153 [[maybe_unused]] const Common::ParamPackage& params) { 149 [[maybe_unused]] const Common::ParamPackage& params) {
154 return {}; 150 return {};
155 }; 151 }
156 152
157 /// Retrieves the motion mappings for the given device 153 /// Retrieves the motion mappings for the given device
158 virtual InputCommon::MotionMapping GetMotionMappingForDevice( 154 virtual MotionMapping GetMotionMappingForDevice(
159 [[maybe_unused]] const Common::ParamPackage& params) { 155 [[maybe_unused]] const Common::ParamPackage& params) {
160 return {}; 156 return {};
161 }; 157 }
162 158
163 /// Retrieves the name of the given input. 159 /// Retrieves the name of the given input.
164 virtual Common::Input::ButtonNames GetUIName( 160 virtual Common::Input::ButtonNames GetUIName(
165 [[maybe_unused]] const Common::ParamPackage& params) const { 161 [[maybe_unused]] const Common::ParamPackage& params) const {
166 return Common::Input::ButtonNames::Engine; 162 return Common::Input::ButtonNames::Engine;
167 }; 163 }
168 164
169 /// Retrieves the index number of the given hat button direction 165 /// Retrieves the index number of the given hat button direction
170 virtual u8 GetHatButtonId([[maybe_unused]] const std::string& direction_name) const { 166 virtual u8 GetHatButtonId([[maybe_unused]] const std::string& direction_name) const {
171 return 0; 167 return 0;
172 }; 168 }
173 169
174 void PreSetController(const PadIdentifier& identifier); 170 void PreSetController(const PadIdentifier& identifier);
175 void PreSetButton(const PadIdentifier& identifier, int button); 171 void PreSetButton(const PadIdentifier& identifier, int button);
@@ -194,7 +190,7 @@ protected:
194 void SetHatButton(const PadIdentifier& identifier, int button, u8 value); 190 void SetHatButton(const PadIdentifier& identifier, int button, u8 value);
195 void SetAxis(const PadIdentifier& identifier, int axis, f32 value); 191 void SetAxis(const PadIdentifier& identifier, int axis, f32 value);
196 void SetBattery(const PadIdentifier& identifier, BatteryLevel value); 192 void SetBattery(const PadIdentifier& identifier, BatteryLevel value);
197 void SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value); 193 void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value);
198 194
199 virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const { 195 virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const {
200 return "Unknown"; 196 return "Unknown";
@@ -206,14 +202,15 @@ private:
206 std::unordered_map<int, u8> hat_buttons; 202 std::unordered_map<int, u8> hat_buttons;
207 std::unordered_map<int, float> axes; 203 std::unordered_map<int, float> axes;
208 std::unordered_map<int, BasicMotion> motions; 204 std::unordered_map<int, BasicMotion> motions;
209 BatteryLevel battery; 205 BatteryLevel battery{};
210 }; 206 };
211 207
212 void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value); 208 void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value);
213 void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value); 209 void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value);
214 void TriggerOnAxisChange(const PadIdentifier& identifier, int button, f32 value); 210 void TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value);
215 void TriggerOnBatteryChange(const PadIdentifier& identifier, BatteryLevel value); 211 void TriggerOnBatteryChange(const PadIdentifier& identifier, BatteryLevel value);
216 void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, BasicMotion value); 212 void TriggerOnMotionChange(const PadIdentifier& identifier, int motion,
213 const BasicMotion& value);
217 214
218 bool IsInputIdentifierEqual(const InputIdentifier& input_identifier, 215 bool IsInputIdentifierEqual(const InputIdentifier& input_identifier,
219 const PadIdentifier& identifier, EngineInputType type, 216 const PadIdentifier& identifier, EngineInputType type,
diff --git a/src/input_common/input_mapping.h b/src/input_common/input_mapping.h
index 44eb8ad9a..93564b5f8 100644
--- a/src/input_common/input_mapping.h
+++ b/src/input_common/input_mapping.h
@@ -14,8 +14,8 @@ public:
14 MappingFactory(); 14 MappingFactory();
15 15
16 /** 16 /**
17 * Resets all varables to beggin the mapping process 17 * Resets all variables to begin the mapping process
18 * @param "type": type of input desired to be returned 18 * @param type type of input desired to be returned
19 */ 19 */
20 void BeginMapping(Polling::InputType type); 20 void BeginMapping(Polling::InputType type);
21 21
@@ -24,8 +24,8 @@ public:
24 24
25 /** 25 /**
26 * Registers mapping input data from the driver 26 * Registers mapping input data from the driver
27 * @param "data": An struct containing all the information needed to create a proper 27 * @param data A struct containing all the information needed to create a proper
28 * ParamPackage 28 * ParamPackage
29 */ 29 */
30 void RegisterInput(const MappingData& data); 30 void RegisterInput(const MappingData& data);
31 31
@@ -34,42 +34,42 @@ public:
34 34
35private: 35private:
36 /** 36 /**
37 * If provided data satisfies the requeriments it will push an element to the input_queue 37 * If provided data satisfies the requirements it will push an element to the input_queue
38 * Supported input: 38 * Supported input:
39 * - Button: Creates a basic button ParamPackage 39 * - Button: Creates a basic button ParamPackage
40 * - HatButton: Creates a basic hat button ParamPackage 40 * - HatButton: Creates a basic hat button ParamPackage
41 * - Analog: Creates a basic analog ParamPackage 41 * - Analog: Creates a basic analog ParamPackage
42 * @param "data": An struct containing all the information needed to create a proper 42 * @param data A struct containing all the information needed to create a proper
43 * ParamPackage 43 * ParamPackage
44 */ 44 */
45 void RegisterButton(const MappingData& data); 45 void RegisterButton(const MappingData& data);
46 46
47 /** 47 /**
48 * If provided data satisfies the requeriments it will push an element to the input_queue 48 * If provided data satisfies the requirements it will push an element to the input_queue
49 * Supported input: 49 * Supported input:
50 * - Button, HatButton: Pass the data to RegisterButton 50 * - Button, HatButton: Pass the data to RegisterButton
51 * - Analog: Stores the first axis and on the second axis creates a basic stick ParamPackage 51 * - Analog: Stores the first axis and on the second axis creates a basic stick ParamPackage
52 * @param "data": An struct containing all the information needed to create a proper 52 * @param data A struct containing all the information needed to create a proper
53 * ParamPackage 53 * ParamPackage
54 */ 54 */
55 void RegisterStick(const MappingData& data); 55 void RegisterStick(const MappingData& data);
56 56
57 /** 57 /**
58 * If provided data satisfies the requeriments it will push an element to the input_queue 58 * If provided data satisfies the requirements it will push an element to the input_queue
59 * Supported input: 59 * Supported input:
60 * - Button, HatButton: Pass the data to RegisterButton 60 * - Button, HatButton: Pass the data to RegisterButton
61 * - Analog: Stores the first two axis and on the third axis creates a basic Motion 61 * - Analog: Stores the first two axis and on the third axis creates a basic Motion
62 * ParamPackage 62 * ParamPackage
63 * - Motion: Creates a basic Motion ParamPackage 63 * - Motion: Creates a basic Motion ParamPackage
64 * @param "data": An struct containing all the information needed to create a proper 64 * @param data A struct containing all the information needed to create a proper
65 * ParamPackage 65 * ParamPackage
66 */ 66 */
67 void RegisterMotion(const MappingData& data); 67 void RegisterMotion(const MappingData& data);
68 68
69 /** 69 /**
70 * Returns true if driver can be mapped 70 * Returns true if driver can be mapped
71 * @param "data": An struct containing all the information needed to create a proper 71 * @param data A struct containing all the information needed to create a proper
72 * ParamPackage 72 * ParamPackage
73 */ 73 */
74 bool IsDriverValid(const MappingData& data) const; 74 bool IsDriverValid(const MappingData& data) const;
75 75
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp
index 7e4eafded..7b370335f 100644
--- a/src/input_common/input_poller.cpp
+++ b/src/input_common/input_poller.cpp
@@ -12,8 +12,7 @@ namespace InputCommon {
12 12
13class DummyInput final : public Common::Input::InputDevice { 13class DummyInput final : public Common::Input::InputDevice {
14public: 14public:
15 explicit DummyInput() {} 15 explicit DummyInput() = default;
16 ~DummyInput() {}
17}; 16};
18 17
19class InputFromButton final : public Common::Input::InputDevice { 18class InputFromButton final : public Common::Input::InputDevice {
@@ -33,7 +32,7 @@ public:
33 callback_key = input_engine->SetCallback(input_identifier); 32 callback_key = input_engine->SetCallback(input_identifier);
34 } 33 }
35 34
36 ~InputFromButton() { 35 ~InputFromButton() override {
37 input_engine->DeleteCallback(callback_key); 36 input_engine->DeleteCallback(callback_key);
38 } 37 }
39 38
@@ -45,7 +44,7 @@ public:
45 }; 44 };
46 } 45 }
47 46
48 void ForceUpdate() { 47 void ForceUpdate() override {
49 const Common::Input::CallbackStatus status{ 48 const Common::Input::CallbackStatus status{
50 .type = Common::Input::InputType::Button, 49 .type = Common::Input::InputType::Button,
51 .button_status = GetStatus(), 50 .button_status = GetStatus(),
@@ -94,7 +93,7 @@ public:
94 callback_key = input_engine->SetCallback(input_identifier); 93 callback_key = input_engine->SetCallback(input_identifier);
95 } 94 }
96 95
97 ~InputFromHatButton() { 96 ~InputFromHatButton() override {
98 input_engine->DeleteCallback(callback_key); 97 input_engine->DeleteCallback(callback_key);
99 } 98 }
100 99
@@ -106,7 +105,7 @@ public:
106 }; 105 };
107 } 106 }
108 107
109 void ForceUpdate() { 108 void ForceUpdate() override {
110 const Common::Input::CallbackStatus status{ 109 const Common::Input::CallbackStatus status{
111 .type = Common::Input::InputType::Button, 110 .type = Common::Input::InputType::Button,
112 .button_status = GetStatus(), 111 .button_status = GetStatus(),
@@ -167,7 +166,7 @@ public:
167 callback_key_y = input_engine->SetCallback(y_input_identifier); 166 callback_key_y = input_engine->SetCallback(y_input_identifier);
168 } 167 }
169 168
170 ~InputFromStick() { 169 ~InputFromStick() override {
171 input_engine->DeleteCallback(callback_key_x); 170 input_engine->DeleteCallback(callback_key_x);
172 input_engine->DeleteCallback(callback_key_y); 171 input_engine->DeleteCallback(callback_key_y);
173 } 172 }
@@ -190,7 +189,7 @@ public:
190 return status; 189 return status;
191 } 190 }
192 191
193 void ForceUpdate() { 192 void ForceUpdate() override {
194 const Common::Input::CallbackStatus status{ 193 const Common::Input::CallbackStatus status{
195 .type = Common::Input::InputType::Stick, 194 .type = Common::Input::InputType::Stick,
196 .stick_status = GetStatus(), 195 .stick_status = GetStatus(),
@@ -266,7 +265,7 @@ public:
266 callback_key_y = input_engine->SetCallback(y_input_identifier); 265 callback_key_y = input_engine->SetCallback(y_input_identifier);
267 } 266 }
268 267
269 ~InputFromTouch() { 268 ~InputFromTouch() override {
270 input_engine->DeleteCallback(callback_key_button); 269 input_engine->DeleteCallback(callback_key_button);
271 input_engine->DeleteCallback(callback_key_x); 270 input_engine->DeleteCallback(callback_key_x);
272 input_engine->DeleteCallback(callback_key_y); 271 input_engine->DeleteCallback(callback_key_y);
@@ -352,7 +351,7 @@ public:
352 axis_callback_key = input_engine->SetCallback(axis_input_identifier); 351 axis_callback_key = input_engine->SetCallback(axis_input_identifier);
353 } 352 }
354 353
355 ~InputFromTrigger() { 354 ~InputFromTrigger() override {
356 input_engine->DeleteCallback(callback_key_button); 355 input_engine->DeleteCallback(callback_key_button);
357 input_engine->DeleteCallback(axis_callback_key); 356 input_engine->DeleteCallback(axis_callback_key);
358 } 357 }
@@ -419,7 +418,7 @@ public:
419 callback_key = input_engine->SetCallback(input_identifier); 418 callback_key = input_engine->SetCallback(input_identifier);
420 } 419 }
421 420
422 ~InputFromAnalog() { 421 ~InputFromAnalog() override {
423 input_engine->DeleteCallback(callback_key); 422 input_engine->DeleteCallback(callback_key);
424 } 423 }
425 424
@@ -466,7 +465,7 @@ public:
466 callback_key = input_engine->SetCallback(input_identifier); 465 callback_key = input_engine->SetCallback(input_identifier);
467 } 466 }
468 467
469 ~InputFromBattery() { 468 ~InputFromBattery() override {
470 input_engine->DeleteCallback(callback_key); 469 input_engine->DeleteCallback(callback_key);
471 } 470 }
472 471
@@ -474,7 +473,7 @@ public:
474 return static_cast<Common::Input::BatteryLevel>(input_engine->GetBattery(identifier)); 473 return static_cast<Common::Input::BatteryLevel>(input_engine->GetBattery(identifier));
475 } 474 }
476 475
477 void ForceUpdate() { 476 void ForceUpdate() override {
478 const Common::Input::CallbackStatus status{ 477 const Common::Input::CallbackStatus status{
479 .type = Common::Input::InputType::Battery, 478 .type = Common::Input::InputType::Battery,
480 .battery_status = GetStatus(), 479 .battery_status = GetStatus(),
@@ -518,7 +517,7 @@ public:
518 callback_key = input_engine->SetCallback(input_identifier); 517 callback_key = input_engine->SetCallback(input_identifier);
519 } 518 }
520 519
521 ~InputFromMotion() { 520 ~InputFromMotion() override {
522 input_engine->DeleteCallback(callback_key); 521 input_engine->DeleteCallback(callback_key);
523 } 522 }
524 523
@@ -593,7 +592,7 @@ public:
593 callback_key_z = input_engine->SetCallback(z_input_identifier); 592 callback_key_z = input_engine->SetCallback(z_input_identifier);
594 } 593 }
595 594
596 ~InputFromAxisMotion() { 595 ~InputFromAxisMotion() override {
597 input_engine->DeleteCallback(callback_key_x); 596 input_engine->DeleteCallback(callback_key_x);
598 input_engine->DeleteCallback(callback_key_y); 597 input_engine->DeleteCallback(callback_key_y);
599 input_engine->DeleteCallback(callback_key_z); 598 input_engine->DeleteCallback(callback_key_z);
@@ -618,7 +617,7 @@ public:
618 return status; 617 return status;
619 } 618 }
620 619
621 void ForceUpdate() { 620 void ForceUpdate() override {
622 const Common::Input::CallbackStatus status{ 621 const Common::Input::CallbackStatus status{
623 .type = Common::Input::InputType::Motion, 622 .type = Common::Input::InputType::Motion,
624 .motion_status = GetStatus(), 623 .motion_status = GetStatus(),
@@ -668,16 +667,16 @@ public:
668 explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_) 667 explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_)
669 : identifier(identifier_), input_engine(input_engine_) {} 668 : identifier(identifier_), input_engine(input_engine_) {}
670 669
671 virtual void SetLED(Common::Input::LedStatus led_status) { 670 void SetLED(const Common::Input::LedStatus& led_status) override {
672 input_engine->SetLeds(identifier, led_status); 671 input_engine->SetLeds(identifier, led_status);
673 } 672 }
674 673
675 virtual Common::Input::VibrationError SetVibration( 674 Common::Input::VibrationError SetVibration(
676 Common::Input::VibrationStatus vibration_status) { 675 const Common::Input::VibrationStatus& vibration_status) override {
677 return input_engine->SetRumble(identifier, vibration_status); 676 return input_engine->SetRumble(identifier, vibration_status);
678 } 677 }
679 678
680 virtual Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) { 679 Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) override {
681 return input_engine->SetPollingMode(identifier, polling_mode); 680 return input_engine->SetPollingMode(identifier, polling_mode);
682 } 681 }
683 682
diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h
index 573f09fde..8a0977d58 100644
--- a/src/input_common/input_poller.h
+++ b/src/input_common/input_poller.h
@@ -13,9 +13,6 @@ class Factory;
13 13
14namespace InputCommon { 14namespace InputCommon {
15class InputEngine; 15class InputEngine;
16/**
17 * An Input factory. It receives input events and forward them to all input devices it created.
18 */
19 16
20class OutputFactory final : public Common::Input::Factory<Common::Input::OutputDevice> { 17class OutputFactory final : public Common::Input::Factory<Common::Input::OutputDevice> {
21public: 18public:
@@ -24,10 +21,10 @@ public:
24 /** 21 /**
25 * Creates an output device from the parameters given. 22 * Creates an output device from the parameters given.
26 * @param params contains parameters for creating the device: 23 * @param params contains parameters for creating the device:
27 * @param - "guid": text string for identifing controllers 24 * - "guid" text string for identifying controllers
28 * @param - "port": port of the connected device 25 * - "port": port of the connected device
29 * @param - "pad": slot of the connected controller 26 * - "pad": slot of the connected controller
30 * @return an unique ouput device with the parameters specified 27 * @returns a unique output device with the parameters specified
31 */ 28 */
32 std::unique_ptr<Common::Input::OutputDevice> Create( 29 std::unique_ptr<Common::Input::OutputDevice> Create(
33 const Common::ParamPackage& params) override; 30 const Common::ParamPackage& params) override;
@@ -36,6 +33,9 @@ private:
36 std::shared_ptr<InputEngine> input_engine; 33 std::shared_ptr<InputEngine> input_engine;
37}; 34};
38 35
36/**
37 * An Input factory. It receives input events and forward them to all input devices it created.
38 */
39class InputFactory final : public Common::Input::Factory<Common::Input::InputDevice> { 39class InputFactory final : public Common::Input::Factory<Common::Input::InputDevice> {
40public: 40public:
41 explicit InputFactory(std::shared_ptr<InputEngine> input_engine_); 41 explicit InputFactory(std::shared_ptr<InputEngine> input_engine_);
@@ -54,16 +54,16 @@ public:
54 * - battery: Contains "battery" 54 * - battery: Contains "battery"
55 * - output: Contains "output" 55 * - output: Contains "output"
56 * @param params contains parameters for creating the device: 56 * @param params contains parameters for creating the device:
57 * @param - "code": the code of the keyboard key to bind with the input 57 * - "code": the code of the keyboard key to bind with the input
58 * @param - "button": same as "code" but for controller buttons 58 * - "button": same as "code" but for controller buttons
59 * @param - "hat": similar as "button" but it's a group of hat buttons from SDL 59 * - "hat": similar as "button" but it's a group of hat buttons from SDL
60 * @param - "axis": the axis number of the axis to bind with the input 60 * - "axis": the axis number of the axis to bind with the input
61 * @param - "motion": the motion number of the motion to bind with the input 61 * - "motion": the motion number of the motion to bind with the input
62 * @param - "axis_x": same as axis but specifing horizontal direction 62 * - "axis_x": same as axis but specifying horizontal direction
63 * @param - "axis_y": same as axis but specifing vertical direction 63 * - "axis_y": same as axis but specifying vertical direction
64 * @param - "axis_z": same as axis but specifing forward direction 64 * - "axis_z": same as axis but specifying forward direction
65 * @param - "battery": Only used as a placeholder to set the input type 65 * - "battery": Only used as a placeholder to set the input type
66 * @return an unique input device with the parameters specified 66 * @returns a unique input device with the parameters specified
67 */ 67 */
68 std::unique_ptr<Common::Input::InputDevice> Create(const Common::ParamPackage& params) override; 68 std::unique_ptr<Common::Input::InputDevice> Create(const Common::ParamPackage& params) override;
69 69
@@ -71,14 +71,14 @@ private:
71 /** 71 /**
72 * Creates a button device from the parameters given. 72 * Creates a button device from the parameters given.
73 * @param params contains parameters for creating the device: 73 * @param params contains parameters for creating the device:
74 * @param - "code": the code of the keyboard key to bind with the input 74 * - "code": the code of the keyboard key to bind with the input
75 * @param - "button": same as "code" but for controller buttons 75 * - "button": same as "code" but for controller buttons
76 * @param - "toggle": press once to enable, press again to disable 76 * - "toggle": press once to enable, press again to disable
77 * @param - "inverted": inverts the output of the button 77 * - "inverted": inverts the output of the button
78 * @param - "guid": text string for identifing controllers 78 * - "guid": text string for identifying controllers
79 * @param - "port": port of the connected device 79 * - "port": port of the connected device
80 * @param - "pad": slot of the connected controller 80 * - "pad": slot of the connected controller
81 * @return an unique input device with the parameters specified 81 * @returns a unique input device with the parameters specified
82 */ 82 */
83 std::unique_ptr<Common::Input::InputDevice> CreateButtonDevice( 83 std::unique_ptr<Common::Input::InputDevice> CreateButtonDevice(
84 const Common::ParamPackage& params); 84 const Common::ParamPackage& params);
@@ -86,14 +86,14 @@ private:
86 /** 86 /**
87 * Creates a hat button device from the parameters given. 87 * Creates a hat button device from the parameters given.
88 * @param params contains parameters for creating the device: 88 * @param params contains parameters for creating the device:
89 * @param - "button": the controller hat id to bind with the input 89 * - "button": the controller hat id to bind with the input
90 * @param - "direction": the direction id to be detected 90 * - "direction": the direction id to be detected
91 * @param - "toggle": press once to enable, press again to disable 91 * - "toggle": press once to enable, press again to disable
92 * @param - "inverted": inverts the output of the button 92 * - "inverted": inverts the output of the button
93 * @param - "guid": text string for identifing controllers 93 * - "guid": text string for identifying controllers
94 * @param - "port": port of the connected device 94 * - "port": port of the connected device
95 * @param - "pad": slot of the connected controller 95 * - "pad": slot of the connected controller
96 * @return an unique input device with the parameters specified 96 * @returns a unique input device with the parameters specified
97 */ 97 */
98 std::unique_ptr<Common::Input::InputDevice> CreateHatButtonDevice( 98 std::unique_ptr<Common::Input::InputDevice> CreateHatButtonDevice(
99 const Common::ParamPackage& params); 99 const Common::ParamPackage& params);
@@ -101,19 +101,19 @@ private:
101 /** 101 /**
102 * Creates a stick device from the parameters given. 102 * Creates a stick device from the parameters given.
103 * @param params contains parameters for creating the device: 103 * @param params contains parameters for creating the device:
104 * @param - "axis_x": the controller horizontal axis id to bind with the input 104 * - "axis_x": the controller horizontal axis id to bind with the input
105 * @param - "axis_y": the controller vertical axis id to bind with the input 105 * - "axis_y": the controller vertical axis id to bind with the input
106 * @param - "deadzone": the mimimum required value to be detected 106 * - "deadzone": the minimum required value to be detected
107 * @param - "range": the maximum value required to reach 100% 107 * - "range": the maximum value required to reach 100%
108 * @param - "threshold": the mimimum required value to considered pressed 108 * - "threshold": the minimum required value to considered pressed
109 * @param - "offset_x": the amount of offset in the x axis 109 * - "offset_x": the amount of offset in the x axis
110 * @param - "offset_y": the amount of offset in the y axis 110 * - "offset_y": the amount of offset in the y axis
111 * @param - "invert_x": inverts the sign of the horizontal axis 111 * - "invert_x": inverts the sign of the horizontal axis
112 * @param - "invert_y": inverts the sign of the vertical axis 112 * - "invert_y": inverts the sign of the vertical axis
113 * @param - "guid": text string for identifing controllers 113 * - "guid": text string for identifying controllers
114 * @param - "port": port of the connected device 114 * - "port": port of the connected device
115 * @param - "pad": slot of the connected controller 115 * - "pad": slot of the connected controller
116 * @return an unique input device with the parameters specified 116 * @returns a unique input device with the parameters specified
117 */ 117 */
118 std::unique_ptr<Common::Input::InputDevice> CreateStickDevice( 118 std::unique_ptr<Common::Input::InputDevice> CreateStickDevice(
119 const Common::ParamPackage& params); 119 const Common::ParamPackage& params);
@@ -121,16 +121,16 @@ private:
121 /** 121 /**
122 * Creates an analog device from the parameters given. 122 * Creates an analog device from the parameters given.
123 * @param params contains parameters for creating the device: 123 * @param params contains parameters for creating the device:
124 * @param - "axis": the controller axis id to bind with the input 124 * - "axis": the controller axis id to bind with the input
125 * @param - "deadzone": the mimimum required value to be detected 125 * - "deadzone": the minimum required value to be detected
126 * @param - "range": the maximum value required to reach 100% 126 * - "range": the maximum value required to reach 100%
127 * @param - "threshold": the mimimum required value to considered pressed 127 * - "threshold": the minimum required value to considered pressed
128 * @param - "offset": the amount of offset in the axis 128 * - "offset": the amount of offset in the axis
129 * @param - "invert": inverts the sign of the axis 129 * - "invert": inverts the sign of the axis
130 * @param - "guid": text string for identifing controllers 130 * - "guid": text string for identifying controllers
131 * @param - "port": port of the connected device 131 * - "port": port of the connected device
132 * @param - "pad": slot of the connected controller 132 * - "pad": slot of the connected controller
133 * @return an unique input device with the parameters specified 133 * @returns a unique input device with the parameters specified
134 */ 134 */
135 std::unique_ptr<Common::Input::InputDevice> CreateAnalogDevice( 135 std::unique_ptr<Common::Input::InputDevice> CreateAnalogDevice(
136 const Common::ParamPackage& params); 136 const Common::ParamPackage& params);
@@ -138,20 +138,20 @@ private:
138 /** 138 /**
139 * Creates a trigger device from the parameters given. 139 * Creates a trigger device from the parameters given.
140 * @param params contains parameters for creating the device: 140 * @param params contains parameters for creating the device:
141 * @param - "button": the controller hat id to bind with the input 141 * - "button": the controller hat id to bind with the input
142 * @param - "direction": the direction id to be detected 142 * - "direction": the direction id to be detected
143 * @param - "toggle": press once to enable, press again to disable 143 * - "toggle": press once to enable, press again to disable
144 * @param - "inverted": inverts the output of the button 144 * - "inverted": inverts the output of the button
145 * @param - "axis": the controller axis id to bind with the input 145 * - "axis": the controller axis id to bind with the input
146 * @param - "deadzone": the mimimum required value to be detected 146 * - "deadzone": the minimum required value to be detected
147 * @param - "range": the maximum value required to reach 100% 147 * - "range": the maximum value required to reach 100%
148 * @param - "threshold": the mimimum required value to considered pressed 148 * - "threshold": the minimum required value to considered pressed
149 * @param - "offset": the amount of offset in the axis 149 * - "offset": the amount of offset in the axis
150 * @param - "invert": inverts the sign of the axis 150 * - "invert": inverts the sign of the axis
151 * @param - "guid": text string for identifing controllers 151 * - "guid": text string for identifying controllers
152 * @param - "port": port of the connected device 152 * - "port": port of the connected device
153 * @param - "pad": slot of the connected controller 153 * - "pad": slot of the connected controller
154 * @return an unique input device with the parameters specified 154 * @returns a unique input device with the parameters specified
155 */ 155 */
156 std::unique_ptr<Common::Input::InputDevice> CreateTriggerDevice( 156 std::unique_ptr<Common::Input::InputDevice> CreateTriggerDevice(
157 const Common::ParamPackage& params); 157 const Common::ParamPackage& params);
@@ -159,23 +159,23 @@ private:
159 /** 159 /**
160 * Creates a touch device from the parameters given. 160 * Creates a touch device from the parameters given.
161 * @param params contains parameters for creating the device: 161 * @param params contains parameters for creating the device:
162 * @param - "button": the controller hat id to bind with the input 162 * - "button": the controller hat id to bind with the input
163 * @param - "direction": the direction id to be detected 163 * - "direction": the direction id to be detected
164 * @param - "toggle": press once to enable, press again to disable 164 * - "toggle": press once to enable, press again to disable
165 * @param - "inverted": inverts the output of the button 165 * - "inverted": inverts the output of the button
166 * @param - "axis_x": the controller horizontal axis id to bind with the input 166 * - "axis_x": the controller horizontal axis id to bind with the input
167 * @param - "axis_y": the controller vertical axis id to bind with the input 167 * - "axis_y": the controller vertical axis id to bind with the input
168 * @param - "deadzone": the mimimum required value to be detected 168 * - "deadzone": the minimum required value to be detected
169 * @param - "range": the maximum value required to reach 100% 169 * - "range": the maximum value required to reach 100%
170 * @param - "threshold": the mimimum required value to considered pressed 170 * - "threshold": the minimum required value to considered pressed
171 * @param - "offset_x": the amount of offset in the x axis 171 * - "offset_x": the amount of offset in the x axis
172 * @param - "offset_y": the amount of offset in the y axis 172 * - "offset_y": the amount of offset in the y axis
173 * @param - "invert_x": inverts the sign of the horizontal axis 173 * - "invert_x": inverts the sign of the horizontal axis
174 * @param - "invert_y": inverts the sign of the vertical axis 174 * - "invert_y": inverts the sign of the vertical axis
175 * @param - "guid": text string for identifing controllers 175 * - "guid": text string for identifying controllers
176 * @param - "port": port of the connected device 176 * - "port": port of the connected device
177 * @param - "pad": slot of the connected controller 177 * - "pad": slot of the connected controller
178 * @return an unique input device with the parameters specified 178 * @returns a unique input device with the parameters specified
179 */ 179 */
180 std::unique_ptr<Common::Input::InputDevice> CreateTouchDevice( 180 std::unique_ptr<Common::Input::InputDevice> CreateTouchDevice(
181 const Common::ParamPackage& params); 181 const Common::ParamPackage& params);
@@ -183,10 +183,10 @@ private:
183 /** 183 /**
184 * Creates a battery device from the parameters given. 184 * Creates a battery device from the parameters given.
185 * @param params contains parameters for creating the device: 185 * @param params contains parameters for creating the device:
186 * @param - "guid": text string for identifing controllers 186 * - "guid": text string for identifying controllers
187 * @param - "port": port of the connected device 187 * - "port": port of the connected device
188 * @param - "pad": slot of the connected controller 188 * - "pad": slot of the connected controller
189 * @return an unique input device with the parameters specified 189 * @returns a unique input device with the parameters specified
190 */ 190 */
191 std::unique_ptr<Common::Input::InputDevice> CreateBatteryDevice( 191 std::unique_ptr<Common::Input::InputDevice> CreateBatteryDevice(
192 const Common::ParamPackage& params); 192 const Common::ParamPackage& params);
@@ -194,21 +194,21 @@ private:
194 /** 194 /**
195 * Creates a motion device from the parameters given. 195 * Creates a motion device from the parameters given.
196 * @param params contains parameters for creating the device: 196 * @param params contains parameters for creating the device:
197 * @param - "axis_x": the controller horizontal axis id to bind with the input 197 * - "axis_x": the controller horizontal axis id to bind with the input
198 * @param - "axis_y": the controller vertical axis id to bind with the input 198 * - "axis_y": the controller vertical axis id to bind with the input
199 * @param - "axis_z": the controller fordward axis id to bind with the input 199 * - "axis_z": the controller forward axis id to bind with the input
200 * @param - "deadzone": the mimimum required value to be detected 200 * - "deadzone": the minimum required value to be detected
201 * @param - "range": the maximum value required to reach 100% 201 * - "range": the maximum value required to reach 100%
202 * @param - "offset_x": the amount of offset in the x axis 202 * - "offset_x": the amount of offset in the x axis
203 * @param - "offset_y": the amount of offset in the y axis 203 * - "offset_y": the amount of offset in the y axis
204 * @param - "offset_z": the amount of offset in the z axis 204 * - "offset_z": the amount of offset in the z axis
205 * @param - "invert_x": inverts the sign of the horizontal axis 205 * - "invert_x": inverts the sign of the horizontal axis
206 * @param - "invert_y": inverts the sign of the vertical axis 206 * - "invert_y": inverts the sign of the vertical axis
207 * @param - "invert_z": inverts the sign of the fordward axis 207 * - "invert_z": inverts the sign of the forward axis
208 * @param - "guid": text string for identifing controllers 208 * - "guid": text string for identifying controllers
209 * @param - "port": port of the connected device 209 * - "port": port of the connected device
210 * @param - "pad": slot of the connected controller 210 * - "pad": slot of the connected controller
211 * @return an unique input device with the parameters specified 211 * @returns a unique input device with the parameters specified
212 */ 212 */
213 std::unique_ptr<Common::Input::InputDevice> CreateMotionDevice(Common::ParamPackage params); 213 std::unique_ptr<Common::Input::InputDevice> CreateMotionDevice(Common::ParamPackage params);
214 214
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt
index bc3df80c8..4c76ce1ea 100644
--- a/src/shader_recompiler/CMakeLists.txt
+++ b/src/shader_recompiler/CMakeLists.txt
@@ -1,7 +1,5 @@
1add_library(shader_recompiler STATIC 1add_library(shader_recompiler STATIC
2 backend/bindings.h 2 backend/bindings.h
3 backend/glasm/emit_context.cpp
4 backend/glasm/emit_context.h
5 backend/glasm/emit_glasm.cpp 3 backend/glasm/emit_glasm.cpp
6 backend/glasm/emit_glasm.h 4 backend/glasm/emit_glasm.h
7 backend/glasm/emit_glasm_barriers.cpp 5 backend/glasm/emit_glasm_barriers.cpp
@@ -22,10 +20,10 @@ add_library(shader_recompiler STATIC
22 backend/glasm/emit_glasm_special.cpp 20 backend/glasm/emit_glasm_special.cpp
23 backend/glasm/emit_glasm_undefined.cpp 21 backend/glasm/emit_glasm_undefined.cpp
24 backend/glasm/emit_glasm_warp.cpp 22 backend/glasm/emit_glasm_warp.cpp
23 backend/glasm/glasm_emit_context.cpp
24 backend/glasm/glasm_emit_context.h
25 backend/glasm/reg_alloc.cpp 25 backend/glasm/reg_alloc.cpp
26 backend/glasm/reg_alloc.h 26 backend/glasm/reg_alloc.h
27 backend/glsl/emit_context.cpp
28 backend/glsl/emit_context.h
29 backend/glsl/emit_glsl.cpp 27 backend/glsl/emit_glsl.cpp
30 backend/glsl/emit_glsl.h 28 backend/glsl/emit_glsl.h
31 backend/glsl/emit_glsl_atomic.cpp 29 backend/glsl/emit_glsl_atomic.cpp
@@ -47,10 +45,10 @@ add_library(shader_recompiler STATIC
47 backend/glsl/emit_glsl_special.cpp 45 backend/glsl/emit_glsl_special.cpp
48 backend/glsl/emit_glsl_undefined.cpp 46 backend/glsl/emit_glsl_undefined.cpp
49 backend/glsl/emit_glsl_warp.cpp 47 backend/glsl/emit_glsl_warp.cpp
48 backend/glsl/glsl_emit_context.cpp
49 backend/glsl/glsl_emit_context.h
50 backend/glsl/var_alloc.cpp 50 backend/glsl/var_alloc.cpp
51 backend/glsl/var_alloc.h 51 backend/glsl/var_alloc.h
52 backend/spirv/emit_context.cpp
53 backend/spirv/emit_context.h
54 backend/spirv/emit_spirv.cpp 52 backend/spirv/emit_spirv.cpp
55 backend/spirv/emit_spirv.h 53 backend/spirv/emit_spirv.h
56 backend/spirv/emit_spirv_atomic.cpp 54 backend/spirv/emit_spirv_atomic.cpp
@@ -72,6 +70,8 @@ add_library(shader_recompiler STATIC
72 backend/spirv/emit_spirv_special.cpp 70 backend/spirv/emit_spirv_special.cpp
73 backend/spirv/emit_spirv_undefined.cpp 71 backend/spirv/emit_spirv_undefined.cpp
74 backend/spirv/emit_spirv_warp.cpp 72 backend/spirv/emit_spirv_warp.cpp
73 backend/spirv/spirv_emit_context.cpp
74 backend/spirv/spirv_emit_context.h
75 environment.h 75 environment.h
76 exception.h 76 exception.h
77 frontend/ir/abstract_syntax_list.h 77 frontend/ir/abstract_syntax_list.h
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
index 004658546..42eff443f 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
@@ -9,9 +9,9 @@
9#include "common/div_ceil.h" 9#include "common/div_ceil.h"
10#include "common/settings.h" 10#include "common/settings.h"
11#include "shader_recompiler/backend/bindings.h" 11#include "shader_recompiler/backend/bindings.h"
12#include "shader_recompiler/backend/glasm/emit_context.h"
13#include "shader_recompiler/backend/glasm/emit_glasm.h" 12#include "shader_recompiler/backend/glasm/emit_glasm.h"
14#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 13#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
14#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
15#include "shader_recompiler/frontend/ir/ir_emitter.h" 15#include "shader_recompiler/frontend/ir/ir_emitter.h"
16#include "shader_recompiler/frontend/ir/program.h" 16#include "shader_recompiler/frontend/ir/program.h"
17#include "shader_recompiler/profile.h" 17#include "shader_recompiler/profile.h"
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_barriers.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_barriers.cpp
index e69de29bb..c0b97683e 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_barriers.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_barriers.cpp
@@ -0,0 +1,22 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
6#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
7
8namespace Shader::Backend::GLASM {
9
10void EmitBarrier(EmitContext& ctx) {
11 ctx.Add("BAR;");
12}
13
14void EmitWorkgroupMemoryBarrier(EmitContext& ctx) {
15 ctx.Add("MEMBAR.CTA;");
16}
17
18void EmitDeviceMemoryBarrier(EmitContext& ctx) {
19 ctx.Add("MEMBAR;");
20}
21
22} // namespace Shader::Backend::GLASM
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp
index 9201ccd39..3bfcbbe65 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp
@@ -2,8 +2,8 @@
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 "shader_recompiler/backend/glasm/emit_context.h"
6#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 5#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
6#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
7#include "shader_recompiler/frontend/ir/value.h" 7#include "shader_recompiler/frontend/ir/value.h"
8 8
9namespace Shader::Backend::GLASM { 9namespace Shader::Backend::GLASM {
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_composite.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_composite.cpp
index bff0b7c1c..babbe6654 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_composite.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_composite.cpp
@@ -2,8 +2,8 @@
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 "shader_recompiler/backend/glasm/emit_context.h"
6#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 5#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
6#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
7#include "shader_recompiler/frontend/ir/value.h" 7#include "shader_recompiler/frontend/ir/value.h"
8 8
9namespace Shader::Backend::GLASM { 9namespace Shader::Backend::GLASM {
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
index 02c9dc6d7..081b2c8e0 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glasm/emit_context.h"
8#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 7#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
8#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10#include "shader_recompiler/profile.h" 10#include "shader_recompiler/profile.h"
11#include "shader_recompiler/shader_info.h" 11#include "shader_recompiler/shader_info.h"
@@ -335,6 +335,35 @@ void EmitSetFragDepth(EmitContext& ctx, ScalarF32 value) {
335 ctx.Add("MOV.F result.depth.z,{};", value); 335 ctx.Add("MOV.F result.depth.z,{};", value);
336} 336}
337 337
338void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst) {
339 ctx.Add("MOV.S {},invocation.groupid;", inst);
340}
341
342void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst) {
343 ctx.Add("MOV.S {},invocation.localid;", inst);
344}
345
346void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) {
347 ctx.Add("MOV.S {}.x,primitive_invocation.x;", inst);
348}
349
350void EmitSampleId(EmitContext& ctx, IR::Inst& inst) {
351 ctx.Add("MOV.S {}.x,fragment.sampleid.x;", inst);
352}
353
354void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst) {
355 ctx.Add("MOV.S {}.x,fragment.helperthread.x;", inst);
356}
357
358void EmitYDirection(EmitContext& ctx, IR::Inst& inst) {
359 ctx.uses_y_direction = true;
360 ctx.Add("MOV.F {}.x,y_direction[0].w;", inst);
361}
362
363void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) {
364 ctx.Add("MOV.F {}.x,scaling[0].z;", inst);
365}
366
338void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, ScalarU32 word_offset) { 367void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, ScalarU32 word_offset) {
339 ctx.Add("MOV.U {},lmem[{}].x;", inst, word_offset); 368 ctx.Add("MOV.U {},lmem[{}].x;", inst, word_offset);
340} 369}
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_control_flow.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_control_flow.cpp
index e69de29bb..8a14fc8d9 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_control_flow.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_control_flow.cpp
@@ -0,0 +1,18 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
6#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
7
8namespace Shader::Backend::GLASM {
9
10void EmitJoin(EmitContext&) {
11 throw NotImplementedException("Join shouldn't be emitted");
12}
13
14void EmitDemoteToHelperInvocation(EmitContext& ctx) {
15 ctx.Add("KIL TR.x;");
16}
17
18} // namespace Shader::Backend::GLASM
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_convert.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_convert.cpp
index ccdf1cbc8..4cff70fe4 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_convert.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_convert.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glasm/emit_context.h"
8#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 7#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
8#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
9#include "shader_recompiler/frontend/ir/modifiers.h" 9#include "shader_recompiler/frontend/ir/modifiers.h"
10#include "shader_recompiler/frontend/ir/value.h" 10#include "shader_recompiler/frontend/ir/value.h"
11 11
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_floating_point.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_floating_point.cpp
index 4ed58619d..356640471 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_floating_point.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_floating_point.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glasm/emit_context.h"
8#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 7#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
8#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
9#include "shader_recompiler/frontend/ir/modifiers.h" 9#include "shader_recompiler/frontend/ir/modifiers.h"
10#include "shader_recompiler/frontend/ir/value.h" 10#include "shader_recompiler/frontend/ir/value.h"
11 11
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
index d325d31c7..237a5af3f 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
@@ -4,8 +4,8 @@
4 4
5#include <utility> 5#include <utility>
6 6
7#include "shader_recompiler/backend/glasm/emit_context.h"
8#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 7#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
8#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
9#include "shader_recompiler/frontend/ir/modifiers.h" 9#include "shader_recompiler/frontend/ir/modifiers.h"
10#include "shader_recompiler/frontend/ir/value.h" 10#include "shader_recompiler/frontend/ir/value.h"
11 11
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp
index 8aa494a4d..f698b8b9b 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp
@@ -2,8 +2,8 @@
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 "shader_recompiler/backend/glasm/emit_context.h"
6#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 5#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
6#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
7#include "shader_recompiler/frontend/ir/value.h" 7#include "shader_recompiler/frontend/ir/value.h"
8 8
9namespace Shader::Backend::GLASM { 9namespace Shader::Backend::GLASM {
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_logical.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_logical.cpp
index e69de29bb..eed7bfec2 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_logical.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_logical.cpp
@@ -0,0 +1,26 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
6#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
7
8namespace Shader::Backend::GLASM {
9
10void EmitLogicalOr(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
11 ctx.Add("OR.S {},{},{};", inst, a, b);
12}
13
14void EmitLogicalAnd(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
15 ctx.Add("AND.S {},{},{};", inst, a, b);
16}
17
18void EmitLogicalXor(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
19 ctx.Add("XOR.S {},{},{};", inst, a, b);
20}
21
22void EmitLogicalNot(EmitContext& ctx, IR::Inst& inst, ScalarS32 value) {
23 ctx.Add("SEQ.S {},{},0;", inst, value);
24}
25
26} // namespace Shader::Backend::GLASM
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp
index af9fac7c1..f135b67f5 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_memory.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glasm/emit_context.h"
8#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 7#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
8#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
9#include "shader_recompiler/frontend/ir/program.h" 9#include "shader_recompiler/frontend/ir/program.h"
10#include "shader_recompiler/frontend/ir/value.h" 10#include "shader_recompiler/frontend/ir/value.h"
11#include "shader_recompiler/runtime_info.h" 11#include "shader_recompiler/runtime_info.h"
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
index 681aeda8d..86287ee3f 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glasm/emit_context.h"
8#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 7#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
8#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
9#include "shader_recompiler/frontend/ir/program.h" 9#include "shader_recompiler/frontend/ir/program.h"
10#include "shader_recompiler/frontend/ir/value.h" 10#include "shader_recompiler/frontend/ir/value.h"
11 11
@@ -17,110 +17,6 @@ namespace Shader::Backend::GLASM {
17 17
18#define NotImplemented() throw NotImplementedException("GLASM instruction {}", __LINE__) 18#define NotImplemented() throw NotImplementedException("GLASM instruction {}", __LINE__)
19 19
20static void DefinePhi(EmitContext& ctx, IR::Inst& phi) {
21 switch (phi.Type()) {
22 case IR::Type::U1:
23 case IR::Type::U32:
24 case IR::Type::F32:
25 ctx.reg_alloc.Define(phi);
26 break;
27 case IR::Type::U64:
28 case IR::Type::F64:
29 ctx.reg_alloc.LongDefine(phi);
30 break;
31 default:
32 throw NotImplementedException("Phi node type {}", phi.Type());
33 }
34}
35
36void EmitPhi(EmitContext& ctx, IR::Inst& phi) {
37 const size_t num_args{phi.NumArgs()};
38 for (size_t i = 0; i < num_args; ++i) {
39 ctx.reg_alloc.Consume(phi.Arg(i));
40 }
41 if (!phi.Definition<Id>().is_valid) {
42 // The phi node wasn't forward defined
43 DefinePhi(ctx, phi);
44 }
45}
46
47void EmitVoid(EmitContext&) {}
48
49void EmitReference(EmitContext& ctx, const IR::Value& value) {
50 ctx.reg_alloc.Consume(value);
51}
52
53void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& value) {
54 IR::Inst& phi{RegAlloc::AliasInst(*phi_value.Inst())};
55 if (!phi.Definition<Id>().is_valid) {
56 // The phi node wasn't forward defined
57 DefinePhi(ctx, phi);
58 }
59 const Register phi_reg{ctx.reg_alloc.Consume(IR::Value{&phi})};
60 const Value eval_value{ctx.reg_alloc.Consume(value)};
61
62 if (phi_reg == eval_value) {
63 return;
64 }
65 switch (phi.Flags<IR::Type>()) {
66 case IR::Type::U1:
67 case IR::Type::U32:
68 case IR::Type::F32:
69 ctx.Add("MOV.S {}.x,{};", phi_reg, ScalarS32{eval_value});
70 break;
71 case IR::Type::U64:
72 case IR::Type::F64:
73 ctx.Add("MOV.U64 {}.x,{};", phi_reg, ScalarRegister{eval_value});
74 break;
75 default:
76 throw NotImplementedException("Phi node type {}", phi.Type());
77 }
78}
79
80void EmitJoin(EmitContext& ctx) {
81 NotImplemented();
82}
83
84void EmitDemoteToHelperInvocation(EmitContext& ctx) {
85 ctx.Add("KIL TR.x;");
86}
87
88void EmitBarrier(EmitContext& ctx) {
89 ctx.Add("BAR;");
90}
91
92void EmitWorkgroupMemoryBarrier(EmitContext& ctx) {
93 ctx.Add("MEMBAR.CTA;");
94}
95
96void EmitDeviceMemoryBarrier(EmitContext& ctx) {
97 ctx.Add("MEMBAR;");
98}
99
100void EmitPrologue(EmitContext& ctx) {
101 // TODO
102}
103
104void EmitEpilogue(EmitContext& ctx) {
105 // TODO
106}
107
108void EmitEmitVertex(EmitContext& ctx, ScalarS32 stream) {
109 if (stream.type == Type::U32 && stream.imm_u32 == 0) {
110 ctx.Add("EMIT;");
111 } else {
112 ctx.Add("EMITS {};", stream);
113 }
114}
115
116void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) {
117 if (!stream.IsImmediate()) {
118 LOG_WARNING(Shader_GLASM, "Stream is not immediate");
119 }
120 ctx.reg_alloc.Consume(stream);
121 ctx.Add("ENDPRIM;");
122}
123
124void EmitGetRegister(EmitContext& ctx) { 20void EmitGetRegister(EmitContext& ctx) {
125 NotImplemented(); 21 NotImplemented();
126} 22}
@@ -185,55 +81,6 @@ void EmitSetOFlag(EmitContext& ctx) {
185 NotImplemented(); 81 NotImplemented();
186} 82}
187 83
188void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst) {
189 ctx.Add("MOV.S {},invocation.groupid;", inst);
190}
191
192void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst) {
193 ctx.Add("MOV.S {},invocation.localid;", inst);
194}
195
196void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) {
197 ctx.Add("MOV.S {}.x,primitive_invocation.x;", inst);
198}
199
200void EmitSampleId(EmitContext& ctx, IR::Inst& inst) {
201 ctx.Add("MOV.S {}.x,fragment.sampleid.x;", inst);
202}
203
204void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst) {
205 ctx.Add("MOV.S {}.x,fragment.helperthread.x;", inst);
206}
207
208void EmitYDirection(EmitContext& ctx, IR::Inst& inst) {
209 ctx.uses_y_direction = true;
210 ctx.Add("MOV.F {}.x,y_direction[0].w;", inst);
211}
212
213void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) {
214 ctx.Add("MOV.F {}.x,scaling[0].z;", inst);
215}
216
217void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) {
218 ctx.Add("MOV.S {}.x,0;", inst);
219}
220
221void EmitUndefU8(EmitContext& ctx, IR::Inst& inst) {
222 ctx.Add("MOV.S {}.x,0;", inst);
223}
224
225void EmitUndefU16(EmitContext& ctx, IR::Inst& inst) {
226 ctx.Add("MOV.S {}.x,0;", inst);
227}
228
229void EmitUndefU32(EmitContext& ctx, IR::Inst& inst) {
230 ctx.Add("MOV.S {}.x,0;", inst);
231}
232
233void EmitUndefU64(EmitContext& ctx, IR::Inst& inst) {
234 ctx.LongAdd("MOV.S64 {}.x,0;", inst);
235}
236
237void EmitGetZeroFromOp(EmitContext& ctx) { 84void EmitGetZeroFromOp(EmitContext& ctx) {
238 NotImplemented(); 85 NotImplemented();
239} 86}
@@ -258,20 +105,4 @@ void EmitGetInBoundsFromOp(EmitContext& ctx) {
258 NotImplemented(); 105 NotImplemented();
259} 106}
260 107
261void EmitLogicalOr(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
262 ctx.Add("OR.S {},{},{};", inst, a, b);
263}
264
265void EmitLogicalAnd(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
266 ctx.Add("AND.S {},{},{};", inst, a, b);
267}
268
269void EmitLogicalXor(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
270 ctx.Add("XOR.S {},{},{};", inst, a, b);
271}
272
273void EmitLogicalNot(EmitContext& ctx, IR::Inst& inst, ScalarS32 value) {
274 ctx.Add("SEQ.S {},{},0;", inst, value);
275}
276
277} // namespace Shader::Backend::GLASM 108} // namespace Shader::Backend::GLASM
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_select.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_select.cpp
index 68fff613c..dc441c56d 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_select.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_select.cpp
@@ -3,8 +3,8 @@
3// Licensed under GPLv2 or any later version 3// Licensed under GPLv2 or any later version
4// Refer to the license.txt file included. 4// Refer to the license.txt file included.
5 5
6#include "shader_recompiler/backend/glasm/emit_context.h"
7#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 6#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
7#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
8#include "shader_recompiler/frontend/ir/value.h" 8#include "shader_recompiler/frontend/ir/value.h"
9 9
10namespace Shader::Backend::GLASM { 10namespace Shader::Backend::GLASM {
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_shared_memory.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_shared_memory.cpp
index c1498f449..39e1c6c3a 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_shared_memory.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_shared_memory.cpp
@@ -3,8 +3,8 @@
3// Licensed under GPLv2 or any later version 3// Licensed under GPLv2 or any later version
4// Refer to the license.txt file included. 4// Refer to the license.txt file included.
5 5
6#include "shader_recompiler/backend/glasm/emit_context.h"
7#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 6#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
7#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
8#include "shader_recompiler/frontend/ir/value.h" 8#include "shader_recompiler/frontend/ir/value.h"
9 9
10namespace Shader::Backend::GLASM { 10namespace Shader::Backend::GLASM {
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_special.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_special.cpp
index e69de29bb..e7a5fb13a 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_special.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_special.cpp
@@ -0,0 +1,95 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
6#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
7#include "shader_recompiler/frontend/ir/value.h"
8
9namespace Shader::Backend::GLASM {
10
11static void DefinePhi(EmitContext& ctx, IR::Inst& phi) {
12 switch (phi.Type()) {
13 case IR::Type::U1:
14 case IR::Type::U32:
15 case IR::Type::F32:
16 ctx.reg_alloc.Define(phi);
17 break;
18 case IR::Type::U64:
19 case IR::Type::F64:
20 ctx.reg_alloc.LongDefine(phi);
21 break;
22 default:
23 throw NotImplementedException("Phi node type {}", phi.Type());
24 }
25}
26
27void EmitPhi(EmitContext& ctx, IR::Inst& phi) {
28 const size_t num_args{phi.NumArgs()};
29 for (size_t i = 0; i < num_args; ++i) {
30 ctx.reg_alloc.Consume(phi.Arg(i));
31 }
32 if (!phi.Definition<Id>().is_valid) {
33 // The phi node wasn't forward defined
34 DefinePhi(ctx, phi);
35 }
36}
37
38void EmitVoid(EmitContext&) {}
39
40void EmitReference(EmitContext& ctx, const IR::Value& value) {
41 ctx.reg_alloc.Consume(value);
42}
43
44void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& value) {
45 IR::Inst& phi{RegAlloc::AliasInst(*phi_value.Inst())};
46 if (!phi.Definition<Id>().is_valid) {
47 // The phi node wasn't forward defined
48 DefinePhi(ctx, phi);
49 }
50 const Register phi_reg{ctx.reg_alloc.Consume(IR::Value{&phi})};
51 const Value eval_value{ctx.reg_alloc.Consume(value)};
52
53 if (phi_reg == eval_value) {
54 return;
55 }
56 switch (phi.Flags<IR::Type>()) {
57 case IR::Type::U1:
58 case IR::Type::U32:
59 case IR::Type::F32:
60 ctx.Add("MOV.S {}.x,{};", phi_reg, ScalarS32{eval_value});
61 break;
62 case IR::Type::U64:
63 case IR::Type::F64:
64 ctx.Add("MOV.U64 {}.x,{};", phi_reg, ScalarRegister{eval_value});
65 break;
66 default:
67 throw NotImplementedException("Phi node type {}", phi.Type());
68 }
69}
70
71void EmitPrologue(EmitContext&) {
72 // TODO
73}
74
75void EmitEpilogue(EmitContext&) {
76 // TODO
77}
78
79void EmitEmitVertex(EmitContext& ctx, ScalarS32 stream) {
80 if (stream.type == Type::U32 && stream.imm_u32 == 0) {
81 ctx.Add("EMIT;");
82 } else {
83 ctx.Add("EMITS {};", stream);
84 }
85}
86
87void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) {
88 if (!stream.IsImmediate()) {
89 LOG_WARNING(Shader_GLASM, "Stream is not immediate");
90 }
91 ctx.reg_alloc.Consume(stream);
92 ctx.Add("ENDPRIM;");
93}
94
95} // namespace Shader::Backend::GLASM
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_undefined.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_undefined.cpp
index e69de29bb..875e9d991 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_undefined.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_undefined.cpp
@@ -0,0 +1,30 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
6#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
7
8namespace Shader::Backend::GLASM {
9
10void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) {
11 ctx.Add("MOV.S {}.x,0;", inst);
12}
13
14void EmitUndefU8(EmitContext& ctx, IR::Inst& inst) {
15 ctx.Add("MOV.S {}.x,0;", inst);
16}
17
18void EmitUndefU16(EmitContext& ctx, IR::Inst& inst) {
19 ctx.Add("MOV.S {}.x,0;", inst);
20}
21
22void EmitUndefU32(EmitContext& ctx, IR::Inst& inst) {
23 ctx.Add("MOV.S {}.x,0;", inst);
24}
25
26void EmitUndefU64(EmitContext& ctx, IR::Inst& inst) {
27 ctx.LongAdd("MOV.S64 {}.x,0;", inst);
28}
29
30} // namespace Shader::Backend::GLASM
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp
index 544d475b4..32e0dd923 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_warp.cpp
@@ -2,8 +2,8 @@
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 "shader_recompiler/backend/glasm/emit_context.h"
6#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 5#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
6#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
7#include "shader_recompiler/frontend/ir/value.h" 7#include "shader_recompiler/frontend/ir/value.h"
8#include "shader_recompiler/profile.h" 8#include "shader_recompiler/profile.h"
9 9
diff --git a/src/shader_recompiler/backend/glasm/emit_context.cpp b/src/shader_recompiler/backend/glasm/glasm_emit_context.cpp
index 8fd459dfe..0401953f7 100644
--- a/src/shader_recompiler/backend/glasm/emit_context.cpp
+++ b/src/shader_recompiler/backend/glasm/glasm_emit_context.cpp
@@ -5,8 +5,8 @@
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/bindings.h" 7#include "shader_recompiler/backend/bindings.h"
8#include "shader_recompiler/backend/glasm/emit_context.h"
9#include "shader_recompiler/backend/glasm/emit_glasm.h" 8#include "shader_recompiler/backend/glasm/emit_glasm.h"
9#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
10#include "shader_recompiler/frontend/ir/program.h" 10#include "shader_recompiler/frontend/ir/program.h"
11#include "shader_recompiler/profile.h" 11#include "shader_recompiler/profile.h"
12#include "shader_recompiler/runtime_info.h" 12#include "shader_recompiler/runtime_info.h"
diff --git a/src/shader_recompiler/backend/glasm/emit_context.h b/src/shader_recompiler/backend/glasm/glasm_emit_context.h
index 8433e5c00..8433e5c00 100644
--- a/src/shader_recompiler/backend/glasm/emit_context.h
+++ b/src/shader_recompiler/backend/glasm/glasm_emit_context.h
diff --git a/src/shader_recompiler/backend/glasm/reg_alloc.cpp b/src/shader_recompiler/backend/glasm/reg_alloc.cpp
index 4c046db6e..201e428c1 100644
--- a/src/shader_recompiler/backend/glasm/reg_alloc.cpp
+++ b/src/shader_recompiler/backend/glasm/reg_alloc.cpp
@@ -6,7 +6,7 @@
6 6
7#include <fmt/format.h> 7#include <fmt/format.h>
8 8
9#include "shader_recompiler/backend/glasm/emit_context.h" 9#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
10#include "shader_recompiler/backend/glasm/reg_alloc.h" 10#include "shader_recompiler/backend/glasm/reg_alloc.h"
11#include "shader_recompiler/exception.h" 11#include "shader_recompiler/exception.h"
12#include "shader_recompiler/frontend/ir/value.h" 12#include "shader_recompiler/frontend/ir/value.h"
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl.cpp b/src/shader_recompiler/backend/glsl/emit_glsl.cpp
index 8a430d573..78b2eeaa2 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl.cpp
@@ -9,9 +9,9 @@
9 9
10#include "common/div_ceil.h" 10#include "common/div_ceil.h"
11#include "common/settings.h" 11#include "common/settings.h"
12#include "shader_recompiler/backend/glsl/emit_context.h"
13#include "shader_recompiler/backend/glsl/emit_glsl.h" 12#include "shader_recompiler/backend/glsl/emit_glsl.h"
14#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 13#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
14#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
15#include "shader_recompiler/frontend/ir/ir_emitter.h" 15#include "shader_recompiler/frontend/ir/ir_emitter.h"
16 16
17namespace Shader::Backend::GLSL { 17namespace Shader::Backend::GLSL {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp
index 772acc5a4..dc377b053 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10 10
11namespace Shader::Backend::GLSL { 11namespace Shader::Backend::GLSL {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_barriers.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_barriers.cpp
index e1d1b558e..8a9faa394 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_barriers.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_barriers.cpp
@@ -2,8 +2,8 @@
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 "shader_recompiler/backend/glsl/emit_context.h"
6#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 5#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
6#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
7#include "shader_recompiler/frontend/ir/value.h" 7#include "shader_recompiler/frontend/ir/value.h"
8 8
9namespace Shader::Backend::GLSL { 9namespace Shader::Backend::GLSL {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
index 3c1714e89..0f2668d9e 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10 10
11namespace Shader::Backend::GLSL { 11namespace Shader::Backend::GLSL {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_composite.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_composite.cpp
index 49a66e3ec..98cc57e58 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_composite.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_composite.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10 10
11namespace Shader::Backend::GLSL { 11namespace Shader::Backend::GLSL {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
index 4c26f3829..1920047f4 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10#include "shader_recompiler/profile.h" 10#include "shader_recompiler/profile.h"
11#include "shader_recompiler/runtime_info.h" 11#include "shader_recompiler/runtime_info.h"
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_control_flow.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_control_flow.cpp
index 53f8896be..c86465e8b 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_control_flow.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_control_flow.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/exception.h" 9#include "shader_recompiler/exception.h"
10 10
11namespace Shader::Backend::GLSL { 11namespace Shader::Backend::GLSL {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_convert.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_convert.cpp
index eeae6562c..ce6ea1bb7 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_convert.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_convert.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10 10
11namespace Shader::Backend::GLSL { 11namespace Shader::Backend::GLSL {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp
index d423bfb1b..b765a251b 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/modifiers.h" 9#include "shader_recompiler/frontend/ir/modifiers.h"
10#include "shader_recompiler/frontend/ir/value.h" 10#include "shader_recompiler/frontend/ir/value.h"
11 11
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
index 2f78d0267..fae2e397a 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/modifiers.h" 9#include "shader_recompiler/frontend/ir/modifiers.h"
10#include "shader_recompiler/frontend/ir/value.h" 10#include "shader_recompiler/frontend/ir/value.h"
11#include "shader_recompiler/profile.h" 11#include "shader_recompiler/profile.h"
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp
index 88c1d4c5e..44060df33 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10 10
11namespace Shader::Backend::GLSL { 11namespace Shader::Backend::GLSL {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_logical.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_logical.cpp
index 338ff4bd6..742fec9cf 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_logical.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_logical.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10 10
11namespace Shader::Backend::GLSL { 11namespace Shader::Backend::GLSL {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_memory.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_memory.cpp
index e3957491f..9fd41b4fd 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_memory.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_memory.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10#include "shader_recompiler/profile.h" 10#include "shader_recompiler/profile.h"
11 11
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp
index f420fe388..4ebdfb3bc 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10 10
11#ifdef _MSC_VER 11#ifdef _MSC_VER
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_select.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_select.cpp
index 49fba9073..b1e486e5f 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_select.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_select.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10 10
11namespace Shader::Backend::GLSL { 11namespace Shader::Backend::GLSL {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_shared_memory.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_shared_memory.cpp
index 518b78f06..74ae345e5 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_shared_memory.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_shared_memory.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10 10
11namespace Shader::Backend::GLSL { 11namespace Shader::Backend::GLSL {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp
index 67f9dad68..b8ddafe48 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/program.h" 9#include "shader_recompiler/frontend/ir/program.h"
10#include "shader_recompiler/frontend/ir/value.h" 10#include "shader_recompiler/frontend/ir/value.h"
11#include "shader_recompiler/profile.h" 11#include "shader_recompiler/profile.h"
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_undefined.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_undefined.cpp
index 15bf02dd6..cace1db85 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_undefined.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_undefined.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9 9
10namespace Shader::Backend::GLSL { 10namespace Shader::Backend::GLSL {
11 11
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp
index cd285e2c8..6e01979b4 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp
@@ -4,8 +4,8 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10#include "shader_recompiler/profile.h" 10#include "shader_recompiler/profile.h"
11 11
diff --git a/src/shader_recompiler/backend/glsl/emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
index 97bd59302..1de017e76 100644
--- a/src/shader_recompiler/backend/glsl/emit_context.cpp
+++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
@@ -3,7 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "shader_recompiler/backend/bindings.h" 5#include "shader_recompiler/backend/bindings.h"
6#include "shader_recompiler/backend/glsl/emit_context.h" 6#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
7#include "shader_recompiler/frontend/ir/program.h" 7#include "shader_recompiler/frontend/ir/program.h"
8#include "shader_recompiler/profile.h" 8#include "shader_recompiler/profile.h"
9#include "shader_recompiler/runtime_info.h" 9#include "shader_recompiler/runtime_info.h"
diff --git a/src/shader_recompiler/backend/glsl/emit_context.h b/src/shader_recompiler/backend/glsl/glsl_emit_context.h
index d9b639d29..d9b639d29 100644
--- a/src/shader_recompiler/backend/glsl/emit_context.h
+++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.h
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index d7a86e270..6ce7ed12a 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -11,6 +11,7 @@
11#include "common/settings.h" 11#include "common/settings.h"
12#include "shader_recompiler/backend/spirv/emit_spirv.h" 12#include "shader_recompiler/backend/spirv/emit_spirv.h"
13#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 13#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
14#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
14#include "shader_recompiler/frontend/ir/basic_block.h" 15#include "shader_recompiler/frontend/ir/basic_block.h"
15#include "shader_recompiler/frontend/ir/program.h" 16#include "shader_recompiler/frontend/ir/program.h"
16 17
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h
index 4b25534ce..b412957c7 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.h
@@ -6,13 +6,11 @@
6 6
7#include <vector> 7#include <vector>
8 8
9#include <sirit/sirit.h>
10
11#include "common/common_types.h" 9#include "common/common_types.h"
12#include "shader_recompiler/backend/bindings.h" 10#include "shader_recompiler/backend/bindings.h"
13#include "shader_recompiler/backend/spirv/emit_context.h"
14#include "shader_recompiler/frontend/ir/program.h" 11#include "shader_recompiler/frontend/ir/program.h"
15#include "shader_recompiler/profile.h" 12#include "shader_recompiler/profile.h"
13#include "shader_recompiler/runtime_info.h"
16 14
17namespace Shader::Backend::SPIRV { 15namespace Shader::Backend::SPIRV {
18 16
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp
index 9af8bb9e1..0d37b405c 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7 8
8namespace Shader::Backend::SPIRV { 9namespace Shader::Backend::SPIRV {
9namespace { 10namespace {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp
index e0b52a001..9ce95a41b 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7#include "shader_recompiler/frontend/ir/modifiers.h" 8#include "shader_recompiler/frontend/ir/modifiers.h"
8 9
9namespace Shader::Backend::SPIRV { 10namespace Shader::Backend::SPIRV {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
index bb11f4f4e..02d1e63f7 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7 8
8namespace Shader::Backend::SPIRV { 9namespace Shader::Backend::SPIRV {
9 10
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp
index 10ff4ecab..5c3e1ee2b 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7#include "shader_recompiler/frontend/ir/modifiers.h" 8#include "shader_recompiler/frontend/ir/modifiers.h"
8 9
9namespace Shader::Backend::SPIRV { 10namespace Shader::Backend::SPIRV {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index bac683ae1..ad84966b5 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -7,6 +7,7 @@
7 7
8#include "shader_recompiler/backend/spirv/emit_spirv.h" 8#include "shader_recompiler/backend/spirv/emit_spirv.h"
9#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 9#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
10#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
10 11
11namespace Shader::Backend::SPIRV { 12namespace Shader::Backend::SPIRV {
12namespace { 13namespace {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
index d33486f28..1eca3aa85 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7 8
8namespace Shader::Backend::SPIRV { 9namespace Shader::Backend::SPIRV {
9 10
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp
index fd42b7a16..832de2452 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7 8
8namespace Shader::Backend::SPIRV { 9namespace Shader::Backend::SPIRV {
9namespace { 10namespace {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
index 61cf25f9c..0cdc46495 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7#include "shader_recompiler/frontend/ir/modifiers.h" 8#include "shader_recompiler/frontend/ir/modifiers.h"
8 9
9namespace Shader::Backend::SPIRV { 10namespace Shader::Backend::SPIRV {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
index 4d168a96d..d18d5f1d5 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -6,6 +6,7 @@
6 6
7#include "shader_recompiler/backend/spirv/emit_spirv.h" 7#include "shader_recompiler/backend/spirv/emit_spirv.h"
8#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 8#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
9#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
9#include "shader_recompiler/frontend/ir/modifiers.h" 10#include "shader_recompiler/frontend/ir/modifiers.h"
10 11
11namespace Shader::Backend::SPIRV { 12namespace Shader::Backend::SPIRV {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image_atomic.cpp
index d7f1a365a..a96190bc6 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image_atomic.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image_atomic.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7#include "shader_recompiler/frontend/ir/modifiers.h" 8#include "shader_recompiler/frontend/ir/modifiers.h"
8 9
9namespace Shader::Backend::SPIRV { 10namespace Shader::Backend::SPIRV {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
index 50277eec3..44521f539 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7 8
8namespace Shader::Backend::SPIRV { 9namespace Shader::Backend::SPIRV {
9namespace { 10namespace {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp
index b9a9500fc..47745f7ee 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7 8
8namespace Shader::Backend::SPIRV { 9namespace Shader::Backend::SPIRV {
9 10
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
index 679ee2684..175f4be19 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
@@ -6,6 +6,7 @@
6 6
7#include "shader_recompiler/backend/spirv/emit_spirv.h" 7#include "shader_recompiler/backend/spirv/emit_spirv.h"
8#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 8#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
9#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
9 10
10namespace Shader::Backend::SPIRV { 11namespace Shader::Backend::SPIRV {
11namespace { 12namespace {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp
index c5b4f4720..48caf1ffc 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7 8
8namespace Shader::Backend::SPIRV { 9namespace Shader::Backend::SPIRV {
9 10
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp
index 9a79fc7a2..330c9052c 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7 8
8namespace Shader::Backend::SPIRV { 9namespace Shader::Backend::SPIRV {
9namespace { 10namespace {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
index 9e7eb3cb1..d96a17583 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7 8
8namespace Shader::Backend::SPIRV { 9namespace Shader::Backend::SPIRV {
9namespace { 10namespace {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp
index c9f469e90..b5766fc52 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7 8
8namespace Shader::Backend::SPIRV { 9namespace Shader::Backend::SPIRV {
9 10
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
index cef52c56e..7034228bf 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
@@ -4,6 +4,7 @@
4 4
5#include "shader_recompiler/backend/spirv/emit_spirv.h" 5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 6#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
7#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
7 8
8namespace Shader::Backend::SPIRV { 9namespace Shader::Backend::SPIRV {
9namespace { 10namespace {
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index 723455462..4b6f792bf 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -13,8 +13,8 @@
13 13
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/div_ceil.h" 15#include "common/div_ceil.h"
16#include "shader_recompiler/backend/spirv/emit_context.h"
17#include "shader_recompiler/backend/spirv/emit_spirv.h" 16#include "shader_recompiler/backend/spirv/emit_spirv.h"
17#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
18 18
19namespace Shader::Backend::SPIRV { 19namespace Shader::Backend::SPIRV {
20namespace { 20namespace {
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
index 63f8185d9..63f8185d9 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.h
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index ab7c21a49..8788f5148 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -185,16 +185,6 @@ struct GPU::Impl {
185 return *dma_pusher; 185 return *dma_pusher;
186 } 186 }
187 187
188 /// Returns a reference to the GPU CDMA pusher.
189 [[nodiscard]] Tegra::CDmaPusher& CDmaPusher() {
190 return *cdma_pusher;
191 }
192
193 /// Returns a const reference to the GPU CDMA pusher.
194 [[nodiscard]] const Tegra::CDmaPusher& CDmaPusher() const {
195 return *cdma_pusher;
196 }
197
198 /// Returns a reference to the underlying renderer. 188 /// Returns a reference to the underlying renderer.
199 [[nodiscard]] VideoCore::RendererBase& Renderer() { 189 [[nodiscard]] VideoCore::RendererBase& Renderer() {
200 return *renderer; 190 return *renderer;
@@ -338,25 +328,27 @@ struct GPU::Impl {
338 } 328 }
339 329
340 /// Push GPU command buffer entries to be processed 330 /// Push GPU command buffer entries to be processed
341 void PushCommandBuffer(Tegra::ChCommandHeaderList& entries) { 331 void PushCommandBuffer(u32 id, Tegra::ChCommandHeaderList& entries) {
342 if (!use_nvdec) { 332 if (!use_nvdec) {
343 return; 333 return;
344 } 334 }
345 335
346 if (!cdma_pusher) { 336 if (!cdma_pushers.contains(id)) {
347 cdma_pusher = std::make_unique<Tegra::CDmaPusher>(gpu); 337 cdma_pushers.insert_or_assign(id, std::make_unique<Tegra::CDmaPusher>(gpu));
348 } 338 }
349 339
350 // SubmitCommandBuffer would make the nvdec operations async, this is not currently working 340 // SubmitCommandBuffer would make the nvdec operations async, this is not currently working
351 // TODO(ameerj): RE proper async nvdec operation 341 // TODO(ameerj): RE proper async nvdec operation
352 // gpu_thread.SubmitCommandBuffer(std::move(entries)); 342 // gpu_thread.SubmitCommandBuffer(std::move(entries));
353 343 cdma_pushers[id]->ProcessEntries(std::move(entries));
354 cdma_pusher->ProcessEntries(std::move(entries));
355 } 344 }
356 345
357 /// Frees the CDMAPusher instance to free up resources 346 /// Frees the CDMAPusher instance to free up resources
358 void ClearCdmaInstance() { 347 void ClearCdmaInstance(u32 id) {
359 cdma_pusher.reset(); 348 const auto iter = cdma_pushers.find(id);
349 if (iter != cdma_pushers.end()) {
350 cdma_pushers.erase(iter);
351 }
360 } 352 }
361 353
362 /// Swap buffers (render frame) 354 /// Swap buffers (render frame)
@@ -659,7 +651,7 @@ struct GPU::Impl {
659 Core::System& system; 651 Core::System& system;
660 std::unique_ptr<Tegra::MemoryManager> memory_manager; 652 std::unique_ptr<Tegra::MemoryManager> memory_manager;
661 std::unique_ptr<Tegra::DmaPusher> dma_pusher; 653 std::unique_ptr<Tegra::DmaPusher> dma_pusher;
662 std::unique_ptr<Tegra::CDmaPusher> cdma_pusher; 654 std::map<u32, std::unique_ptr<Tegra::CDmaPusher>> cdma_pushers;
663 std::unique_ptr<VideoCore::RendererBase> renderer; 655 std::unique_ptr<VideoCore::RendererBase> renderer;
664 VideoCore::RasterizerInterface* rasterizer = nullptr; 656 VideoCore::RasterizerInterface* rasterizer = nullptr;
665 const bool use_nvdec; 657 const bool use_nvdec;
@@ -811,14 +803,6 @@ const Tegra::DmaPusher& GPU::DmaPusher() const {
811 return impl->DmaPusher(); 803 return impl->DmaPusher();
812} 804}
813 805
814Tegra::CDmaPusher& GPU::CDmaPusher() {
815 return impl->CDmaPusher();
816}
817
818const Tegra::CDmaPusher& GPU::CDmaPusher() const {
819 return impl->CDmaPusher();
820}
821
822VideoCore::RendererBase& GPU::Renderer() { 806VideoCore::RendererBase& GPU::Renderer() {
823 return impl->Renderer(); 807 return impl->Renderer();
824} 808}
@@ -887,12 +871,12 @@ void GPU::PushGPUEntries(Tegra::CommandList&& entries) {
887 impl->PushGPUEntries(std::move(entries)); 871 impl->PushGPUEntries(std::move(entries));
888} 872}
889 873
890void GPU::PushCommandBuffer(Tegra::ChCommandHeaderList& entries) { 874void GPU::PushCommandBuffer(u32 id, Tegra::ChCommandHeaderList& entries) {
891 impl->PushCommandBuffer(entries); 875 impl->PushCommandBuffer(id, entries);
892} 876}
893 877
894void GPU::ClearCdmaInstance() { 878void GPU::ClearCdmaInstance(u32 id) {
895 impl->ClearCdmaInstance(); 879 impl->ClearCdmaInstance(id);
896} 880}
897 881
898void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { 882void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index c89a5d693..500411176 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -242,10 +242,10 @@ public:
242 void PushGPUEntries(Tegra::CommandList&& entries); 242 void PushGPUEntries(Tegra::CommandList&& entries);
243 243
244 /// Push GPU command buffer entries to be processed 244 /// Push GPU command buffer entries to be processed
245 void PushCommandBuffer(Tegra::ChCommandHeaderList& entries); 245 void PushCommandBuffer(u32 id, Tegra::ChCommandHeaderList& entries);
246 246
247 /// Frees the CDMAPusher instance to free up resources 247 /// Frees the CDMAPusher instance to free up resources
248 void ClearCdmaInstance(); 248 void ClearCdmaInstance(u32 id);
249 249
250 /// Swap buffers (render frame) 250 /// Swap buffers (render frame)
251 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer); 251 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer);
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 31adada56..751e4792b 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -162,7 +162,7 @@ struct FormatTuple {
162 {VK_FORMAT_UNDEFINED}, // R16_SINT 162 {VK_FORMAT_UNDEFINED}, // R16_SINT
163 {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // R16G16_UNORM 163 {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // R16G16_UNORM
164 {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // R16G16_FLOAT 164 {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // R16G16_FLOAT
165 {VK_FORMAT_UNDEFINED}, // R16G16_UINT 165 {VK_FORMAT_R16G16_UINT, Attachable | Storage}, // R16G16_UINT
166 {VK_FORMAT_R16G16_SINT, Attachable | Storage}, // R16G16_SINT 166 {VK_FORMAT_R16G16_SINT, Attachable | Storage}, // R16G16_SINT
167 {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM 167 {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM
168 {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT 168 {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT
@@ -176,8 +176,8 @@ struct FormatTuple {
176 {VK_FORMAT_R32_UINT, Attachable | Storage}, // R32_UINT 176 {VK_FORMAT_R32_UINT, Attachable | Storage}, // R32_UINT
177 {VK_FORMAT_R32_SINT, Attachable | Storage}, // R32_SINT 177 {VK_FORMAT_R32_SINT, Attachable | Storage}, // R32_SINT
178 {VK_FORMAT_ASTC_8x8_UNORM_BLOCK}, // ASTC_2D_8X8_UNORM 178 {VK_FORMAT_ASTC_8x8_UNORM_BLOCK}, // ASTC_2D_8X8_UNORM
179 {VK_FORMAT_UNDEFINED}, // ASTC_2D_8X5_UNORM 179 {VK_FORMAT_ASTC_8x5_UNORM_BLOCK}, // ASTC_2D_8X5_UNORM
180 {VK_FORMAT_UNDEFINED}, // ASTC_2D_5X4_UNORM 180 {VK_FORMAT_ASTC_5x4_UNORM_BLOCK}, // ASTC_2D_5X4_UNORM
181 {VK_FORMAT_B8G8R8A8_SRGB, Attachable}, // B8G8R8A8_SRGB 181 {VK_FORMAT_B8G8R8A8_SRGB, Attachable}, // B8G8R8A8_SRGB
182 {VK_FORMAT_BC1_RGBA_SRGB_BLOCK}, // BC1_RGBA_SRGB 182 {VK_FORMAT_BC1_RGBA_SRGB_BLOCK}, // BC1_RGBA_SRGB
183 {VK_FORMAT_BC2_SRGB_BLOCK}, // BC2_SRGB 183 {VK_FORMAT_BC2_SRGB_BLOCK}, // BC2_SRGB
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 565b99254..5aaeb16ca 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1122,7 +1122,7 @@ typename TextureCache<P>::BlitImages TextureCache<P>::GetBlitImages(
1122 break; 1122 break;
1123 } 1123 }
1124 if (can_be_depth_blit) { 1124 if (can_be_depth_blit) {
1125 const ImageBase* const dst_image = src_id ? &slot_images[src_id] : nullptr; 1125 const ImageBase* const dst_image = dst_id ? &slot_images[dst_id] : nullptr;
1126 DeduceBlitImages(dst_info, src_info, dst_image, src_image); 1126 DeduceBlitImages(dst_info, src_info, dst_image, src_image);
1127 if (GetFormatType(dst_info.format) != GetFormatType(src_info.format)) { 1127 if (GetFormatType(dst_info.format) != GetFormatType(src_info.format)) {
1128 continue; 1128 continue;
@@ -1135,8 +1135,16 @@ typename TextureCache<P>::BlitImages TextureCache<P>::GetBlitImages(
1135 dst_id = InsertImage(dst_info, dst_addr, RelaxedOptions{}); 1135 dst_id = InsertImage(dst_info, dst_addr, RelaxedOptions{});
1136 } 1136 }
1137 } while (has_deleted_images); 1137 } while (has_deleted_images);
1138 if (GetFormatType(dst_info.format) != SurfaceType::ColorTexture) { 1138 const ImageBase& src_image = slot_images[src_id];
1139 // Make sure the images are depth and/or stencil textures. 1139 const ImageBase& dst_image = slot_images[dst_id];
1140 const bool native_bgr = runtime.HasNativeBgr();
1141 if (GetFormatType(dst_info.format) != GetFormatType(dst_image.info.format) ||
1142 GetFormatType(src_info.format) != GetFormatType(src_image.info.format) ||
1143 !VideoCore::Surface::IsViewCompatible(dst_info.format, dst_image.info.format, false,
1144 native_bgr) ||
1145 !VideoCore::Surface::IsViewCompatible(src_info.format, src_image.info.format, false,
1146 native_bgr)) {
1147 // Make sure the images match the expected format.
1140 do { 1148 do {
1141 has_deleted_images = false; 1149 has_deleted_images = false;
1142 src_id = FindOrInsertImage(src_info, src_addr, RelaxedOptions{}); 1150 src_id = FindOrInsertImage(src_info, src_addr, RelaxedOptions{});
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 70c52aaac..7bf5b6578 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -130,6 +130,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::Physica
130 VK_FORMAT_R16G16_UNORM, 130 VK_FORMAT_R16G16_UNORM,
131 VK_FORMAT_R16G16_SNORM, 131 VK_FORMAT_R16G16_SNORM,
132 VK_FORMAT_R16G16_SFLOAT, 132 VK_FORMAT_R16G16_SFLOAT,
133 VK_FORMAT_R16G16_UINT,
133 VK_FORMAT_R16G16_SINT, 134 VK_FORMAT_R16G16_SINT,
134 VK_FORMAT_R16_UNORM, 135 VK_FORMAT_R16_UNORM,
135 VK_FORMAT_R16_SNORM, 136 VK_FORMAT_R16_SNORM,
diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp
index de7f98c4f..c3857fc98 100644
--- a/src/yuzu/applets/qt_software_keyboard.cpp
+++ b/src/yuzu/applets/qt_software_keyboard.cpp
@@ -475,11 +475,26 @@ void QtSoftwareKeyboardDialog::open() {
475 row = 0; 475 row = 0;
476 column = 0; 476 column = 0;
477 477
478 const auto* const curr_button = 478 switch (bottom_osk_index) {
479 keyboard_buttons[static_cast<int>(bottom_osk_index)][row][column]; 479 case BottomOSKIndex::LowerCase:
480 case BottomOSKIndex::UpperCase: {
481 const auto* const curr_button =
482 keyboard_buttons[static_cast<std::size_t>(bottom_osk_index)][row][column];
483
484 // This is a workaround for setFocus() randomly not showing focus in the UI
485 QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center()));
486 break;
487 }
488 case BottomOSKIndex::NumberPad: {
489 const auto* const curr_button = numberpad_buttons[row][column];
480 490
481 // This is a workaround for setFocus() randomly not showing focus in the UI 491 // This is a workaround for setFocus() randomly not showing focus in the UI
482 QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); 492 QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center()));
493 break;
494 }
495 default:
496 break;
497 }
483 498
484 StartInputThread(); 499 StartInputThread();
485} 500}
diff --git a/src/yuzu/debugger/profiler.cpp b/src/yuzu/debugger/profiler.cpp
index a8b254199..33110685a 100644
--- a/src/yuzu/debugger/profiler.cpp
+++ b/src/yuzu/debugger/profiler.cpp
@@ -163,7 +163,7 @@ void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* ev) {
163} 163}
164 164
165void MicroProfileWidget::wheelEvent(QWheelEvent* ev) { 165void MicroProfileWidget::wheelEvent(QWheelEvent* ev) {
166 const auto wheel_position = ev->pos(); 166 const auto wheel_position = ev->position().toPoint();
167 MicroProfileMousePosition(wheel_position.x() / x_scale, wheel_position.y() / y_scale, 167 MicroProfileMousePosition(wheel_position.x() / x_scale, wheel_position.y() / y_scale,
168 ev->angleDelta().y() / 120); 168 ev->angleDelta().y() / 120);
169 ev->accept(); 169 ev->accept();
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index d012477e4..b7bb43348 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -77,6 +77,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
77#include "common/fs/fs.h" 77#include "common/fs/fs.h"
78#include "common/fs/fs_paths.h" 78#include "common/fs/fs_paths.h"
79#include "common/fs/path_util.h" 79#include "common/fs/path_util.h"
80#include "common/literals.h"
80#include "common/logging/backend.h" 81#include "common/logging/backend.h"
81#include "common/logging/filter.h" 82#include "common/logging/filter.h"
82#include "common/logging/log.h" 83#include "common/logging/log.h"
@@ -134,6 +135,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
134#include "yuzu/main.h" 135#include "yuzu/main.h"
135#include "yuzu/uisettings.h" 136#include "yuzu/uisettings.h"
136 137
138using namespace Common::Literals;
139
137#ifdef USE_DISCORD_PRESENCE 140#ifdef USE_DISCORD_PRESENCE
138#include "yuzu/discord_impl.h" 141#include "yuzu/discord_impl.h"
139#endif 142#endif
@@ -259,10 +262,9 @@ GMainWindow::GMainWindow()
259 LOG_INFO(Frontend, "Host CPU: {}", cpu_string); 262 LOG_INFO(Frontend, "Host CPU: {}", cpu_string);
260#endif 263#endif
261 LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString()); 264 LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString());
262 LOG_INFO(Frontend, "Host RAM: {:.2f} GB", 265 LOG_INFO(Frontend, "Host RAM: {:.2f} GiB",
263 Common::GetMemInfo().TotalPhysicalMemory / 1024.0f / 1024 / 1024); 266 Common::GetMemInfo().TotalPhysicalMemory / f64{1_GiB});
264 LOG_INFO(Frontend, "Host Swap: {:.2f} GB", 267 LOG_INFO(Frontend, "Host Swap: {:.2f} GiB", Common::GetMemInfo().TotalSwapMemory / f64{1_GiB});
265 Common::GetMemInfo().TotalSwapMemory / 1024.0f / 1024 / 1024);
266 UpdateWindowTitle(); 268 UpdateWindowTitle();
267 269
268 show(); 270 show();
@@ -1082,14 +1084,15 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
1082 state != Qt::ApplicationActive) { 1084 state != Qt::ApplicationActive) {
1083 LOG_DEBUG(Frontend, "ApplicationState unusual flag: {} ", state); 1085 LOG_DEBUG(Frontend, "ApplicationState unusual flag: {} ", state);
1084 } 1086 }
1085 if (ui->action_Pause->isEnabled() && 1087 if (emulation_running) {
1086 (state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) { 1088 if (emu_thread->IsRunning() &&
1087 auto_paused = true; 1089 (state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
1088 OnPauseGame(); 1090 auto_paused = true;
1089 } else if (emulation_running && !emu_thread->IsRunning() && auto_paused && 1091 OnPauseGame();
1090 state == Qt::ApplicationActive) { 1092 } else if (!emu_thread->IsRunning() && auto_paused && state == Qt::ApplicationActive) {
1091 auto_paused = false; 1093 auto_paused = false;
1092 OnStartGame(); 1094 OnStartGame();
1095 }
1093 } 1096 }
1094} 1097}
1095 1098