diff options
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) | |||
| 131 | if (MSVC) | 131 | if (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) |
| 136 | else() | 136 | else() |
| 137 | set(CMAKE_CXX_STANDARD 20) | 137 | set(CMAKE_CXX_STANDARD 20) |
| @@ -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) | |||
| 44 | add_library(microprofile INTERFACE) | 44 | add_library(microprofile INTERFACE) |
| 45 | target_include_directories(microprofile INTERFACE ./microprofile) | 45 | target_include_directories(microprofile INTERFACE ./microprofile) |
| 46 | 46 | ||
| 47 | # Unicorn | ||
| 48 | add_library(unicorn-headers INTERFACE) | ||
| 49 | target_include_directories(unicorn-headers INTERFACE ./unicorn/include) | ||
| 50 | |||
| 51 | # libusb | 47 | # libusb |
| 52 | if (NOT LIBUSB_FOUND OR YUZU_USE_BUNDLED_LIBUSB) | 48 | if (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 | |||
| 6 | find_path(LIBUNICORN_INCLUDE_DIR | ||
| 7 | unicorn/unicorn.h | ||
| 8 | HINTS $ENV{UNICORNDIR} | ||
| 9 | PATH_SUFFIXES include) | ||
| 10 | |||
| 11 | find_library(LIBUNICORN_LIBRARY | ||
| 12 | NAMES unicorn | ||
| 13 | HINTS $ENV{UNICORNDIR}) | ||
| 14 | |||
| 15 | include(FindPackageHandleStandardArgs) | ||
| 16 | find_package_handle_standard_args(unicorn DEFAULT_MSG | ||
| 17 | LIBUNICORN_LIBRARY LIBUNICORN_INCLUDE_DIR) | ||
| 18 | mark_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 |
| 229 | struct InputCallback { | 229 | struct 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 { | |||
| 266 | public: | 262 | public: |
| 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 | ||
| 524 | std::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 | |||
| 530 | Kernel::PhysicalCore& System::CurrentPhysicalCore() { | 524 | Kernel::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 | ||
| 125 | void CpuManager::MultiCoreRunIdleThread() { | 127 | void 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 | ||
| 130 | void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) { | 134 | void 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 | ||
| 165 | void EmulatedConsole::SetTouch(Common::Input::CallbackStatus callback, | 169 | void 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 | ||
| 463 | void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::size_t index, | 474 | void 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 | ||
| 603 | void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::size_t index, | 614 | void 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 | ||
| 653 | void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, | 664 | void 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 | ||
| 695 | void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::size_t index) { | 706 | void 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 | ||
| 733 | void EmulatedController::SetBattery(Common::Input::CallbackStatus callback, std::size_t index) { | 745 | void 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 | ||
| 1111 | int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) { | 1124 | int 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 | ||
| 162 | void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) { | 167 | void 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 | ||
| 219 | void EmulatedDevices::SetKeyboardModifier(Common::Input::CallbackStatus callback, | 225 | void 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 | ||
| 289 | void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index) { | 295 | void 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 | ||
| 350 | void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index) { | 357 | void 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 | ||
| 377 | void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) { | 385 | void 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 | ||
| 436 | int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) { | 444 | int 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 | ||
| 148 | NpadIdType 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 | |||
| 148 | void HIDCore::EnableAllControllerConfiguration() { | 158 | void 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 | ||
| 29 | bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 value) { | 30 | bool 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 | ||
| 59 | bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 new_value) { | 60 | bool 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 | ||
| 89 | class ThreadQueueImplForKAddressArbiter final : public KThreadQueue { | ||
| 90 | public: | ||
| 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 | |||
| 106 | private: | ||
| 107 | KAddressArbiter::ThreadTree* m_tree; | ||
| 108 | }; | ||
| 109 | |||
| 88 | } // namespace | 110 | } // namespace |
| 89 | 111 | ||
| 90 | ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) { | 112 | ResultCode 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 | |||
| 214 | ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) { | 236 | ResultCode 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 | ||
| 281 | ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { | 289 | ResultCode 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 | |||
| 173 | private: | 177 | private: |
| 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); | |||
| 48 | static_assert(ClassToken<KTransferMemory> == 0b10010001'00000000); | 49 | static_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); | 52 | static_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 | |||
| 79 | static_assert(ClassToken<KTransferMemory> == ((0b10010001 << 8) | ClassToken<KAutoObject>)); | 80 | static_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>)); | 83 | static_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 | |||
| 18 | namespace Kernel { | ||
| 19 | |||
| 20 | KCodeMemory::KCodeMemory(KernelCore& kernel_) | ||
| 21 | : KAutoObjectWithSlabHeapAndContainer{kernel_}, m_lock(kernel_) {} | ||
| 22 | |||
| 23 | ResultCode 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 | |||
| 52 | void 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 | |||
| 60 | ResultCode 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 | |||
| 80 | ResultCode 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 | |||
| 97 | ResultCode 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 | |||
| 130 | ResultCode 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 | |||
| 17 | namespace Kernel { | ||
| 18 | |||
| 19 | enum class CodeMemoryOperation : u32 { | ||
| 20 | Map = 0, | ||
| 21 | MapToOwner = 1, | ||
| 22 | Unmap = 2, | ||
| 23 | UnmapFromOwner = 3, | ||
| 24 | }; | ||
| 25 | |||
| 26 | class KCodeMemory final | ||
| 27 | : public KAutoObjectWithSlabHeapAndContainer<KCodeMemory, KAutoObjectWithList> { | ||
| 28 | KERNEL_AUTOOBJECT_TRAITS(KCodeMemory, KAutoObject); | ||
| 29 | |||
| 30 | public: | ||
| 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 | |||
| 56 | private: | ||
| 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) { | |||
| 33 | bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero, | 34 | bool 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 | ||
| 61 | class ThreadQueueImplForKConditionVariableWaitForAddress final : public KThreadQueue { | ||
| 62 | public: | ||
| 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 | |||
| 76 | class ThreadQueueImplForKConditionVariableWaitConditionVariable final : public KThreadQueue { | ||
| 77 | private: | ||
| 78 | KConditionVariable::ThreadTree* m_tree; | ||
| 79 | |||
| 80 | public: | ||
| 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 | ||
| 62 | KConditionVariable::KConditionVariable(Core::System& system_) | 105 | KConditionVariable::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 | ||
| 104 | ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) { | 151 | ResultCode 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 | ||
| 158 | KThread* KConditionVariable::SignalImpl(KThread* thread) { | 194 | void 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 | ||
| 211 | void KConditionVariable::Signal(u64 cv_key, s32 count) { | 241 | void 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 | ||
| 260 | ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { | 266 | ResultCode 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 | ||
| 36 | private: | 36 | private: |
| 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 | ||
| 64 | ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { | 66 | ResultCode 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 | ||
| 86 | ResultCode KHandleTable::Reserve(Handle* out_handle) { | 89 | ResultCode 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 | ||
| 96 | void KHandleTable::Unreserve(Handle handle) { | 100 | void 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 | ||
| 114 | void KHandleTable::Register(Handle handle, KAutoObject* obj, u16 type) { | 119 | void 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 | |||
| 11 | namespace Kernel { | ||
| 12 | |||
| 13 | namespace { | ||
| 14 | |||
| 15 | class ThreadQueueImplForKLightConditionVariable final : public KThreadQueue { | ||
| 16 | public: | ||
| 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 | |||
| 35 | private: | ||
| 36 | KThread::WaiterList* m_wait_list; | ||
| 37 | bool m_allow_terminating_thread; | ||
| 38 | }; | ||
| 39 | |||
| 40 | } // namespace | ||
| 41 | |||
| 42 | void 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 | |||
| 71 | void 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 | ||
| 15 | namespace Kernel { | 10 | namespace Kernel { |
| 11 | |||
| 16 | class KernelCore; | 12 | class KernelCore; |
| 13 | class KLightLock; | ||
| 17 | 14 | ||
| 18 | class KLightConditionVariable { | 15 | class KLightConditionVariable { |
| 19 | public: | 16 | public: |
| 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 | ||
| 35 | private: | 22 | private: |
| 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 | ||
| 10 | namespace Kernel { | 11 | namespace Kernel { |
| 11 | 12 | ||
| 13 | namespace { | ||
| 14 | |||
| 15 | class ThreadQueueImplForKLightLock final : public KThreadQueue { | ||
| 16 | public: | ||
| 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 | |||
| 12 | void KLightLock::Lock() { | 33 | void 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 | ||
| 34 | void KLightLock::Unlock() { | 49 | void 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 | ||
| 44 | void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { | 58 | bool 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 | ||
| 79 | void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { | 87 | void 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 | }; |
| 135 | DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); | 155 | DECLARE_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 | ||
| 371 | ResultCode 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 | } | ||
| 371 | void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) { | 398 | void 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 | ||
| 972 | ResultCode 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 | |||
| 999 | ResultCode 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 | |||
| 945 | ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { | 1026 | ResultCode 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 | ||
| 1315 | ResultCode 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 | ||
| 238 | void KProcess::UnpinCurrentThread() { | 242 | void KProcess::UnpinCurrentThread() { |
| @@ -250,6 +254,20 @@ void KProcess::UnpinCurrentThread() { | |||
| 250 | KScheduler::SetSchedulerUpdateNeeded(kernel); | 254 | KScheduler::SetSchedulerUpdateNeeded(kernel); |
| 251 | } | 255 | } |
| 252 | 256 | ||
| 257 | void 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 | |||
| 253 | ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address, | 271 | ResultCode 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 | ||
| 362 | bool KScheduler::CanSchedule(KernelCore& kernel) { | 362 | bool KScheduler::CanSchedule(KernelCore& kernel) { |
| 363 | return kernel.CurrentScheduler()->GetCurrentThread()->GetDisableDispatchCount() <= 1; | 363 | return kernel.GetCurrentEmuThread()->GetDisableDispatchCount() <= 1; |
| 364 | } | 364 | } |
| 365 | 365 | ||
| 366 | bool KScheduler::IsSchedulerUpdateNeeded(const KernelCore& kernel) { | 366 | bool KScheduler::IsSchedulerUpdateNeeded(const KernelCore& kernel) { |
| @@ -376,20 +376,30 @@ void KScheduler::ClearSchedulerUpdateNeeded(KernelCore& kernel) { | |||
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | void KScheduler::DisableScheduling(KernelCore& kernel) { | 378 | void 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 | ||
| 385 | void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling) { | 388 | void 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 | ||
| 395 | u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { | 405 | u64 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 | ||
| 620 | KScheduler::~KScheduler() { | 630 | void 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 | ||
| 637 | KScheduler::~KScheduler() { | ||
| 638 | ASSERT(!idle_thread); | ||
| 639 | } | ||
| 640 | |||
| 627 | KThread* KScheduler::GetCurrentThread() const { | 641 | KThread* 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 | ||
| 657 | void KScheduler::Unload(KThread* thread) { | 673 | void 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 | ||
| 680 | void KScheduler::Reload(KThread* thread) { | 703 | void 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 | ||
| 707 | void KScheduler::ScheduleImpl() { | 725 | void 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 | ||
| 14 | namespace Kernel { | 15 | namespace Kernel { |
| 15 | 16 | ||
| 17 | namespace { | ||
| 18 | |||
| 19 | class ThreadQueueImplForKSynchronizationObjectWait final : public KThreadQueueWithoutEndWait { | ||
| 20 | public: | ||
| 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 | |||
| 63 | private: | ||
| 64 | KSynchronizationObject** m_objects; | ||
| 65 | KSynchronizationObject::ThreadListNode* m_nodes; | ||
| 66 | s32 m_count; | ||
| 67 | }; | ||
| 68 | |||
| 69 | } // namespace | ||
| 70 | |||
| 16 | void KSynchronizationObject::Finalize() { | 71 | void 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 | ||
| 138 | KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) | 147 | KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) |
| @@ -141,7 +150,7 @@ KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) | |||
| 141 | KSynchronizationObject::~KSynchronizationObject() = default; | 150 | KSynchronizationObject::~KSynchronizationObject() = default; |
| 142 | 151 | ||
| 143 | void KSynchronizationObject::NotifyAvailable(ResultCode result) { | 152 | void 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 | |||
| 38 | protected: | 70 | protected: |
| 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 | ||
| 57 | namespace Kernel { | 60 | namespace Kernel { |
| 58 | 61 | ||
| 62 | namespace { | ||
| 63 | |||
| 64 | class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait { | ||
| 65 | public: | ||
| 66 | explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel_) | ||
| 67 | : KThreadQueueWithoutEndWait(kernel_) {} | ||
| 68 | }; | ||
| 69 | |||
| 70 | class ThreadQueueImplForKThreadSetProperty final : public KThreadQueue { | ||
| 71 | public: | ||
| 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 | |||
| 84 | private: | ||
| 85 | KThread::WaiterList* m_wait_list; | ||
| 86 | }; | ||
| 87 | |||
| 88 | } // namespace | ||
| 89 | |||
| 59 | KThread::KThread(KernelCore& kernel_) | 90 | KThread::KThread(KernelCore& kernel_) |
| 60 | : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {} | 91 | : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {} |
| 61 | KThread::~KThread() = default; | 92 | KThread::~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 | ||
| 221 | ResultCode KThread::InitializeDummyThread(KThread* thread) { | 252 | ResultCode KThread::InitializeDummyThread(KThread* thread) { |
| 222 | return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Main); | 253 | return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Dummy); |
| 223 | } | 254 | } |
| 224 | 255 | ||
| 225 | ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { | 256 | ResultCode 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 | ||
| 297 | void KThread::Wakeup() { | 331 | void 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 | ||
| 478 | ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { | 509 | ResultCode 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. | 1024 | void 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 | |||
| 1032 | void 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 | |||
| 1042 | void 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 | |||
| 1052 | void 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 | ||
| 1022 | void KThread::SetState(ThreadState state) { | 1062 | void 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 | ||
| 1093 | KScopedDisableDispatch::~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 | }; |
| 52 | DECLARE_ENUM_FLAG_OPERATORS(ThreadType); | 53 | DECLARE_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 | ||
| 791 | class KScopedDisableDispatch { | ||
| 792 | public: | ||
| 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 | |||
| 803 | private: | ||
| 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 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | void KThreadQueue::NotifyAvailable([[maybe_unused]] KThread* waiting_thread, | ||
| 12 | [[maybe_unused]] KSynchronizationObject* signaled_object, | ||
| 13 | [[maybe_unused]] ResultCode wait_result) {} | ||
| 14 | |||
| 15 | void 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 | |||
| 29 | void 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 | |||
| 46 | void 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 | ||
| 9 | namespace Kernel { | 10 | namespace Kernel { |
| @@ -11,71 +12,24 @@ namespace Kernel { | |||
| 11 | class KThreadQueue { | 12 | class KThreadQueue { |
| 12 | public: | 13 | public: |
| 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 | ||
| 76 | private: | 23 | private: |
| 77 | KernelCore& kernel; | 24 | KernelCore& kernel; |
| 78 | KThread::WaiterList wait_list{}; | 25 | KThread::WaiterList wait_list{}; |
| 79 | }; | 26 | }; |
| 80 | 27 | ||
| 28 | class KThreadQueueWithoutEndWait : public KThreadQueue { | ||
| 29 | public: | ||
| 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 | ||
| 854 | size_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 | |||
| 848 | Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() { | 862 | Kernel::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 | ||
| 854 | const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { | 866 | const 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 | ||
| 860 | Kernel::KScheduler* KernelCore::CurrentScheduler() { | 870 | Kernel::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 | ||
| 1081 | bool KernelCore::IsShuttingDown() const { | ||
| 1082 | return impl->IsShuttingDown(); | ||
| 1083 | } | ||
| 1084 | |||
| 1068 | void KernelCore::ExceptionalExit() { | 1085 | void KernelCore::ExceptionalExit() { |
| 1069 | exception_exited = true; | 1086 | exception_exited = true; |
| 1070 | Suspend(true); | 1087 | Suspend(true); |
| 1071 | } | 1088 | } |
| 1072 | 1089 | ||
| 1073 | void KernelCore::EnterSVCProfile() { | 1090 | void 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 | ||
| 1078 | void KernelCore::ExitSVCProfile() { | 1094 | void 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 | ||
| 1083 | std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) { | 1098 | std::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; | |||
| 53 | class KThread; | 53 | class KThread; |
| 54 | class KTransferMemory; | 54 | class KTransferMemory; |
| 55 | class KWritableEvent; | 55 | class KWritableEvent; |
| 56 | class KCodeMemory; | ||
| 56 | class PhysicalCore; | 57 | class PhysicalCore; |
| 57 | class ServiceThread; | 58 | class ServiceThread; |
| 58 | class Synchronization; | 59 | class 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 | ||
| 27 | private: | 27 | private: |
| 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 | ||
| 36 | ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name) | 35 | ServiceThread::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 | ||
| 68 | void ServiceThread::Impl::QueueSyncRequest(KSession& session, | 78 | void ServiceThread::Impl::QueueSyncRequest(KSession& session, |
| @@ -88,12 +98,9 @@ void ServiceThread::Impl::QueueSyncRequest(KSession& session, | |||
| 88 | } | 98 | } |
| 89 | 99 | ||
| 90 | ServiceThread::Impl::~Impl() { | 100 | ServiceThread::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. |
| 309 | static ResultCode SendSyncRequest(Core::System& system, Handle handle) { | 311 | static 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 | ||
| 332 | static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { | 337 | static 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 | ||
| 1206 | constexpr bool IsValidMapCodeMemoryPermission(Svc::MemoryPermission perm) { | ||
| 1207 | return perm == Svc::MemoryPermission::ReadWrite; | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | constexpr bool IsValidMapToOwnerCodeMemoryPermission(Svc::MemoryPermission perm) { | ||
| 1211 | return perm == Svc::MemoryPermission::Read || perm == Svc::MemoryPermission::ReadExecute; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | constexpr bool IsValidUnmapCodeMemoryPermission(Svc::MemoryPermission perm) { | ||
| 1215 | return perm == Svc::MemoryPermission::None; | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(Svc::MemoryPermission perm) { | ||
| 1219 | return perm == Svc::MemoryPermission::None; | ||
| 1220 | } | ||
| 1221 | |||
| 1200 | } // Anonymous namespace | 1222 | } // Anonymous namespace |
| 1201 | 1223 | ||
| 1202 | static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, | 1224 | static 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 | ||
| 1331 | static 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 | |||
| 1371 | static 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 | |||
| 1406 | static 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 | |||
| 1441 | static 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 | |||
| 1309 | static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, | 1520 | static 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 | ||
| 77 | template <ResultCode func(Core::System&, u64, u32, u64, u64)> | ||
| 78 | void 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 | ||
| 85 | template <ResultCode func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)> | ||
| 86 | void 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 | |||
| 76 | template <ResultCode func(Core::System&, u32*)> | 93 | template <ResultCode func(Core::System&, u32*)> |
| 77 | void SvcWrap64(Core::System& system) { | 94 | void 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 | ||
| 322 | template <ResultCode func(Core::System&, Handle*, u64, u64)> | ||
| 323 | void SvcWrap64(Core::System& system) { | ||
| 324 | u32 param_1 = 0; | ||
| 325 | const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2)).raw; | ||
| 326 | |||
| 327 | system.CurrentArmInterface().SetReg(1, param_1); | ||
| 328 | FuncReturn(system, retval); | ||
| 329 | } | ||
| 330 | |||
| 304 | template <ResultCode func(Core::System&, Handle*, u64, u32, u32)> | 331 | template <ResultCode func(Core::System&, Handle*, u64, u32, u32)> |
| 305 | void SvcWrap64(Core::System& system) { | 332 | void 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 | ||
| 12 | namespace Service::Glue { | 13 | namespace 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 | |||
| 8 | namespace Service::Glue { | ||
| 9 | |||
| 10 | NOTIF_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 | |||
| 25 | NOTIF_A::~NOTIF_A() = default; | ||
| 26 | |||
| 27 | void 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 | |||
| 38 | void 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 | |||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Service::Glue { | ||
| 14 | |||
| 15 | class NOTIF_A final : public ServiceFramework<NOTIF_A> { | ||
| 16 | public: | ||
| 17 | explicit NOTIF_A(Core::System& system_); | ||
| 18 | ~NOTIF_A() override; | ||
| 19 | |||
| 20 | private: | ||
| 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 | ||
| 690 | void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, | 700 | void 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 | ||
| 703 | bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, | 769 | bool 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 | ||
| 1040 | void Controller_NPad::StartLRAssignmentMode() { | 1159 | void 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 | ||
| 987 | void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { | 988 | void 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 | ||
| 67 | void nvhost_nvdec::OnClose(DeviceFD fd) { | 71 | void 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 | |||
| 28 | private: | ||
| 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 | ||
| 62 | NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) { | 62 | NvResult 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(¶ms, input.data(), sizeof(IoctlSubmit)); | 65 | std::memcpy(¶ms, 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(), ¶ms, sizeof(IoctlSubmit)); | 99 | std::memcpy(output.data(), ¶ms, 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 | |||
| 65 | void nvhost_vic::OnOpen(DeviceFD fd) {} | 68 | void nvhost_vic::OnOpen(DeviceFD fd) {} |
| 66 | 69 | ||
| 67 | void nvhost_vic::OnClose(DeviceFD fd) { | 70 | void 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 | |||
| 27 | private: | ||
| 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 | ||
| 72 | GCAdapter::GCAdapter(const std::string& input_engine_) : InputEngine(input_engine_) { | 72 | GCAdapter::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 | ||
| 328 | Common::Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, | 328 | Common::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 { | |||
| 22 | class LibUSBContext; | 22 | class LibUSBContext; |
| 23 | class LibUSBDeviceHandle; | 23 | class LibUSBDeviceHandle; |
| 24 | 24 | ||
| 25 | class GCAdapter : public InputCommon::InputEngine { | 25 | class GCAdapter : public InputEngine { |
| 26 | public: | 26 | public: |
| 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 | ||
| 27 | Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { | 27 | Keyboard::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 | */ |
| 15 | class Keyboard final : public InputCommon::InputEngine { | 15 | class Keyboard final : public InputEngine { |
| 16 | public: | 16 | public: |
| 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 | ||
| 27 | Mouse::Mouse(const std::string& input_engine_) : InputEngine(input_engine_) { | 27 | Mouse::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 | */ |
| 30 | class Mouse final : public InputCommon::InputEngine { | 30 | class Mouse final : public InputEngine { |
| 31 | public: | 31 | public: |
| 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 | ||
| 390 | SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engine_) { | 390 | SDLDriver::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 | } |
| 494 | Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, | 495 | |
| 495 | const Common::Input::VibrationStatus vibration) { | 496 | Common::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 | |||
| 529 | Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, | 532 | Common::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; | |||
| 19 | using SDL_Joystick = struct _SDL_Joystick; | 19 | using SDL_Joystick = struct _SDL_Joystick; |
| 20 | using SDL_JoystickID = s32; | 20 | using SDL_JoystickID = s32; |
| 21 | 21 | ||
| 22 | namespace InputCommon { | ||
| 23 | |||
| 24 | class SDLJoystick; | ||
| 25 | |||
| 22 | using ButtonBindings = | 26 | using ButtonBindings = |
| 23 | std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>; | 27 | std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>; |
| 24 | using ZButtonBindings = | 28 | using 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 | ||
| 27 | namespace InputCommon { | 31 | class SDLDriver : public InputEngine { |
| 28 | |||
| 29 | class SDLJoystick; | ||
| 30 | |||
| 31 | class SDLDriver : public InputCommon::InputEngine { | ||
| 32 | public: | 32 | public: |
| 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 | ||
| 64 | private: | 64 | private: |
| 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 | ||
| 16 | namespace InputCommon::TasInput { | 15 | namespace InputCommon::TasInput { |
| 17 | 16 | ||
| 18 | enum TasAxes : u8 { | 17 | enum 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 | ||
| 50 | Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engine_) { | 49 | Tas::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 | ||
| 67 | Tas::~Tas() { | 66 | Tas::~Tas() { |
| 68 | Stop(); | 67 | Stop(); |
| 69 | }; | 68 | } |
| 70 | 69 | ||
| 71 | void Tas::LoadTasFiles() { | 70 | void Tas::LoadTasFiles() { |
| 72 | script_length = 0; | 71 | script_length = 0; |
| @@ -79,43 +78,43 @@ void Tas::LoadTasFiles() { | |||
| 79 | } | 78 | } |
| 80 | 79 | ||
| 81 | void Tas::LoadTasFile(size_t player_index, size_t file_index) { | 80 | void 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 | ||
| 126 | void Tas::WriteTasFile(std::u8string file_name) { | 125 | void 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 | ||
| 226 | TasAnalog Tas::ReadCommandAxis(const std::string& line) const { | 226 | TasAnalog 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 | ||
| 241 | u64 Tas::ReadCommandButtons(const std::string& data) const { | 242 | u64 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 | ||
| 256 | std::string Tas::WriteCommandButtons(u64 buttons) const { | 257 | std::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 | ||
| 271 | void Tas::SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value) { | ||
| 272 | SetAxis(identifier, static_cast<int>(axis), value); | ||
| 273 | } | ||
| 274 | |||
| 270 | void Tas::StartStop() { | 275 | void 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 | /* |
| 15 | To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below | 15 | To 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 | ||
| 84 | class Tas final : public InputCommon::InputEngine { | 84 | class Tas final : public InputEngine { |
| 85 | public: | 85 | public: |
| 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 | ||
| 130 | private: | 130 | private: |
| 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 | ||
| 16 | TouchScreen::TouchScreen(const std::string& input_engine_) : InputEngine(input_engine_) { | 16 | TouchScreen::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 | */ |
| 15 | class TouchScreen final : public InputCommon::InputEngine { | 15 | class TouchScreen final : public InputEngine { |
| 16 | public: | 16 | public: |
| 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 | ||
| 139 | UDPClient::UDPClient(const std::string& input_engine_) : InputEngine(input_engine_) { | 139 | UDPClient::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 | */ |
| 52 | class UDPClient final : public InputCommon::InputEngine { | 52 | class UDPClient final : public InputEngine { |
| 53 | public: | 53 | public: |
| 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 | ||
| 11 | void InputEngine::PreSetController(const PadIdentifier& identifier) { | 11 | void 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 | ||
| 18 | void InputEngine::PreSetButton(const PadIdentifier& identifier, int button) { | 16 | void 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 | ||
| 26 | void InputEngine::PreSetHatButton(const PadIdentifier& identifier, int button) { | 22 | void 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 | ||
| 34 | void InputEngine::PreSetAxis(const PadIdentifier& identifier, int axis) { | 28 | void 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 | ||
| 42 | void InputEngine::PreSetMotion(const PadIdentifier& identifier, int motion) { | 34 | void 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 | ||
| 50 | void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool value) { | 40 | void 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 | ||
| 94 | void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value) { | 84 | void 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 | ||
| 105 | bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const { | 95 | bool 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 | ||
| 120 | bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const { | 112 | bool 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 | ||
| 135 | f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const { | 129 | f32 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 | ||
| 150 | BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const { | 146 | BatteryLevel 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 | ||
| 161 | BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const { | 158 | BasicMotion 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 | ||
| 172 | void InputEngine::ResetButtonState() { | 170 | void 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 | ||
| 183 | void InputEngine::ResetAnalogState() { | 181 | void 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 | ||
| 191 | void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value) { | 189 | void 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 | ||
| 219 | void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value) { | 217 | void 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 | ||
| 248 | void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value) { | 246 | void 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, | |||
| 274 | void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier, | 272 | void 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 | ||
| 288 | void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion, | 286 | void 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 | ||
| 343 | int InputEngine::SetCallback(InputIdentifier input_identifier) { | 341 | int 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 |
| 27 | struct BasicMotion { | 27 | struct 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 | ||
| 103 | class InputEngine { | 103 | class InputEngine { |
| 104 | public: | 104 | public: |
| 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 | ||
| 35 | private: | 35 | private: |
| 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 | ||
| 13 | class DummyInput final : public Common::Input::InputDevice { | 13 | class DummyInput final : public Common::Input::InputDevice { |
| 14 | public: | 14 | public: |
| 15 | explicit DummyInput() {} | 15 | explicit DummyInput() = default; |
| 16 | ~DummyInput() {} | ||
| 17 | }; | 16 | }; |
| 18 | 17 | ||
| 19 | class InputFromButton final : public Common::Input::InputDevice { | 18 | class 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 | ||
| 14 | namespace InputCommon { | 14 | namespace InputCommon { |
| 15 | class InputEngine; | 15 | class InputEngine; |
| 16 | /** | ||
| 17 | * An Input factory. It receives input events and forward them to all input devices it created. | ||
| 18 | */ | ||
| 19 | 16 | ||
| 20 | class OutputFactory final : public Common::Input::Factory<Common::Input::OutputDevice> { | 17 | class OutputFactory final : public Common::Input::Factory<Common::Input::OutputDevice> { |
| 21 | public: | 18 | public: |
| @@ -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 | */ | ||
| 39 | class InputFactory final : public Common::Input::Factory<Common::Input::InputDevice> { | 39 | class InputFactory final : public Common::Input::Factory<Common::Input::InputDevice> { |
| 40 | public: | 40 | public: |
| 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 @@ | |||
| 1 | add_library(shader_recompiler STATIC | 1 | add_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 | |||
| 8 | namespace Shader::Backend::GLASM { | ||
| 9 | |||
| 10 | void EmitBarrier(EmitContext& ctx) { | ||
| 11 | ctx.Add("BAR;"); | ||
| 12 | } | ||
| 13 | |||
| 14 | void EmitWorkgroupMemoryBarrier(EmitContext& ctx) { | ||
| 15 | ctx.Add("MEMBAR.CTA;"); | ||
| 16 | } | ||
| 17 | |||
| 18 | void 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 | ||
| 9 | namespace Shader::Backend::GLASM { | 9 | namespace 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 | ||
| 9 | namespace Shader::Backend::GLASM { | 9 | namespace 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 | ||
| 338 | void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst) { | ||
| 339 | ctx.Add("MOV.S {},invocation.groupid;", inst); | ||
| 340 | } | ||
| 341 | |||
| 342 | void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst) { | ||
| 343 | ctx.Add("MOV.S {},invocation.localid;", inst); | ||
| 344 | } | ||
| 345 | |||
| 346 | void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) { | ||
| 347 | ctx.Add("MOV.S {}.x,primitive_invocation.x;", inst); | ||
| 348 | } | ||
| 349 | |||
| 350 | void EmitSampleId(EmitContext& ctx, IR::Inst& inst) { | ||
| 351 | ctx.Add("MOV.S {}.x,fragment.sampleid.x;", inst); | ||
| 352 | } | ||
| 353 | |||
| 354 | void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst) { | ||
| 355 | ctx.Add("MOV.S {}.x,fragment.helperthread.x;", inst); | ||
| 356 | } | ||
| 357 | |||
| 358 | void 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 | |||
| 363 | void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) { | ||
| 364 | ctx.Add("MOV.F {}.x,scaling[0].z;", inst); | ||
| 365 | } | ||
| 366 | |||
| 338 | void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, ScalarU32 word_offset) { | 367 | void 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 | |||
| 8 | namespace Shader::Backend::GLASM { | ||
| 9 | |||
| 10 | void EmitJoin(EmitContext&) { | ||
| 11 | throw NotImplementedException("Join shouldn't be emitted"); | ||
| 12 | } | ||
| 13 | |||
| 14 | void 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 | ||
| 9 | namespace Shader::Backend::GLASM { | 9 | namespace 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 | |||
| 8 | namespace Shader::Backend::GLASM { | ||
| 9 | |||
| 10 | void EmitLogicalOr(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) { | ||
| 11 | ctx.Add("OR.S {},{},{};", inst, a, b); | ||
| 12 | } | ||
| 13 | |||
| 14 | void EmitLogicalAnd(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) { | ||
| 15 | ctx.Add("AND.S {},{},{};", inst, a, b); | ||
| 16 | } | ||
| 17 | |||
| 18 | void EmitLogicalXor(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) { | ||
| 19 | ctx.Add("XOR.S {},{},{};", inst, a, b); | ||
| 20 | } | ||
| 21 | |||
| 22 | void 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 | ||
| 20 | static 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 | |||
| 36 | void 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 | |||
| 47 | void EmitVoid(EmitContext&) {} | ||
| 48 | |||
| 49 | void EmitReference(EmitContext& ctx, const IR::Value& value) { | ||
| 50 | ctx.reg_alloc.Consume(value); | ||
| 51 | } | ||
| 52 | |||
| 53 | void 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 | |||
| 80 | void EmitJoin(EmitContext& ctx) { | ||
| 81 | NotImplemented(); | ||
| 82 | } | ||
| 83 | |||
| 84 | void EmitDemoteToHelperInvocation(EmitContext& ctx) { | ||
| 85 | ctx.Add("KIL TR.x;"); | ||
| 86 | } | ||
| 87 | |||
| 88 | void EmitBarrier(EmitContext& ctx) { | ||
| 89 | ctx.Add("BAR;"); | ||
| 90 | } | ||
| 91 | |||
| 92 | void EmitWorkgroupMemoryBarrier(EmitContext& ctx) { | ||
| 93 | ctx.Add("MEMBAR.CTA;"); | ||
| 94 | } | ||
| 95 | |||
| 96 | void EmitDeviceMemoryBarrier(EmitContext& ctx) { | ||
| 97 | ctx.Add("MEMBAR;"); | ||
| 98 | } | ||
| 99 | |||
| 100 | void EmitPrologue(EmitContext& ctx) { | ||
| 101 | // TODO | ||
| 102 | } | ||
| 103 | |||
| 104 | void EmitEpilogue(EmitContext& ctx) { | ||
| 105 | // TODO | ||
| 106 | } | ||
| 107 | |||
| 108 | void 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 | |||
| 116 | void 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 | |||
| 124 | void EmitGetRegister(EmitContext& ctx) { | 20 | void 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 | ||
| 188 | void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst) { | ||
| 189 | ctx.Add("MOV.S {},invocation.groupid;", inst); | ||
| 190 | } | ||
| 191 | |||
| 192 | void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst) { | ||
| 193 | ctx.Add("MOV.S {},invocation.localid;", inst); | ||
| 194 | } | ||
| 195 | |||
| 196 | void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) { | ||
| 197 | ctx.Add("MOV.S {}.x,primitive_invocation.x;", inst); | ||
| 198 | } | ||
| 199 | |||
| 200 | void EmitSampleId(EmitContext& ctx, IR::Inst& inst) { | ||
| 201 | ctx.Add("MOV.S {}.x,fragment.sampleid.x;", inst); | ||
| 202 | } | ||
| 203 | |||
| 204 | void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst) { | ||
| 205 | ctx.Add("MOV.S {}.x,fragment.helperthread.x;", inst); | ||
| 206 | } | ||
| 207 | |||
| 208 | void 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 | |||
| 213 | void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) { | ||
| 214 | ctx.Add("MOV.F {}.x,scaling[0].z;", inst); | ||
| 215 | } | ||
| 216 | |||
| 217 | void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) { | ||
| 218 | ctx.Add("MOV.S {}.x,0;", inst); | ||
| 219 | } | ||
| 220 | |||
| 221 | void EmitUndefU8(EmitContext& ctx, IR::Inst& inst) { | ||
| 222 | ctx.Add("MOV.S {}.x,0;", inst); | ||
| 223 | } | ||
| 224 | |||
| 225 | void EmitUndefU16(EmitContext& ctx, IR::Inst& inst) { | ||
| 226 | ctx.Add("MOV.S {}.x,0;", inst); | ||
| 227 | } | ||
| 228 | |||
| 229 | void EmitUndefU32(EmitContext& ctx, IR::Inst& inst) { | ||
| 230 | ctx.Add("MOV.S {}.x,0;", inst); | ||
| 231 | } | ||
| 232 | |||
| 233 | void EmitUndefU64(EmitContext& ctx, IR::Inst& inst) { | ||
| 234 | ctx.LongAdd("MOV.S64 {}.x,0;", inst); | ||
| 235 | } | ||
| 236 | |||
| 237 | void EmitGetZeroFromOp(EmitContext& ctx) { | 84 | void 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 | ||
| 261 | void EmitLogicalOr(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) { | ||
| 262 | ctx.Add("OR.S {},{},{};", inst, a, b); | ||
| 263 | } | ||
| 264 | |||
| 265 | void EmitLogicalAnd(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) { | ||
| 266 | ctx.Add("AND.S {},{},{};", inst, a, b); | ||
| 267 | } | ||
| 268 | |||
| 269 | void EmitLogicalXor(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) { | ||
| 270 | ctx.Add("XOR.S {},{},{};", inst, a, b); | ||
| 271 | } | ||
| 272 | |||
| 273 | void 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 | ||
| 10 | namespace Shader::Backend::GLASM { | 10 | namespace 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 | ||
| 10 | namespace Shader::Backend::GLASM { | 10 | namespace 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 | |||
| 9 | namespace Shader::Backend::GLASM { | ||
| 10 | |||
| 11 | static 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 | |||
| 27 | void 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 | |||
| 38 | void EmitVoid(EmitContext&) {} | ||
| 39 | |||
| 40 | void EmitReference(EmitContext& ctx, const IR::Value& value) { | ||
| 41 | ctx.reg_alloc.Consume(value); | ||
| 42 | } | ||
| 43 | |||
| 44 | void 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 | |||
| 71 | void EmitPrologue(EmitContext&) { | ||
| 72 | // TODO | ||
| 73 | } | ||
| 74 | |||
| 75 | void EmitEpilogue(EmitContext&) { | ||
| 76 | // TODO | ||
| 77 | } | ||
| 78 | |||
| 79 | void 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 | |||
| 87 | void 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 | |||
| 8 | namespace Shader::Backend::GLASM { | ||
| 9 | |||
| 10 | void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) { | ||
| 11 | ctx.Add("MOV.S {}.x,0;", inst); | ||
| 12 | } | ||
| 13 | |||
| 14 | void EmitUndefU8(EmitContext& ctx, IR::Inst& inst) { | ||
| 15 | ctx.Add("MOV.S {}.x,0;", inst); | ||
| 16 | } | ||
| 17 | |||
| 18 | void EmitUndefU16(EmitContext& ctx, IR::Inst& inst) { | ||
| 19 | ctx.Add("MOV.S {}.x,0;", inst); | ||
| 20 | } | ||
| 21 | |||
| 22 | void EmitUndefU32(EmitContext& ctx, IR::Inst& inst) { | ||
| 23 | ctx.Add("MOV.S {}.x,0;", inst); | ||
| 24 | } | ||
| 25 | |||
| 26 | void 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 | ||
| 17 | namespace Shader::Backend::GLSL { | 17 | namespace 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 | ||
| 11 | namespace Shader::Backend::GLSL { | 11 | namespace 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 | ||
| 9 | namespace Shader::Backend::GLSL { | 9 | namespace 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 | ||
| 11 | namespace Shader::Backend::GLSL { | 11 | namespace 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 | ||
| 11 | namespace Shader::Backend::GLSL { | 11 | namespace 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 | ||
| 11 | namespace Shader::Backend::GLSL { | 11 | namespace 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 | ||
| 11 | namespace Shader::Backend::GLSL { | 11 | namespace 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 | ||
| 11 | namespace Shader::Backend::GLSL { | 11 | namespace 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 | ||
| 11 | namespace Shader::Backend::GLSL { | 11 | namespace 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 | ||
| 11 | namespace Shader::Backend::GLSL { | 11 | namespace 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 | ||
| 11 | namespace Shader::Backend::GLSL { | 11 | namespace 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 | ||
| 10 | namespace Shader::Backend::GLSL { | 10 | namespace 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 | ||
| 17 | namespace Shader::Backend::SPIRV { | 15 | namespace 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 | ||
| 8 | namespace Shader::Backend::SPIRV { | 9 | namespace Shader::Backend::SPIRV { |
| 9 | namespace { | 10 | namespace { |
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 | ||
| 9 | namespace Shader::Backend::SPIRV { | 10 | namespace 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 | ||
| 8 | namespace Shader::Backend::SPIRV { | 9 | namespace 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 | ||
| 9 | namespace Shader::Backend::SPIRV { | 10 | namespace 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 | ||
| 11 | namespace Shader::Backend::SPIRV { | 12 | namespace Shader::Backend::SPIRV { |
| 12 | namespace { | 13 | namespace { |
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 | ||
| 8 | namespace Shader::Backend::SPIRV { | 9 | namespace 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 | ||
| 8 | namespace Shader::Backend::SPIRV { | 9 | namespace Shader::Backend::SPIRV { |
| 9 | namespace { | 10 | namespace { |
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 | ||
| 9 | namespace Shader::Backend::SPIRV { | 10 | namespace 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 | ||
| 11 | namespace Shader::Backend::SPIRV { | 12 | namespace 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 | ||
| 9 | namespace Shader::Backend::SPIRV { | 10 | namespace 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 | ||
| 8 | namespace Shader::Backend::SPIRV { | 9 | namespace Shader::Backend::SPIRV { |
| 9 | namespace { | 10 | namespace { |
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 | ||
| 8 | namespace Shader::Backend::SPIRV { | 9 | namespace 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 | ||
| 10 | namespace Shader::Backend::SPIRV { | 11 | namespace Shader::Backend::SPIRV { |
| 11 | namespace { | 12 | namespace { |
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 | ||
| 8 | namespace Shader::Backend::SPIRV { | 9 | namespace 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 | ||
| 8 | namespace Shader::Backend::SPIRV { | 9 | namespace Shader::Backend::SPIRV { |
| 9 | namespace { | 10 | namespace { |
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 | ||
| 8 | namespace Shader::Backend::SPIRV { | 9 | namespace Shader::Backend::SPIRV { |
| 9 | namespace { | 10 | namespace { |
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 | ||
| 8 | namespace Shader::Backend::SPIRV { | 9 | namespace 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 | ||
| 8 | namespace Shader::Backend::SPIRV { | 9 | namespace Shader::Backend::SPIRV { |
| 9 | namespace { | 10 | namespace { |
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 | ||
| 19 | namespace Shader::Backend::SPIRV { | 19 | namespace Shader::Backend::SPIRV { |
| 20 | namespace { | 20 | namespace { |
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 | ||
| 814 | Tegra::CDmaPusher& GPU::CDmaPusher() { | ||
| 815 | return impl->CDmaPusher(); | ||
| 816 | } | ||
| 817 | |||
| 818 | const Tegra::CDmaPusher& GPU::CDmaPusher() const { | ||
| 819 | return impl->CDmaPusher(); | ||
| 820 | } | ||
| 821 | |||
| 822 | VideoCore::RendererBase& GPU::Renderer() { | 806 | VideoCore::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 | ||
| 890 | void GPU::PushCommandBuffer(Tegra::ChCommandHeaderList& entries) { | 874 | void GPU::PushCommandBuffer(u32 id, Tegra::ChCommandHeaderList& entries) { |
| 891 | impl->PushCommandBuffer(entries); | 875 | impl->PushCommandBuffer(id, entries); |
| 892 | } | 876 | } |
| 893 | 877 | ||
| 894 | void GPU::ClearCdmaInstance() { | 878 | void GPU::ClearCdmaInstance(u32 id) { |
| 895 | impl->ClearCdmaInstance(); | 879 | impl->ClearCdmaInstance(id); |
| 896 | } | 880 | } |
| 897 | 881 | ||
| 898 | void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | 882 | void 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 | ||
| 165 | void MicroProfileWidget::wheelEvent(QWheelEvent* ev) { | 165 | void 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 | ||
| 138 | using 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 | ||