diff options
Diffstat (limited to 'src')
54 files changed, 586 insertions, 197 deletions
diff --git a/src/common/bit_util.h b/src/common/bit_util.h index eef8c1c5a..f50d3308a 100644 --- a/src/common/bit_util.h +++ b/src/common/bit_util.h | |||
| @@ -46,6 +46,12 @@ template <typename T> | |||
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | template <typename T> | 48 | template <typename T> |
| 49 | requires std::is_unsigned_v<T> | ||
| 50 | [[nodiscard]] constexpr bool IsPow2(T value) { | ||
| 51 | return std::has_single_bit(value); | ||
| 52 | } | ||
| 53 | |||
| 54 | template <typename T> | ||
| 49 | requires std::is_integral_v<T> | 55 | requires std::is_integral_v<T> |
| 50 | [[nodiscard]] T NextPow2(T value) { | 56 | [[nodiscard]] T NextPow2(T value) { |
| 51 | return static_cast<T>(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U))); | 57 | return static_cast<T>(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U))); |
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 62010d762..81b212e4b 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp | |||
| @@ -124,7 +124,10 @@ void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) { | |||
| 124 | 124 | ||
| 125 | // "from" might no longer be valid if the thread was killed | 125 | // "from" might no longer be valid if the thread was killed |
| 126 | if (auto from = weak_from.lock()) { | 126 | if (auto from = weak_from.lock()) { |
| 127 | ASSERT(from->impl->previous_fiber != nullptr); | 127 | if (from->impl->previous_fiber == nullptr) { |
| 128 | ASSERT_MSG(false, "previous_fiber is nullptr!"); | ||
| 129 | return; | ||
| 130 | } | ||
| 128 | from->impl->previous_fiber->impl->context = transfer.fctx; | 131 | from->impl->previous_fiber->impl->context = transfer.fctx; |
| 129 | from->impl->previous_fiber->impl->guard.unlock(); | 132 | from->impl->previous_fiber->impl->guard.unlock(); |
| 130 | from->impl->previous_fiber.reset(); | 133 | from->impl->previous_fiber.reset(); |
diff --git a/src/common/input.h b/src/common/input.h index f775a4c01..f4f9eb30a 100644 --- a/src/common/input.h +++ b/src/common/input.h | |||
| @@ -209,6 +209,13 @@ enum class ButtonNames { | |||
| 209 | Triangle, | 209 | Triangle, |
| 210 | Share, | 210 | Share, |
| 211 | Options, | 211 | Options, |
| 212 | |||
| 213 | // Mouse buttons | ||
| 214 | ButtonMouseWheel, | ||
| 215 | ButtonBackward, | ||
| 216 | ButtonForward, | ||
| 217 | ButtonTask, | ||
| 218 | ButtonExtra, | ||
| 212 | }; | 219 | }; |
| 213 | 220 | ||
| 214 | // Callback data consisting of an input type and the equivalent data status | 221 | // Callback data consisting of an input type and the equivalent data status |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b1a746727..6e8d11919 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -247,6 +247,9 @@ add_library(core STATIC | |||
| 247 | hle/kernel/k_trace.h | 247 | hle/kernel/k_trace.h |
| 248 | hle/kernel/k_transfer_memory.cpp | 248 | hle/kernel/k_transfer_memory.cpp |
| 249 | hle/kernel/k_transfer_memory.h | 249 | hle/kernel/k_transfer_memory.h |
| 250 | hle/kernel/k_worker_task.h | ||
| 251 | hle/kernel/k_worker_task_manager.cpp | ||
| 252 | hle/kernel/k_worker_task_manager.h | ||
| 250 | hle/kernel/k_writable_event.cpp | 253 | hle/kernel/k_writable_event.cpp |
| 251 | hle/kernel/k_writable_event.h | 254 | hle/kernel/k_writable_event.h |
| 252 | hle/kernel/kernel.cpp | 255 | hle/kernel/kernel.cpp |
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 08f8af551..eef0ff493 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp | |||
| @@ -158,7 +158,7 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) { | |||
| 158 | auto& motion = console.motion_state; | 158 | auto& motion = console.motion_state; |
| 159 | motion.accel = emulated.GetAcceleration(); | 159 | motion.accel = emulated.GetAcceleration(); |
| 160 | motion.gyro = emulated.GetGyroscope(); | 160 | motion.gyro = emulated.GetGyroscope(); |
| 161 | motion.rotation = emulated.GetGyroscope(); | 161 | motion.rotation = emulated.GetRotations(); |
| 162 | motion.orientation = emulated.GetOrientation(); | 162 | motion.orientation = emulated.GetOrientation(); |
| 163 | motion.quaternion = emulated.GetQuaternion(); | 163 | motion.quaternion = emulated.GetQuaternion(); |
| 164 | motion.gyro_bias = emulated.GetGyroBias(); | 164 | motion.gyro_bias = emulated.GetGyroBias(); |
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 13edb7332..d12037b11 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -145,7 +145,7 @@ void EmulatedController::LoadDevices() { | |||
| 145 | motion_devices.begin(), Common::Input::CreateDevice<Common::Input::InputDevice>); | 145 | motion_devices.begin(), Common::Input::CreateDevice<Common::Input::InputDevice>); |
| 146 | std::transform(trigger_params.begin(), trigger_params.end(), trigger_devices.begin(), | 146 | std::transform(trigger_params.begin(), trigger_params.end(), trigger_devices.begin(), |
| 147 | Common::Input::CreateDevice<Common::Input::InputDevice>); | 147 | Common::Input::CreateDevice<Common::Input::InputDevice>); |
| 148 | std::transform(battery_params.begin(), battery_params.begin(), battery_devices.end(), | 148 | std::transform(battery_params.begin(), battery_params.end(), battery_devices.begin(), |
| 149 | Common::Input::CreateDevice<Common::Input::InputDevice>); | 149 | Common::Input::CreateDevice<Common::Input::InputDevice>); |
| 150 | std::transform(output_params.begin(), output_params.end(), output_devices.begin(), | 150 | std::transform(output_params.begin(), output_params.end(), output_devices.begin(), |
| 151 | Common::Input::CreateDevice<Common::Input::OutputDevice>); | 151 | Common::Input::CreateDevice<Common::Input::OutputDevice>); |
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index f5acff6e0..860aab400 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp | |||
| @@ -114,7 +114,7 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu | |||
| 114 | if (TransformToButton(callback).value) { | 114 | if (TransformToButton(callback).value) { |
| 115 | std::random_device device; | 115 | std::random_device device; |
| 116 | std::mt19937 gen(device()); | 116 | std::mt19937 gen(device()); |
| 117 | std::uniform_int_distribution<s16> distribution(-1000, 1000); | 117 | std::uniform_int_distribution<s16> distribution(-5000, 5000); |
| 118 | status.accel.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f; | 118 | status.accel.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f; |
| 119 | status.accel.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f; | 119 | status.accel.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f; |
| 120 | status.accel.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f; | 120 | status.accel.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f; |
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 55e6fb9f7..754b41ff6 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -341,10 +341,6 @@ public: | |||
| 341 | return *thread; | 341 | return *thread; |
| 342 | } | 342 | } |
| 343 | 343 | ||
| 344 | bool IsThreadWaiting() const { | ||
| 345 | return is_thread_waiting; | ||
| 346 | } | ||
| 347 | |||
| 348 | private: | 344 | private: |
| 349 | friend class IPC::ResponseBuilder; | 345 | friend class IPC::ResponseBuilder; |
| 350 | 346 | ||
| @@ -379,7 +375,6 @@ private: | |||
| 379 | u32 domain_offset{}; | 375 | u32 domain_offset{}; |
| 380 | 376 | ||
| 381 | std::shared_ptr<SessionRequestManager> manager; | 377 | std::shared_ptr<SessionRequestManager> manager; |
| 382 | bool is_thread_waiting{}; | ||
| 383 | 378 | ||
| 384 | KernelCore& kernel; | 379 | KernelCore& kernel; |
| 385 | Core::Memory::Memory& memory; | 380 | Core::Memory::Memory& memory; |
diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp index 0166df0a5..1b44541b1 100644 --- a/src/core/hle/kernel/k_memory_manager.cpp +++ b/src/core/hle/kernel/k_memory_manager.cpp | |||
| @@ -8,12 +8,16 @@ | |||
| 8 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/scope_exit.h" | 10 | #include "common/scope_exit.h" |
| 11 | #include "core/core.h" | ||
| 12 | #include "core/device_memory.h" | ||
| 11 | #include "core/hle/kernel/k_memory_manager.h" | 13 | #include "core/hle/kernel/k_memory_manager.h" |
| 12 | #include "core/hle/kernel/k_page_linked_list.h" | 14 | #include "core/hle/kernel/k_page_linked_list.h" |
| 13 | #include "core/hle/kernel/svc_results.h" | 15 | #include "core/hle/kernel/svc_results.h" |
| 14 | 16 | ||
| 15 | namespace Kernel { | 17 | namespace Kernel { |
| 16 | 18 | ||
| 19 | KMemoryManager::KMemoryManager(Core::System& system_) : system{system_} {} | ||
| 20 | |||
| 17 | std::size_t KMemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u64 end_address) { | 21 | std::size_t KMemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u64 end_address) { |
| 18 | const auto size{end_address - start_address}; | 22 | const auto size{end_address - start_address}; |
| 19 | 23 | ||
| @@ -81,7 +85,7 @@ VAddr KMemoryManager::AllocateAndOpenContinuous(std::size_t num_pages, std::size | |||
| 81 | } | 85 | } |
| 82 | 86 | ||
| 83 | ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, | 87 | ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, |
| 84 | Direction dir) { | 88 | Direction dir, u32 heap_fill_value) { |
| 85 | ASSERT(page_list.GetNumPages() == 0); | 89 | ASSERT(page_list.GetNumPages() == 0); |
| 86 | 90 | ||
| 87 | // Early return if we're allocating no pages | 91 | // Early return if we're allocating no pages |
| @@ -139,6 +143,12 @@ ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_ | |||
| 139 | } | 143 | } |
| 140 | } | 144 | } |
| 141 | 145 | ||
| 146 | // Clear allocated memory. | ||
| 147 | for (const auto& it : page_list.Nodes()) { | ||
| 148 | std::memset(system.DeviceMemory().GetPointer(it.GetAddress()), heap_fill_value, | ||
| 149 | it.GetSize()); | ||
| 150 | } | ||
| 151 | |||
| 142 | // Only succeed if we allocated as many pages as we wanted | 152 | // Only succeed if we allocated as many pages as we wanted |
| 143 | if (num_pages) { | 153 | if (num_pages) { |
| 144 | return ResultOutOfMemory; | 154 | return ResultOutOfMemory; |
| @@ -146,11 +156,12 @@ ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_ | |||
| 146 | 156 | ||
| 147 | // We succeeded! | 157 | // We succeeded! |
| 148 | group_guard.Cancel(); | 158 | group_guard.Cancel(); |
| 159 | |||
| 149 | return ResultSuccess; | 160 | return ResultSuccess; |
| 150 | } | 161 | } |
| 151 | 162 | ||
| 152 | ResultCode KMemoryManager::Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, | 163 | ResultCode KMemoryManager::Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, |
| 153 | Direction dir) { | 164 | Direction dir, u32 heap_fill_value) { |
| 154 | // Early return if we're freeing no pages | 165 | // Early return if we're freeing no pages |
| 155 | if (!num_pages) { | 166 | if (!num_pages) { |
| 156 | return ResultSuccess; | 167 | return ResultSuccess; |
diff --git a/src/core/hle/kernel/k_memory_manager.h b/src/core/hle/kernel/k_memory_manager.h index 39badc5f1..abd6c8ace 100644 --- a/src/core/hle/kernel/k_memory_manager.h +++ b/src/core/hle/kernel/k_memory_manager.h | |||
| @@ -12,6 +12,10 @@ | |||
| 12 | #include "core/hle/kernel/k_page_heap.h" | 12 | #include "core/hle/kernel/k_page_heap.h" |
| 13 | #include "core/hle/result.h" | 13 | #include "core/hle/result.h" |
| 14 | 14 | ||
| 15 | namespace Core { | ||
| 16 | class System; | ||
| 17 | } | ||
| 18 | |||
| 15 | namespace Kernel { | 19 | namespace Kernel { |
| 16 | 20 | ||
| 17 | class KPageLinkedList; | 21 | class KPageLinkedList; |
| @@ -42,7 +46,7 @@ public: | |||
| 42 | Mask = (0xF << Shift), | 46 | Mask = (0xF << Shift), |
| 43 | }; | 47 | }; |
| 44 | 48 | ||
| 45 | KMemoryManager() = default; | 49 | explicit KMemoryManager(Core::System& system_); |
| 46 | 50 | ||
| 47 | constexpr std::size_t GetSize(Pool pool) const { | 51 | constexpr std::size_t GetSize(Pool pool) const { |
| 48 | return managers[static_cast<std::size_t>(pool)].GetSize(); | 52 | return managers[static_cast<std::size_t>(pool)].GetSize(); |
| @@ -51,10 +55,10 @@ public: | |||
| 51 | void InitializeManager(Pool pool, u64 start_address, u64 end_address); | 55 | void InitializeManager(Pool pool, u64 start_address, u64 end_address); |
| 52 | 56 | ||
| 53 | VAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option); | 57 | VAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option); |
| 54 | ResultCode Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, | 58 | ResultCode Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, Direction dir, |
| 55 | Direction dir = Direction::FromFront); | 59 | u32 heap_fill_value = 0); |
| 56 | ResultCode Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, | 60 | ResultCode Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, Direction dir, |
| 57 | Direction dir = Direction::FromFront); | 61 | u32 heap_fill_value = 0); |
| 58 | 62 | ||
| 59 | static constexpr std::size_t MaxManagerCount = 10; | 63 | static constexpr std::size_t MaxManagerCount = 10; |
| 60 | 64 | ||
| @@ -129,6 +133,7 @@ private: | |||
| 129 | }; | 133 | }; |
| 130 | 134 | ||
| 131 | private: | 135 | private: |
| 136 | Core::System& system; | ||
| 132 | std::array<std::mutex, static_cast<std::size_t>(Pool::Count)> pool_locks; | 137 | std::array<std::mutex, static_cast<std::size_t>(Pool::Count)> pool_locks; |
| 133 | std::array<Impl, MaxManagerCount> managers; | 138 | std::array<Impl, MaxManagerCount> managers; |
| 134 | }; | 139 | }; |
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 27d86c9a4..b650ea31d 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp | |||
| @@ -289,8 +289,8 @@ ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemory | |||
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | KPageLinkedList page_linked_list; | 291 | KPageLinkedList page_linked_list; |
| 292 | CASCADE_CODE( | 292 | CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool, |
| 293 | system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool)); | 293 | allocation_option)); |
| 294 | CASCADE_CODE(Operate(addr, num_pages, page_linked_list, OperationType::MapGroup)); | 294 | CASCADE_CODE(Operate(addr, num_pages, page_linked_list, OperationType::MapGroup)); |
| 295 | 295 | ||
| 296 | block_manager->Update(addr, num_pages, state, perm); | 296 | block_manager->Update(addr, num_pages, state, perm); |
| @@ -457,8 +457,8 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { | |||
| 457 | 457 | ||
| 458 | KPageLinkedList page_linked_list; | 458 | KPageLinkedList page_linked_list; |
| 459 | 459 | ||
| 460 | CASCADE_CODE( | 460 | CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, |
| 461 | system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, memory_pool)); | 461 | memory_pool, allocation_option)); |
| 462 | 462 | ||
| 463 | // We succeeded, so commit the memory reservation. | 463 | // We succeeded, so commit the memory reservation. |
| 464 | memory_reservation.Commit(); | 464 | memory_reservation.Commit(); |
| @@ -541,7 +541,8 @@ ResultCode KPageTable::UnmapMemory(VAddr addr, std::size_t size) { | |||
| 541 | } | 541 | } |
| 542 | 542 | ||
| 543 | const std::size_t num_pages{size / PageSize}; | 543 | const std::size_t num_pages{size / PageSize}; |
| 544 | system.Kernel().MemoryManager().Free(page_linked_list, num_pages, memory_pool); | 544 | system.Kernel().MemoryManager().Free(page_linked_list, num_pages, memory_pool, |
| 545 | allocation_option); | ||
| 545 | 546 | ||
| 546 | block_manager->Update(addr, num_pages, KMemoryState::Free); | 547 | block_manager->Update(addr, num_pages, KMemoryState::Free); |
| 547 | 548 | ||
| @@ -960,7 +961,7 @@ ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) { | |||
| 960 | // Allocate pages for the heap extension. | 961 | // Allocate pages for the heap extension. |
| 961 | KPageLinkedList page_linked_list; | 962 | KPageLinkedList page_linked_list; |
| 962 | R_TRY(system.Kernel().MemoryManager().Allocate(page_linked_list, allocation_size / PageSize, | 963 | R_TRY(system.Kernel().MemoryManager().Allocate(page_linked_list, allocation_size / PageSize, |
| 963 | memory_pool)); | 964 | memory_pool, allocation_option)); |
| 964 | 965 | ||
| 965 | // Map the pages. | 966 | // Map the pages. |
| 966 | { | 967 | { |
| @@ -1027,8 +1028,8 @@ ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages, | |||
| 1027 | CASCADE_CODE(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr)); | 1028 | CASCADE_CODE(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr)); |
| 1028 | } else { | 1029 | } else { |
| 1029 | KPageLinkedList page_group; | 1030 | KPageLinkedList page_group; |
| 1030 | CASCADE_CODE( | 1031 | CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_group, needed_num_pages, |
| 1031 | system.Kernel().MemoryManager().Allocate(page_group, needed_num_pages, memory_pool)); | 1032 | memory_pool, allocation_option)); |
| 1032 | CASCADE_CODE(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup)); | 1033 | CASCADE_CODE(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup)); |
| 1033 | } | 1034 | } |
| 1034 | 1035 | ||
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 274644181..f67986e91 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h | |||
| @@ -303,6 +303,7 @@ private: | |||
| 303 | bool is_aslr_enabled{}; | 303 | bool is_aslr_enabled{}; |
| 304 | 304 | ||
| 305 | KMemoryManager::Pool memory_pool{KMemoryManager::Pool::Application}; | 305 | KMemoryManager::Pool memory_pool{KMemoryManager::Pool::Application}; |
| 306 | KMemoryManager::Direction allocation_option{KMemoryManager::Direction::FromFront}; | ||
| 306 | 307 | ||
| 307 | Common::PageTable page_table_impl; | 308 | Common::PageTable page_table_impl; |
| 308 | 309 | ||
diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h index f4d71ad7e..0b894c8cf 100644 --- a/src/core/hle/kernel/k_priority_queue.h +++ b/src/core/hle/kernel/k_priority_queue.h | |||
| @@ -45,6 +45,7 @@ concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) { | |||
| 45 | 45 | ||
| 46 | { t.GetActiveCore() } -> Common::ConvertibleTo<s32>; | 46 | { t.GetActiveCore() } -> Common::ConvertibleTo<s32>; |
| 47 | { t.GetPriority() } -> Common::ConvertibleTo<s32>; | 47 | { t.GetPriority() } -> Common::ConvertibleTo<s32>; |
| 48 | { t.IsDummyThread() } -> Common::ConvertibleTo<bool>; | ||
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority> | 51 | template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority> |
| @@ -349,24 +350,49 @@ public: | |||
| 349 | 350 | ||
| 350 | // Mutators. | 351 | // Mutators. |
| 351 | constexpr void PushBack(Member* member) { | 352 | constexpr void PushBack(Member* member) { |
| 353 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 354 | if (member->IsDummyThread()) { | ||
| 355 | return; | ||
| 356 | } | ||
| 357 | |||
| 352 | this->PushBack(member->GetPriority(), member); | 358 | this->PushBack(member->GetPriority(), member); |
| 353 | } | 359 | } |
| 354 | 360 | ||
| 355 | constexpr void Remove(Member* member) { | 361 | constexpr void Remove(Member* member) { |
| 362 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 363 | if (member->IsDummyThread()) { | ||
| 364 | return; | ||
| 365 | } | ||
| 366 | |||
| 356 | this->Remove(member->GetPriority(), member); | 367 | this->Remove(member->GetPriority(), member); |
| 357 | } | 368 | } |
| 358 | 369 | ||
| 359 | constexpr void MoveToScheduledFront(Member* member) { | 370 | constexpr void MoveToScheduledFront(Member* member) { |
| 371 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 372 | if (member->IsDummyThread()) { | ||
| 373 | return; | ||
| 374 | } | ||
| 375 | |||
| 360 | this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member); | 376 | this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member); |
| 361 | } | 377 | } |
| 362 | 378 | ||
| 363 | constexpr KThread* MoveToScheduledBack(Member* member) { | 379 | constexpr KThread* MoveToScheduledBack(Member* member) { |
| 380 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 381 | if (member->IsDummyThread()) { | ||
| 382 | return {}; | ||
| 383 | } | ||
| 384 | |||
| 364 | return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(), | 385 | return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(), |
| 365 | member); | 386 | member); |
| 366 | } | 387 | } |
| 367 | 388 | ||
| 368 | // First class fancy operations. | 389 | // First class fancy operations. |
| 369 | constexpr void ChangePriority(s32 prev_priority, bool is_running, Member* member) { | 390 | constexpr void ChangePriority(s32 prev_priority, bool is_running, Member* member) { |
| 391 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 392 | if (member->IsDummyThread()) { | ||
| 393 | return; | ||
| 394 | } | ||
| 395 | |||
| 370 | ASSERT(IsValidPriority(prev_priority)); | 396 | ASSERT(IsValidPriority(prev_priority)); |
| 371 | 397 | ||
| 372 | // Remove the member from the queues. | 398 | // Remove the member from the queues. |
| @@ -383,6 +409,11 @@ public: | |||
| 383 | 409 | ||
| 384 | constexpr void ChangeAffinityMask(s32 prev_core, const AffinityMaskType& prev_affinity, | 410 | constexpr void ChangeAffinityMask(s32 prev_core, const AffinityMaskType& prev_affinity, |
| 385 | Member* member) { | 411 | Member* member) { |
| 412 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 413 | if (member->IsDummyThread()) { | ||
| 414 | return; | ||
| 415 | } | ||
| 416 | |||
| 386 | // Get the new information. | 417 | // Get the new information. |
| 387 | const s32 priority = member->GetPriority(); | 418 | const s32 priority = member->GetPriority(); |
| 388 | const AffinityMaskType& new_affinity = member->GetAffinityMask(); | 419 | const AffinityMaskType& new_affinity = member->GetAffinityMask(); |
| @@ -412,6 +443,11 @@ public: | |||
| 412 | } | 443 | } |
| 413 | 444 | ||
| 414 | constexpr void ChangeCore(s32 prev_core, Member* member, bool to_front = false) { | 445 | constexpr void ChangeCore(s32 prev_core, Member* member, bool to_front = false) { |
| 446 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 447 | if (member->IsDummyThread()) { | ||
| 448 | return; | ||
| 449 | } | ||
| 450 | |||
| 415 | // Get the new information. | 451 | // Get the new information. |
| 416 | const s32 new_core = member->GetActiveCore(); | 452 | const s32 new_core = member->GetActiveCore(); |
| 417 | const s32 priority = member->GetPriority(); | 453 | const s32 priority = member->GetPriority(); |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index cca405fed..265ac6fa1 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -149,6 +149,10 @@ ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::st | |||
| 149 | return ResultSuccess; | 149 | return ResultSuccess; |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | void KProcess::DoWorkerTaskImpl() { | ||
| 153 | UNIMPLEMENTED(); | ||
| 154 | } | ||
| 155 | |||
| 152 | KResourceLimit* KProcess::GetResourceLimit() const { | 156 | KResourceLimit* KProcess::GetResourceLimit() const { |
| 153 | return resource_limit; | 157 | return resource_limit; |
| 154 | } | 158 | } |
| @@ -477,7 +481,7 @@ void KProcess::Finalize() { | |||
| 477 | } | 481 | } |
| 478 | 482 | ||
| 479 | // Perform inherited finalization. | 483 | // Perform inherited finalization. |
| 480 | KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize(); | 484 | KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask>::Finalize(); |
| 481 | } | 485 | } |
| 482 | 486 | ||
| 483 | /** | 487 | /** |
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index e7c8b5838..c2a672021 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "core/hle/kernel/k_condition_variable.h" | 15 | #include "core/hle/kernel/k_condition_variable.h" |
| 16 | #include "core/hle/kernel/k_handle_table.h" | 16 | #include "core/hle/kernel/k_handle_table.h" |
| 17 | #include "core/hle/kernel/k_synchronization_object.h" | 17 | #include "core/hle/kernel/k_synchronization_object.h" |
| 18 | #include "core/hle/kernel/k_worker_task.h" | ||
| 18 | #include "core/hle/kernel/process_capability.h" | 19 | #include "core/hle/kernel/process_capability.h" |
| 19 | #include "core/hle/kernel/slab_helpers.h" | 20 | #include "core/hle/kernel/slab_helpers.h" |
| 20 | #include "core/hle/result.h" | 21 | #include "core/hle/result.h" |
| @@ -62,8 +63,7 @@ enum class ProcessStatus { | |||
| 62 | DebugBreak, | 63 | DebugBreak, |
| 63 | }; | 64 | }; |
| 64 | 65 | ||
| 65 | class KProcess final | 66 | class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> { |
| 66 | : public KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject> { | ||
| 67 | KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject); | 67 | KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject); |
| 68 | 68 | ||
| 69 | public: | 69 | public: |
| @@ -345,6 +345,8 @@ public: | |||
| 345 | 345 | ||
| 346 | bool IsSignaled() const override; | 346 | bool IsSignaled() const override; |
| 347 | 347 | ||
| 348 | void DoWorkerTaskImpl(); | ||
| 349 | |||
| 348 | void PinCurrentThread(s32 core_id); | 350 | void PinCurrentThread(s32 core_id); |
| 349 | void UnpinCurrentThread(s32 core_id); | 351 | void UnpinCurrentThread(s32 core_id); |
| 350 | void UnpinThread(KThread* thread); | 352 | void UnpinThread(KThread* thread); |
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 31cec990e..b32d4f285 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp | |||
| @@ -49,8 +49,6 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul | |||
| 49 | if (!must_context_switch || core != current_core) { | 49 | if (!must_context_switch || core != current_core) { |
| 50 | auto& phys_core = kernel.PhysicalCore(core); | 50 | auto& phys_core = kernel.PhysicalCore(core); |
| 51 | phys_core.Interrupt(); | 51 | phys_core.Interrupt(); |
| 52 | } else { | ||
| 53 | must_context_switch = true; | ||
| 54 | } | 52 | } |
| 55 | cores_pending_reschedule &= ~(1ULL << core); | 53 | cores_pending_reschedule &= ~(1ULL << core); |
| 56 | } | 54 | } |
| @@ -408,6 +406,9 @@ void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduli | |||
| 408 | } else { | 406 | } else { |
| 409 | RescheduleCores(kernel, cores_needing_scheduling); | 407 | RescheduleCores(kernel, cores_needing_scheduling); |
| 410 | } | 408 | } |
| 409 | |||
| 410 | // Special case to ensure dummy threads that are waiting block. | ||
| 411 | current_thread->IfDummyThreadTryWait(); | ||
| 411 | } | 412 | } |
| 412 | 413 | ||
| 413 | u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { | 414 | u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { |
| @@ -741,6 +742,12 @@ void KScheduler::ScheduleImpl() { | |||
| 741 | next_thread = idle_thread; | 742 | next_thread = idle_thread; |
| 742 | } | 743 | } |
| 743 | 744 | ||
| 745 | // We never want to schedule a dummy thread, as these are only used by host threads for locking. | ||
| 746 | if (next_thread->GetThreadType() == ThreadType::Dummy) { | ||
| 747 | ASSERT_MSG(false, "Dummy threads should never be scheduled!"); | ||
| 748 | next_thread = idle_thread; | ||
| 749 | } | ||
| 750 | |||
| 744 | // If we're not actually switching thread, there's nothing to do. | 751 | // If we're not actually switching thread, there's nothing to do. |
| 745 | if (next_thread == current_thread.load()) { | 752 | if (next_thread == current_thread.load()) { |
| 746 | previous_thread->EnableDispatch(); | 753 | previous_thread->EnableDispatch(); |
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index d4e4a6b06..4d94eb9cf 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 11 | #include "common/scope_exit.h" | ||
| 12 | #include "core/core_timing.h" | 11 | #include "core/core_timing.h" |
| 13 | #include "core/hle/ipc_helpers.h" | 12 | #include "core/hle/ipc_helpers.h" |
| 14 | #include "core/hle/kernel/hle_ipc.h" | 13 | #include "core/hle/kernel/hle_ipc.h" |
| @@ -123,20 +122,10 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor | |||
| 123 | 122 | ||
| 124 | context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); | 123 | context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); |
| 125 | 124 | ||
| 126 | // In the event that something fails here, stub a result to prevent the game from crashing. | ||
| 127 | // This is a work-around in the event that somehow we process a service request after the | ||
| 128 | // session has been closed by the game. This has been observed to happen rarely in Pokemon | ||
| 129 | // Sword/Shield and is likely a result of us using host threads/scheduling for services. | ||
| 130 | // TODO(bunnei): Find a better solution here. | ||
| 131 | auto error_guard = SCOPE_GUARD({ CompleteSyncRequest(*context); }); | ||
| 132 | |||
| 133 | // Ensure we have a session request handler | 125 | // Ensure we have a session request handler |
| 134 | if (manager->HasSessionRequestHandler(*context)) { | 126 | if (manager->HasSessionRequestHandler(*context)) { |
| 135 | if (auto strong_ptr = manager->GetServiceThread().lock()) { | 127 | if (auto strong_ptr = manager->GetServiceThread().lock()) { |
| 136 | strong_ptr->QueueSyncRequest(*parent, std::move(context)); | 128 | strong_ptr->QueueSyncRequest(*parent, std::move(context)); |
| 137 | |||
| 138 | // We succeeded. | ||
| 139 | error_guard.Cancel(); | ||
| 140 | } else { | 129 | } else { |
| 141 | ASSERT_MSG(false, "strong_ptr is nullptr!"); | 130 | ASSERT_MSG(false, "strong_ptr is nullptr!"); |
| 142 | } | 131 | } |
| @@ -171,13 +160,8 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { | |||
| 171 | convert_to_domain = false; | 160 | convert_to_domain = false; |
| 172 | } | 161 | } |
| 173 | 162 | ||
| 174 | // Some service requests require the thread to block | 163 | // The calling thread is waiting for this request to complete, so wake it up. |
| 175 | { | 164 | context.GetThread().EndWait(result); |
| 176 | KScopedSchedulerLock lock(kernel); | ||
| 177 | if (!context.IsThreadWaiting()) { | ||
| 178 | context.GetThread().EndWait(result); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | 165 | ||
| 182 | return result; | 166 | return result; |
| 183 | } | 167 | } |
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 71e029a3f..f42abb8a1 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include "core/hle/kernel/k_system_control.h" | 30 | #include "core/hle/kernel/k_system_control.h" |
| 31 | #include "core/hle/kernel/k_thread.h" | 31 | #include "core/hle/kernel/k_thread.h" |
| 32 | #include "core/hle/kernel/k_thread_queue.h" | 32 | #include "core/hle/kernel/k_thread_queue.h" |
| 33 | #include "core/hle/kernel/k_worker_task_manager.h" | ||
| 33 | #include "core/hle/kernel/kernel.h" | 34 | #include "core/hle/kernel/kernel.h" |
| 34 | #include "core/hle/kernel/svc_results.h" | 35 | #include "core/hle/kernel/svc_results.h" |
| 35 | #include "core/hle/kernel/time_manager.h" | 36 | #include "core/hle/kernel/time_manager.h" |
| @@ -105,7 +106,7 @@ KThread::~KThread() = default; | |||
| 105 | ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, | 106 | ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, |
| 106 | s32 virt_core, KProcess* owner, ThreadType type) { | 107 | s32 virt_core, KProcess* owner, ThreadType type) { |
| 107 | // Assert parameters are valid. | 108 | // Assert parameters are valid. |
| 108 | ASSERT((type == ThreadType::Main) || | 109 | ASSERT((type == ThreadType::Main) || (type == ThreadType::Dummy) || |
| 109 | (Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority)); | 110 | (Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority)); |
| 110 | ASSERT((owner != nullptr) || (type != ThreadType::User)); | 111 | ASSERT((owner != nullptr) || (type != ThreadType::User)); |
| 111 | ASSERT(0 <= virt_core && virt_core < static_cast<s32>(Common::BitSize<u64>())); | 112 | ASSERT(0 <= virt_core && virt_core < static_cast<s32>(Common::BitSize<u64>())); |
| @@ -139,7 +140,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s | |||
| 139 | UNREACHABLE_MSG("KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type)); | 140 | UNREACHABLE_MSG("KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type)); |
| 140 | break; | 141 | break; |
| 141 | } | 142 | } |
| 142 | thread_type_for_debugging = type; | 143 | thread_type = type; |
| 143 | 144 | ||
| 144 | // Set the ideal core ID and affinity mask. | 145 | // Set the ideal core ID and affinity mask. |
| 145 | virtual_ideal_core_id = virt_core; | 146 | virtual_ideal_core_id = virt_core; |
| @@ -261,7 +262,7 @@ ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uint | |||
| 261 | } | 262 | } |
| 262 | 263 | ||
| 263 | ResultCode KThread::InitializeDummyThread(KThread* thread) { | 264 | ResultCode KThread::InitializeDummyThread(KThread* thread) { |
| 264 | return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Dummy); | 265 | return thread->Initialize({}, {}, {}, DummyThreadPriority, 3, {}, ThreadType::Dummy); |
| 265 | } | 266 | } |
| 266 | 267 | ||
| 267 | ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { | 268 | ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { |
| @@ -332,7 +333,7 @@ void KThread::Finalize() { | |||
| 332 | } | 333 | } |
| 333 | 334 | ||
| 334 | // Perform inherited finalization. | 335 | // Perform inherited finalization. |
| 335 | KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>::Finalize(); | 336 | KSynchronizationObject::Finalize(); |
| 336 | } | 337 | } |
| 337 | 338 | ||
| 338 | bool KThread::IsSignaled() const { | 339 | bool KThread::IsSignaled() const { |
| @@ -376,11 +377,28 @@ void KThread::StartTermination() { | |||
| 376 | 377 | ||
| 377 | // Register terminated dpc flag. | 378 | // Register terminated dpc flag. |
| 378 | RegisterDpc(DpcFlag::Terminated); | 379 | RegisterDpc(DpcFlag::Terminated); |
| 380 | } | ||
| 381 | |||
| 382 | void KThread::FinishTermination() { | ||
| 383 | // Ensure that the thread is not executing on any core. | ||
| 384 | if (parent != nullptr) { | ||
| 385 | for (std::size_t i = 0; i < static_cast<std::size_t>(Core::Hardware::NUM_CPU_CORES); ++i) { | ||
| 386 | KThread* core_thread{}; | ||
| 387 | do { | ||
| 388 | core_thread = kernel.Scheduler(i).GetCurrentThread(); | ||
| 389 | } while (core_thread == this); | ||
| 390 | } | ||
| 391 | } | ||
| 379 | 392 | ||
| 380 | // Close the thread. | 393 | // Close the thread. |
| 381 | this->Close(); | 394 | this->Close(); |
| 382 | } | 395 | } |
| 383 | 396 | ||
| 397 | void KThread::DoWorkerTaskImpl() { | ||
| 398 | // Finish the termination that was begun by Exit(). | ||
| 399 | this->FinishTermination(); | ||
| 400 | } | ||
| 401 | |||
| 384 | void KThread::Pin(s32 current_core) { | 402 | void KThread::Pin(s32 current_core) { |
| 385 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 403 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 386 | 404 | ||
| @@ -417,12 +435,7 @@ void KThread::Pin(s32 current_core) { | |||
| 417 | static_cast<u32>(ThreadState::SuspendShift))); | 435 | static_cast<u32>(ThreadState::SuspendShift))); |
| 418 | 436 | ||
| 419 | // Update our state. | 437 | // Update our state. |
| 420 | const ThreadState old_state = thread_state; | 438 | UpdateState(); |
| 421 | thread_state = static_cast<ThreadState>(GetSuspendFlags() | | ||
| 422 | static_cast<u32>(old_state & ThreadState::Mask)); | ||
| 423 | if (thread_state != old_state) { | ||
| 424 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||
| 425 | } | ||
| 426 | } | 439 | } |
| 427 | 440 | ||
| 428 | // TODO(bunnei): Update our SVC access permissions. | 441 | // TODO(bunnei): Update our SVC access permissions. |
| @@ -463,20 +476,13 @@ void KThread::Unpin() { | |||
| 463 | } | 476 | } |
| 464 | 477 | ||
| 465 | // Allow performing thread suspension (if termination hasn't been requested). | 478 | // Allow performing thread suspension (if termination hasn't been requested). |
| 466 | { | 479 | if (!IsTerminationRequested()) { |
| 467 | // Update our allow flags. | 480 | // Update our allow flags. |
| 468 | if (!IsTerminationRequested()) { | 481 | suspend_allowed_flags |= (1 << (static_cast<u32>(SuspendType::Thread) + |
| 469 | suspend_allowed_flags |= (1 << (static_cast<u32>(SuspendType::Thread) + | 482 | static_cast<u32>(ThreadState::SuspendShift))); |
| 470 | static_cast<u32>(ThreadState::SuspendShift))); | ||
| 471 | } | ||
| 472 | 483 | ||
| 473 | // Update our state. | 484 | // Update our state. |
| 474 | const ThreadState old_state = thread_state; | 485 | UpdateState(); |
| 475 | thread_state = static_cast<ThreadState>(GetSuspendFlags() | | ||
| 476 | static_cast<u32>(old_state & ThreadState::Mask)); | ||
| 477 | if (thread_state != old_state) { | ||
| 478 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||
| 479 | } | ||
| 480 | } | 486 | } |
| 481 | 487 | ||
| 482 | // TODO(bunnei): Update our SVC access permissions. | 488 | // TODO(bunnei): Update our SVC access permissions. |
| @@ -689,12 +695,7 @@ void KThread::Resume(SuspendType type) { | |||
| 689 | ~(1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type))); | 695 | ~(1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type))); |
| 690 | 696 | ||
| 691 | // Update our state. | 697 | // Update our state. |
| 692 | const ThreadState old_state = thread_state; | 698 | this->UpdateState(); |
| 693 | thread_state = static_cast<ThreadState>(GetSuspendFlags() | | ||
| 694 | static_cast<u32>(old_state & ThreadState::Mask)); | ||
| 695 | if (thread_state != old_state) { | ||
| 696 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||
| 697 | } | ||
| 698 | } | 699 | } |
| 699 | 700 | ||
| 700 | void KThread::WaitCancel() { | 701 | void KThread::WaitCancel() { |
| @@ -721,19 +722,22 @@ void KThread::TrySuspend() { | |||
| 721 | ASSERT(GetNumKernelWaiters() == 0); | 722 | ASSERT(GetNumKernelWaiters() == 0); |
| 722 | 723 | ||
| 723 | // Perform the suspend. | 724 | // Perform the suspend. |
| 724 | Suspend(); | 725 | this->UpdateState(); |
| 725 | } | 726 | } |
| 726 | 727 | ||
| 727 | void KThread::Suspend() { | 728 | void KThread::UpdateState() { |
| 728 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 729 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 729 | ASSERT(IsSuspendRequested()); | ||
| 730 | 730 | ||
| 731 | // Set our suspend flags in state. | 731 | // Set our suspend flags in state. |
| 732 | const auto old_state = thread_state; | 732 | const auto old_state = thread_state; |
| 733 | thread_state = static_cast<ThreadState>(GetSuspendFlags()) | (old_state & ThreadState::Mask); | 733 | const auto new_state = |
| 734 | static_cast<ThreadState>(this->GetSuspendFlags()) | (old_state & ThreadState::Mask); | ||
| 735 | thread_state = new_state; | ||
| 734 | 736 | ||
| 735 | // Note the state change in scheduler. | 737 | // Note the state change in scheduler. |
| 736 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | 738 | if (new_state != old_state) { |
| 739 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||
| 740 | } | ||
| 737 | } | 741 | } |
| 738 | 742 | ||
| 739 | void KThread::Continue() { | 743 | void KThread::Continue() { |
| @@ -998,13 +1002,16 @@ ResultCode KThread::Run() { | |||
| 998 | 1002 | ||
| 999 | // If the current thread has been asked to suspend, suspend it and retry. | 1003 | // If the current thread has been asked to suspend, suspend it and retry. |
| 1000 | if (GetCurrentThread(kernel).IsSuspended()) { | 1004 | if (GetCurrentThread(kernel).IsSuspended()) { |
| 1001 | GetCurrentThread(kernel).Suspend(); | 1005 | GetCurrentThread(kernel).UpdateState(); |
| 1002 | continue; | 1006 | continue; |
| 1003 | } | 1007 | } |
| 1004 | 1008 | ||
| 1005 | // If we're not a kernel thread and we've been asked to suspend, suspend ourselves. | 1009 | // If we're not a kernel thread and we've been asked to suspend, suspend ourselves. |
| 1006 | if (IsUserThread() && IsSuspended()) { | 1010 | if (KProcess* owner = this->GetOwnerProcess(); owner != nullptr) { |
| 1007 | Suspend(); | 1011 | if (IsUserThread() && IsSuspended()) { |
| 1012 | this->UpdateState(); | ||
| 1013 | } | ||
| 1014 | owner->IncrementThreadCount(); | ||
| 1008 | } | 1015 | } |
| 1009 | 1016 | ||
| 1010 | // Set our state and finish. | 1017 | // Set our state and finish. |
| @@ -1031,9 +1038,16 @@ void KThread::Exit() { | |||
| 1031 | 1038 | ||
| 1032 | // Disallow all suspension. | 1039 | // Disallow all suspension. |
| 1033 | suspend_allowed_flags = 0; | 1040 | suspend_allowed_flags = 0; |
| 1041 | this->UpdateState(); | ||
| 1042 | |||
| 1043 | // Disallow all suspension. | ||
| 1044 | suspend_allowed_flags = 0; | ||
| 1034 | 1045 | ||
| 1035 | // Start termination. | 1046 | // Start termination. |
| 1036 | StartTermination(); | 1047 | StartTermination(); |
| 1048 | |||
| 1049 | // Register the thread as a work task. | ||
| 1050 | KWorkerTaskManager::AddTask(kernel, KWorkerTaskManager::WorkerType::Exit, this); | ||
| 1037 | } | 1051 | } |
| 1038 | } | 1052 | } |
| 1039 | 1053 | ||
| @@ -1061,12 +1075,46 @@ ResultCode KThread::Sleep(s64 timeout) { | |||
| 1061 | return ResultSuccess; | 1075 | return ResultSuccess; |
| 1062 | } | 1076 | } |
| 1063 | 1077 | ||
| 1078 | void KThread::IfDummyThreadTryWait() { | ||
| 1079 | if (!IsDummyThread()) { | ||
| 1080 | return; | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | if (GetState() != ThreadState::Waiting) { | ||
| 1084 | return; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | // Block until we can grab the lock. | ||
| 1088 | KScopedSpinLock lk{dummy_wait_lock}; | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | void KThread::IfDummyThreadBeginWait() { | ||
| 1092 | if (!IsDummyThread()) { | ||
| 1093 | return; | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | // Ensure the thread will block when IfDummyThreadTryWait is called. | ||
| 1097 | dummy_wait_lock.Lock(); | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | void KThread::IfDummyThreadEndWait() { | ||
| 1101 | if (!IsDummyThread()) { | ||
| 1102 | return; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | // Ensure the thread will no longer block. | ||
| 1106 | dummy_wait_lock.Unlock(); | ||
| 1107 | } | ||
| 1108 | |||
| 1064 | void KThread::BeginWait(KThreadQueue* queue) { | 1109 | void KThread::BeginWait(KThreadQueue* queue) { |
| 1065 | // Set our state as waiting. | 1110 | // Set our state as waiting. |
| 1066 | SetState(ThreadState::Waiting); | 1111 | SetState(ThreadState::Waiting); |
| 1067 | 1112 | ||
| 1068 | // Set our wait queue. | 1113 | // Set our wait queue. |
| 1069 | wait_queue = queue; | 1114 | wait_queue = queue; |
| 1115 | |||
| 1116 | // Special case for dummy threads to ensure they block. | ||
| 1117 | IfDummyThreadBeginWait(); | ||
| 1070 | } | 1118 | } |
| 1071 | 1119 | ||
| 1072 | void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { | 1120 | void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { |
| @@ -1085,7 +1133,16 @@ void KThread::EndWait(ResultCode wait_result_) { | |||
| 1085 | 1133 | ||
| 1086 | // If we're waiting, notify our queue that we're available. | 1134 | // If we're waiting, notify our queue that we're available. |
| 1087 | if (GetState() == ThreadState::Waiting) { | 1135 | if (GetState() == ThreadState::Waiting) { |
| 1136 | if (wait_queue == nullptr) { | ||
| 1137 | // This should never happen, but avoid a hard crash below to get this logged. | ||
| 1138 | ASSERT_MSG(false, "wait_queue is nullptr!"); | ||
| 1139 | return; | ||
| 1140 | } | ||
| 1141 | |||
| 1088 | wait_queue->EndWait(this, wait_result_); | 1142 | wait_queue->EndWait(this, wait_result_); |
| 1143 | |||
| 1144 | // Special case for dummy threads to wakeup if necessary. | ||
| 1145 | IfDummyThreadEndWait(); | ||
| 1089 | } | 1146 | } |
| 1090 | } | 1147 | } |
| 1091 | 1148 | ||
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 83dfde69b..d058db62c 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include "core/hle/kernel/k_light_lock.h" | 19 | #include "core/hle/kernel/k_light_lock.h" |
| 20 | #include "core/hle/kernel/k_spin_lock.h" | 20 | #include "core/hle/kernel/k_spin_lock.h" |
| 21 | #include "core/hle/kernel/k_synchronization_object.h" | 21 | #include "core/hle/kernel/k_synchronization_object.h" |
| 22 | #include "core/hle/kernel/k_worker_task.h" | ||
| 22 | #include "core/hle/kernel/slab_helpers.h" | 23 | #include "core/hle/kernel/slab_helpers.h" |
| 23 | #include "core/hle/kernel/svc_common.h" | 24 | #include "core/hle/kernel/svc_common.h" |
| 24 | #include "core/hle/kernel/svc_types.h" | 25 | #include "core/hle/kernel/svc_types.h" |
| @@ -100,7 +101,7 @@ enum class ThreadWaitReasonForDebugging : u32 { | |||
| 100 | [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); | 101 | [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); |
| 101 | [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); | 102 | [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); |
| 102 | 103 | ||
| 103 | class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>, | 104 | class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>, |
| 104 | public boost::intrusive::list_base_hook<> { | 105 | public boost::intrusive::list_base_hook<> { |
| 105 | KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); | 106 | KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); |
| 106 | 107 | ||
| @@ -111,6 +112,7 @@ private: | |||
| 111 | public: | 112 | public: |
| 112 | static constexpr s32 DefaultThreadPriority = 44; | 113 | static constexpr s32 DefaultThreadPriority = 44; |
| 113 | static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1; | 114 | static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1; |
| 115 | static constexpr s32 DummyThreadPriority = Svc::LowestThreadPriority + 2; | ||
| 114 | 116 | ||
| 115 | explicit KThread(KernelCore& kernel_); | 117 | explicit KThread(KernelCore& kernel_); |
| 116 | ~KThread() override; | 118 | ~KThread() override; |
| @@ -192,9 +194,9 @@ public: | |||
| 192 | 194 | ||
| 193 | void TrySuspend(); | 195 | void TrySuspend(); |
| 194 | 196 | ||
| 195 | void Continue(); | 197 | void UpdateState(); |
| 196 | 198 | ||
| 197 | void Suspend(); | 199 | void Continue(); |
| 198 | 200 | ||
| 199 | constexpr void SetSyncedIndex(s32 index) { | 201 | constexpr void SetSyncedIndex(s32 index) { |
| 200 | synced_index = index; | 202 | synced_index = index; |
| @@ -385,6 +387,8 @@ public: | |||
| 385 | 387 | ||
| 386 | void OnTimer(); | 388 | void OnTimer(); |
| 387 | 389 | ||
| 390 | void DoWorkerTaskImpl(); | ||
| 391 | |||
| 388 | static void PostDestroy(uintptr_t arg); | 392 | static void PostDestroy(uintptr_t arg); |
| 389 | 393 | ||
| 390 | [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread); | 394 | [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread); |
| @@ -550,8 +554,12 @@ public: | |||
| 550 | return wait_reason_for_debugging; | 554 | return wait_reason_for_debugging; |
| 551 | } | 555 | } |
| 552 | 556 | ||
| 553 | [[nodiscard]] ThreadType GetThreadTypeForDebugging() const { | 557 | [[nodiscard]] ThreadType GetThreadType() const { |
| 554 | return thread_type_for_debugging; | 558 | return thread_type; |
| 559 | } | ||
| 560 | |||
| 561 | [[nodiscard]] bool IsDummyThread() const { | ||
| 562 | return GetThreadType() == ThreadType::Dummy; | ||
| 555 | } | 563 | } |
| 556 | 564 | ||
| 557 | void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { | 565 | void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { |
| @@ -628,6 +636,14 @@ public: | |||
| 628 | return condvar_key; | 636 | return condvar_key; |
| 629 | } | 637 | } |
| 630 | 638 | ||
| 639 | // Dummy threads (used for HLE host threads) cannot wait based on the guest scheduler, and | ||
| 640 | // therefore will not block on guest kernel synchronization primitives. These methods handle | ||
| 641 | // blocking as needed. | ||
| 642 | |||
| 643 | void IfDummyThreadTryWait(); | ||
| 644 | void IfDummyThreadBeginWait(); | ||
| 645 | void IfDummyThreadEndWait(); | ||
| 646 | |||
| 631 | private: | 647 | private: |
| 632 | static constexpr size_t PriorityInheritanceCountMax = 10; | 648 | static constexpr size_t PriorityInheritanceCountMax = 10; |
| 633 | union SyncObjectBuffer { | 649 | union SyncObjectBuffer { |
| @@ -679,6 +695,8 @@ private: | |||
| 679 | 695 | ||
| 680 | void StartTermination(); | 696 | void StartTermination(); |
| 681 | 697 | ||
| 698 | void FinishTermination(); | ||
| 699 | |||
| 682 | [[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, | 700 | [[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, |
| 683 | s32 prio, s32 virt_core, KProcess* owner, ThreadType type); | 701 | s32 prio, s32 virt_core, KProcess* owner, ThreadType type); |
| 684 | 702 | ||
| @@ -744,16 +762,17 @@ private: | |||
| 744 | bool resource_limit_release_hint{}; | 762 | bool resource_limit_release_hint{}; |
| 745 | StackParameters stack_parameters{}; | 763 | StackParameters stack_parameters{}; |
| 746 | KSpinLock context_guard{}; | 764 | KSpinLock context_guard{}; |
| 765 | KSpinLock dummy_wait_lock{}; | ||
| 747 | 766 | ||
| 748 | // For emulation | 767 | // For emulation |
| 749 | std::shared_ptr<Common::Fiber> host_context{}; | 768 | std::shared_ptr<Common::Fiber> host_context{}; |
| 750 | bool is_single_core{}; | 769 | bool is_single_core{}; |
| 770 | ThreadType thread_type{}; | ||
| 751 | 771 | ||
| 752 | // For debugging | 772 | // For debugging |
| 753 | std::vector<KSynchronizationObject*> wait_objects_for_debugging; | 773 | std::vector<KSynchronizationObject*> wait_objects_for_debugging; |
| 754 | VAddr mutex_wait_address_for_debugging{}; | 774 | VAddr mutex_wait_address_for_debugging{}; |
| 755 | ThreadWaitReasonForDebugging wait_reason_for_debugging{}; | 775 | ThreadWaitReasonForDebugging wait_reason_for_debugging{}; |
| 756 | ThreadType thread_type_for_debugging{}; | ||
| 757 | 776 | ||
| 758 | public: | 777 | public: |
| 759 | using ConditionVariableThreadTreeType = ConditionVariableThreadTree; | 778 | using ConditionVariableThreadTreeType = ConditionVariableThreadTree; |
diff --git a/src/core/hle/kernel/k_worker_task.h b/src/core/hle/kernel/k_worker_task.h new file mode 100644 index 000000000..b7794c6a8 --- /dev/null +++ b/src/core/hle/kernel/k_worker_task.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | // Copyright 2022 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/kernel/k_synchronization_object.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | class KWorkerTask : public KSynchronizationObject { | ||
| 12 | public: | ||
| 13 | explicit KWorkerTask(KernelCore& kernel_); | ||
| 14 | |||
| 15 | void DoWorkerTask(); | ||
| 16 | }; | ||
| 17 | |||
| 18 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_worker_task_manager.cpp b/src/core/hle/kernel/k_worker_task_manager.cpp new file mode 100644 index 000000000..785e08111 --- /dev/null +++ b/src/core/hle/kernel/k_worker_task_manager.cpp | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | // Copyright 2022 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "core/hle/kernel/k_process.h" | ||
| 7 | #include "core/hle/kernel/k_thread.h" | ||
| 8 | #include "core/hle/kernel/k_worker_task.h" | ||
| 9 | #include "core/hle/kernel/k_worker_task_manager.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | KWorkerTask::KWorkerTask(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} | ||
| 15 | |||
| 16 | void KWorkerTask::DoWorkerTask() { | ||
| 17 | if (auto* const thread = this->DynamicCast<KThread*>(); thread != nullptr) { | ||
| 18 | return thread->DoWorkerTaskImpl(); | ||
| 19 | } else { | ||
| 20 | auto* const process = this->DynamicCast<KProcess*>(); | ||
| 21 | ASSERT(process != nullptr); | ||
| 22 | |||
| 23 | return process->DoWorkerTaskImpl(); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | KWorkerTaskManager::KWorkerTaskManager() : m_waiting_thread(1, "yuzu:KWorkerTaskManager") {} | ||
| 28 | |||
| 29 | void KWorkerTaskManager::AddTask(KernelCore& kernel, WorkerType type, KWorkerTask* task) { | ||
| 30 | ASSERT(type <= WorkerType::Count); | ||
| 31 | kernel.WorkerTaskManager().AddTask(kernel, task); | ||
| 32 | } | ||
| 33 | |||
| 34 | void KWorkerTaskManager::AddTask(KernelCore& kernel, KWorkerTask* task) { | ||
| 35 | KScopedSchedulerLock sl(kernel); | ||
| 36 | m_waiting_thread.QueueWork([task]() { | ||
| 37 | // Do the task. | ||
| 38 | task->DoWorkerTask(); | ||
| 39 | }); | ||
| 40 | } | ||
| 41 | |||
| 42 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_worker_task_manager.h b/src/core/hle/kernel/k_worker_task_manager.h new file mode 100644 index 000000000..43d1bfcec --- /dev/null +++ b/src/core/hle/kernel/k_worker_task_manager.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | // Copyright 2022 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 "common/thread_worker.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | class KernelCore; | ||
| 13 | class KWorkerTask; | ||
| 14 | |||
| 15 | class KWorkerTaskManager final { | ||
| 16 | public: | ||
| 17 | enum class WorkerType : u32 { | ||
| 18 | Exit, | ||
| 19 | Count, | ||
| 20 | }; | ||
| 21 | |||
| 22 | KWorkerTaskManager(); | ||
| 23 | |||
| 24 | static void AddTask(KernelCore& kernel_, WorkerType type, KWorkerTask* task); | ||
| 25 | |||
| 26 | private: | ||
| 27 | void AddTask(KernelCore& kernel, KWorkerTask* task); | ||
| 28 | |||
| 29 | private: | ||
| 30 | Common::ThreadWorker m_waiting_thread; | ||
| 31 | }; | ||
| 32 | |||
| 33 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0b618fb46..49c0714ed 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include "core/hle/kernel/k_shared_memory.h" | 37 | #include "core/hle/kernel/k_shared_memory.h" |
| 38 | #include "core/hle/kernel/k_slab_heap.h" | 38 | #include "core/hle/kernel/k_slab_heap.h" |
| 39 | #include "core/hle/kernel/k_thread.h" | 39 | #include "core/hle/kernel/k_thread.h" |
| 40 | #include "core/hle/kernel/k_worker_task_manager.h" | ||
| 40 | #include "core/hle/kernel/kernel.h" | 41 | #include "core/hle/kernel/kernel.h" |
| 41 | #include "core/hle/kernel/physical_core.h" | 42 | #include "core/hle/kernel/physical_core.h" |
| 42 | #include "core/hle/kernel/service_thread.h" | 43 | #include "core/hle/kernel/service_thread.h" |
| @@ -300,12 +301,10 @@ struct KernelCore::Impl { | |||
| 300 | // Gets the dummy KThread for the caller, allocating a new one if this is the first time | 301 | // Gets the dummy KThread for the caller, allocating a new one if this is the first time |
| 301 | KThread* GetHostDummyThread() { | 302 | KThread* GetHostDummyThread() { |
| 302 | auto make_thread = [this]() { | 303 | auto make_thread = [this]() { |
| 303 | std::lock_guard lk(dummy_thread_lock); | 304 | KThread* thread = KThread::Create(system.Kernel()); |
| 304 | auto& thread = dummy_threads.emplace_back(std::make_unique<KThread>(system.Kernel())); | 305 | ASSERT(KThread::InitializeDummyThread(thread).IsSuccess()); |
| 305 | KAutoObject::Create(thread.get()); | ||
| 306 | ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess()); | ||
| 307 | thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); | 306 | thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); |
| 308 | return thread.get(); | 307 | return thread; |
| 309 | }; | 308 | }; |
| 310 | 309 | ||
| 311 | thread_local KThread* saved_thread = make_thread(); | 310 | thread_local KThread* saved_thread = make_thread(); |
| @@ -630,7 +629,7 @@ struct KernelCore::Impl { | |||
| 630 | const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents(); | 629 | const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents(); |
| 631 | 630 | ||
| 632 | // Initialize memory managers | 631 | // Initialize memory managers |
| 633 | memory_manager = std::make_unique<KMemoryManager>(); | 632 | memory_manager = std::make_unique<KMemoryManager>(system); |
| 634 | memory_manager->InitializeManager(KMemoryManager::Pool::Application, | 633 | memory_manager->InitializeManager(KMemoryManager::Pool::Application, |
| 635 | application_pool.GetAddress(), | 634 | application_pool.GetAddress(), |
| 636 | application_pool.GetEndAddress()); | 635 | application_pool.GetEndAddress()); |
| @@ -730,7 +729,6 @@ struct KernelCore::Impl { | |||
| 730 | std::mutex server_sessions_lock; | 729 | std::mutex server_sessions_lock; |
| 731 | std::mutex registered_objects_lock; | 730 | std::mutex registered_objects_lock; |
| 732 | std::mutex registered_in_use_objects_lock; | 731 | std::mutex registered_in_use_objects_lock; |
| 733 | std::mutex dummy_thread_lock; | ||
| 734 | 732 | ||
| 735 | std::atomic<u32> next_object_id{0}; | 733 | std::atomic<u32> next_object_id{0}; |
| 736 | std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin}; | 734 | std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin}; |
| @@ -787,9 +785,6 @@ struct KernelCore::Impl { | |||
| 787 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; | 785 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; |
| 788 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; | 786 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; |
| 789 | 787 | ||
| 790 | // Specifically tracked to be automatically destroyed with kernel | ||
| 791 | std::vector<std::unique_ptr<KThread>> dummy_threads; | ||
| 792 | |||
| 793 | bool is_multicore{}; | 788 | bool is_multicore{}; |
| 794 | std::atomic_bool is_shutting_down{}; | 789 | std::atomic_bool is_shutting_down{}; |
| 795 | bool is_phantom_mode_for_singlecore{}; | 790 | bool is_phantom_mode_for_singlecore{}; |
| @@ -797,6 +792,8 @@ struct KernelCore::Impl { | |||
| 797 | 792 | ||
| 798 | std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{}; | 793 | std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{}; |
| 799 | 794 | ||
| 795 | KWorkerTaskManager worker_task_manager; | ||
| 796 | |||
| 800 | // System context | 797 | // System context |
| 801 | Core::System& system; | 798 | Core::System& system; |
| 802 | }; | 799 | }; |
| @@ -1137,6 +1134,14 @@ const Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() const { | |||
| 1137 | return impl->slab_resource_counts; | 1134 | return impl->slab_resource_counts; |
| 1138 | } | 1135 | } |
| 1139 | 1136 | ||
| 1137 | KWorkerTaskManager& KernelCore::WorkerTaskManager() { | ||
| 1138 | return impl->worker_task_manager; | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | const KWorkerTaskManager& KernelCore::WorkerTaskManager() const { | ||
| 1142 | return impl->worker_task_manager; | ||
| 1143 | } | ||
| 1144 | |||
| 1140 | bool KernelCore::IsPhantomModeForSingleCore() const { | 1145 | bool KernelCore::IsPhantomModeForSingleCore() const { |
| 1141 | return impl->IsPhantomModeForSingleCore(); | 1146 | return impl->IsPhantomModeForSingleCore(); |
| 1142 | } | 1147 | } |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index b9b423908..0e04fc3bb 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -52,6 +52,7 @@ class KSharedMemory; | |||
| 52 | class KSharedMemoryInfo; | 52 | class KSharedMemoryInfo; |
| 53 | class KThread; | 53 | class KThread; |
| 54 | class KTransferMemory; | 54 | class KTransferMemory; |
| 55 | class KWorkerTaskManager; | ||
| 55 | class KWritableEvent; | 56 | class KWritableEvent; |
| 56 | class KCodeMemory; | 57 | class KCodeMemory; |
| 57 | class PhysicalCore; | 58 | class PhysicalCore; |
| @@ -343,6 +344,12 @@ public: | |||
| 343 | /// Gets the current slab resource counts. | 344 | /// Gets the current slab resource counts. |
| 344 | const Init::KSlabResourceCounts& SlabResourceCounts() const; | 345 | const Init::KSlabResourceCounts& SlabResourceCounts() const; |
| 345 | 346 | ||
| 347 | /// Gets the current worker task manager, used for dispatching KThread/KProcess tasks. | ||
| 348 | KWorkerTaskManager& WorkerTaskManager(); | ||
| 349 | |||
| 350 | /// Gets the current worker task manager, used for dispatching KThread/KProcess tasks. | ||
| 351 | const KWorkerTaskManager& WorkerTaskManager() const; | ||
| 352 | |||
| 346 | private: | 353 | private: |
| 347 | friend class KProcess; | 354 | friend class KProcess; |
| 348 | friend class KThread; | 355 | friend class KThread; |
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index 03f3dec10..4eb3a5988 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "common/scope_exit.h" | 12 | #include "common/scope_exit.h" |
| 13 | #include "common/thread.h" | 13 | #include "common/thread.h" |
| 14 | #include "core/hle/kernel/k_session.h" | 14 | #include "core/hle/kernel/k_session.h" |
| 15 | #include "core/hle/kernel/k_thread.h" | ||
| 15 | #include "core/hle/kernel/kernel.h" | 16 | #include "core/hle/kernel/kernel.h" |
| 16 | #include "core/hle/kernel/service_thread.h" | 17 | #include "core/hle/kernel/service_thread.h" |
| 17 | 18 | ||
| @@ -50,6 +51,10 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std | |||
| 50 | 51 | ||
| 51 | kernel.RegisterHostThread(); | 52 | kernel.RegisterHostThread(); |
| 52 | 53 | ||
| 54 | // Ensure the dummy thread allocated for this host thread is closed on exit. | ||
| 55 | auto* dummy_thread = kernel.GetCurrentEmuThread(); | ||
| 56 | SCOPE_EXIT({ dummy_thread->Close(); }); | ||
| 57 | |||
| 53 | while (true) { | 58 | while (true) { |
| 54 | std::function<void()> task; | 59 | std::function<void()> task; |
| 55 | 60 | ||
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index 94a1b8814..f4034d591 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp | |||
| @@ -37,8 +37,8 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> | |||
| 37 | {130, nullptr, "ActivateOpenContextRetention"}, | 37 | {130, nullptr, "ActivateOpenContextRetention"}, |
| 38 | {140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"}, | 38 | {140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"}, |
| 39 | {150, nullptr, "AuthenticateApplicationAsync"}, | 39 | {150, nullptr, "AuthenticateApplicationAsync"}, |
| 40 | {151, nullptr, "Unknown151"}, | 40 | {151, nullptr, "EnsureSignedDeviceIdentifierCacheForNintendoAccountAsync"}, |
| 41 | {152, nullptr, "Unknown152"}, | 41 | {152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"}, |
| 42 | {190, nullptr, "GetUserLastOpenedApplication"}, | 42 | {190, nullptr, "GetUserLastOpenedApplication"}, |
| 43 | {191, nullptr, "ActivateOpenContextHolder"}, | 43 | {191, nullptr, "ActivateOpenContextHolder"}, |
| 44 | {200, nullptr, "BeginUserRegistration"}, | 44 | {200, nullptr, "BeginUserRegistration"}, |
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index 6ce7fe8e6..991921984 100644 --- a/src/core/hle/service/acc/acc_u1.cpp +++ b/src/core/hle/service/acc/acc_u1.cpp | |||
| @@ -37,8 +37,8 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> | |||
| 37 | {130, nullptr, "ActivateOpenContextRetention"}, | 37 | {130, nullptr, "ActivateOpenContextRetention"}, |
| 38 | {140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"}, | 38 | {140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"}, |
| 39 | {150, nullptr, "AuthenticateApplicationAsync"}, | 39 | {150, nullptr, "AuthenticateApplicationAsync"}, |
| 40 | {151, nullptr, "Unknown151"}, | 40 | {151, nullptr, "EnsureSignedDeviceIdentifierCacheForNintendoAccountAsync"}, |
| 41 | {152, nullptr, "Unknown152"}, | 41 | {152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"}, |
| 42 | {190, nullptr, "GetUserLastOpenedApplication"}, | 42 | {190, nullptr, "GetUserLastOpenedApplication"}, |
| 43 | {191, nullptr, "ActivateOpenContextHolder"}, | 43 | {191, nullptr, "ActivateOpenContextHolder"}, |
| 44 | {997, nullptr, "DebugInvalidateTokenCacheForUser"}, | 44 | {997, nullptr, "DebugInvalidateTokenCacheForUser"}, |
diff --git a/src/core/hle/service/am/omm.cpp b/src/core/hle/service/am/omm.cpp index 55de67e1d..6da9b9f58 100644 --- a/src/core/hle/service/am/omm.cpp +++ b/src/core/hle/service/am/omm.cpp | |||
| @@ -37,6 +37,7 @@ OMM::OMM(Core::System& system_) : ServiceFramework{system_, "omm"} { | |||
| 37 | {25, nullptr, "SetApplicationCecSettingsAndNotifyChanged"}, | 37 | {25, nullptr, "SetApplicationCecSettingsAndNotifyChanged"}, |
| 38 | {26, nullptr, "GetOperationModeSystemInfo"}, | 38 | {26, nullptr, "GetOperationModeSystemInfo"}, |
| 39 | {27, nullptr, "GetAppletFullAwakingSystemEvent"}, | 39 | {27, nullptr, "GetAppletFullAwakingSystemEvent"}, |
| 40 | {28, nullptr, "CreateCradleFirmwareUpdater"}, | ||
| 40 | }; | 41 | }; |
| 41 | // clang-format on | 42 | // clang-format on |
| 42 | 43 | ||
diff --git a/src/core/hle/service/apm/apm_interface.cpp b/src/core/hle/service/apm/apm_interface.cpp index e58bad083..6163e3294 100644 --- a/src/core/hle/service/apm/apm_interface.cpp +++ b/src/core/hle/service/apm/apm_interface.cpp | |||
| @@ -17,7 +17,7 @@ public: | |||
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"}, | 18 | {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"}, |
| 19 | {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"}, | 19 | {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"}, |
| 20 | {2, nullptr, "SetCpuOverclockEnabled"}, | 20 | {2, &ISession::SetCpuOverclockEnabled, "SetCpuOverclockEnabled"}, |
| 21 | }; | 21 | }; |
| 22 | RegisterHandlers(functions); | 22 | RegisterHandlers(functions); |
| 23 | } | 23 | } |
| @@ -47,6 +47,18 @@ private: | |||
| 47 | rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode)); | 47 | rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode)); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | void SetCpuOverclockEnabled(Kernel::HLERequestContext& ctx) { | ||
| 51 | IPC::RequestParser rp{ctx}; | ||
| 52 | |||
| 53 | const auto cpu_overclock_enabled = rp.Pop<bool>(); | ||
| 54 | |||
| 55 | LOG_WARNING(Service_APM, "(STUBBED) called, cpu_overclock_enabled={}", | ||
| 56 | cpu_overclock_enabled); | ||
| 57 | |||
| 58 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 59 | rb.Push(ResultSuccess); | ||
| 60 | } | ||
| 61 | |||
| 50 | Controller& controller; | 62 | Controller& controller; |
| 51 | }; | 63 | }; |
| 52 | 64 | ||
diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp index 2e46e7161..260fd0e0e 100644 --- a/src/core/hle/service/audio/audctl.cpp +++ b/src/core/hle/service/audio/audctl.cpp | |||
| @@ -41,14 +41,14 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} { | |||
| 41 | {27, nullptr, "SetVolumeMappingTableForDev"}, | 41 | {27, nullptr, "SetVolumeMappingTableForDev"}, |
| 42 | {28, nullptr, "GetAudioOutputChannelCountForPlayReport"}, | 42 | {28, nullptr, "GetAudioOutputChannelCountForPlayReport"}, |
| 43 | {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, | 43 | {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, |
| 44 | {30, nullptr, "Unknown30"}, | 44 | {30, nullptr, "SetSpeakerAutoMuteEnabled"}, |
| 45 | {31, nullptr, "Unknown31"}, | 45 | {31, nullptr, "IsSpeakerAutoMuteEnabled"}, |
| 46 | {32, nullptr, "Unknown32"}, | 46 | {32, nullptr, "GetActiveOutputTarget"}, |
| 47 | {33, nullptr, "Unknown33"}, | 47 | {33, nullptr, "GetTargetDeviceInfo"}, |
| 48 | {34, nullptr, "Unknown34"}, | 48 | {34, nullptr, "AcquireTargetNotification"}, |
| 49 | {10000, nullptr, "Unknown10000"}, | 49 | {10000, nullptr, "NotifyAudioOutputTargetForPlayReport"}, |
| 50 | {10001, nullptr, "Unknown10001"}, | 50 | {10001, nullptr, "NotifyAudioOutputChannelCountForPlayReport"}, |
| 51 | {10002, nullptr, "Unknown10002"}, | 51 | {10002, nullptr, "NotifyUnsupportedUsbOutputDeviceAttachedForPlayReport"}, |
| 52 | }; | 52 | }; |
| 53 | // clang-format on | 53 | // clang-format on |
| 54 | 54 | ||
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index d337fd317..cc268d877 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp | |||
| @@ -201,6 +201,22 @@ public: | |||
| 201 | {62, nullptr, "Unknown62"}, | 201 | {62, nullptr, "Unknown62"}, |
| 202 | {63, nullptr, "Unknown63"}, | 202 | {63, nullptr, "Unknown63"}, |
| 203 | {64, nullptr, "Unknown64"}, | 203 | {64, nullptr, "Unknown64"}, |
| 204 | {65, nullptr, "Unknown65"}, | ||
| 205 | {66, nullptr, "Unknown66"}, | ||
| 206 | {67, nullptr, "Unknown67"}, | ||
| 207 | {68, nullptr, "Unknown68"}, | ||
| 208 | {69, nullptr, "Unknown69"}, | ||
| 209 | {70, nullptr, "Unknown70"}, | ||
| 210 | {71, nullptr, "Unknown71"}, | ||
| 211 | {72, nullptr, "Unknown72"}, | ||
| 212 | {73, nullptr, "Unknown73"}, | ||
| 213 | {74, nullptr, "Unknown74"}, | ||
| 214 | {75, nullptr, "Unknown75"}, | ||
| 215 | {76, nullptr, "Unknown76"}, | ||
| 216 | {100, nullptr, "Unknown100"}, | ||
| 217 | {101, nullptr, "Unknown101"}, | ||
| 218 | {110, nullptr, "Unknown102"}, | ||
| 219 | {111, nullptr, "Unknown103"}, | ||
| 204 | }; | 220 | }; |
| 205 | // clang-format on | 221 | // clang-format on |
| 206 | 222 | ||
| @@ -249,6 +265,20 @@ public: | |||
| 249 | {7, nullptr, "AcquireRadioEvent"}, | 265 | {7, nullptr, "AcquireRadioEvent"}, |
| 250 | {8, nullptr, "AcquireGamepadPairingEvent"}, | 266 | {8, nullptr, "AcquireGamepadPairingEvent"}, |
| 251 | {9, nullptr, "IsGamepadPairingStarted"}, | 267 | {9, nullptr, "IsGamepadPairingStarted"}, |
| 268 | {10, nullptr, "StartAudioDeviceDiscovery"}, | ||
| 269 | {11, nullptr, "StopAudioDeviceDiscovery"}, | ||
| 270 | {12, nullptr, "IsDiscoveryingAudioDevice"}, | ||
| 271 | {13, nullptr, "GetDiscoveredAudioDevice"}, | ||
| 272 | {14, nullptr, "AcquireAudioDeviceConnectionEvent"}, | ||
| 273 | {15, nullptr, "ConnectAudioDevice"}, | ||
| 274 | {16, nullptr, "IsConnectingAudioDevice"}, | ||
| 275 | {17, nullptr, "GetConnectedAudioDevices"}, | ||
| 276 | {18, nullptr, "DisconnectAudioDevice"}, | ||
| 277 | {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"}, | ||
| 278 | {20, nullptr, "GetPairedAudioDevices"}, | ||
| 279 | {21, nullptr, "RemoveAudioDevicePairing"}, | ||
| 280 | {22, nullptr, "RequestAudioDeviceConnectionRejection"}, | ||
| 281 | {23, nullptr, "CancelAudioDeviceConnectionRejection"} | ||
| 252 | }; | 282 | }; |
| 253 | // clang-format on | 283 | // clang-format on |
| 254 | 284 | ||
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 3501bc1a4..b087e7bba 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -744,6 +744,7 @@ FSP_SRV::FSP_SRV(Core::System& system_) | |||
| 744 | {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, | 744 | {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, |
| 745 | {204, nullptr, "OpenDataFileSystemByProgramIndex"}, | 745 | {204, nullptr, "OpenDataFileSystemByProgramIndex"}, |
| 746 | {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"}, | 746 | {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"}, |
| 747 | {206, nullptr, "OpenDataStorageByPath"}, | ||
| 747 | {400, nullptr, "OpenDeviceOperator"}, | 748 | {400, nullptr, "OpenDeviceOperator"}, |
| 748 | {500, nullptr, "OpenSdCardDetectionEventNotifier"}, | 749 | {500, nullptr, "OpenSdCardDetectionEventNotifier"}, |
| 749 | {501, nullptr, "OpenGameCardDetectionEventNotifier"}, | 750 | {501, nullptr, "OpenGameCardDetectionEventNotifier"}, |
| @@ -796,6 +797,8 @@ FSP_SRV::FSP_SRV(Core::System& system_) | |||
| 796 | {1014, nullptr, "OutputMultiProgramTagAccessLog"}, | 797 | {1014, nullptr, "OutputMultiProgramTagAccessLog"}, |
| 797 | {1016, nullptr, "FlushAccessLogOnSdCard"}, | 798 | {1016, nullptr, "FlushAccessLogOnSdCard"}, |
| 798 | {1017, nullptr, "OutputApplicationInfoAccessLog"}, | 799 | {1017, nullptr, "OutputApplicationInfoAccessLog"}, |
| 800 | {1018, nullptr, "SetDebugOption"}, | ||
| 801 | {1019, nullptr, "UnsetDebugOption"}, | ||
| 799 | {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, | 802 | {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, |
| 800 | {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, | 803 | {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, |
| 801 | {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, | 804 | {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, |
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 3c36f4085..9f9cea1e0 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp | |||
| @@ -27,13 +27,13 @@ public: | |||
| 27 | {10101, &IFriendService::GetFriendList, "GetFriendList"}, | 27 | {10101, &IFriendService::GetFriendList, "GetFriendList"}, |
| 28 | {10102, nullptr, "UpdateFriendInfo"}, | 28 | {10102, nullptr, "UpdateFriendInfo"}, |
| 29 | {10110, nullptr, "GetFriendProfileImage"}, | 29 | {10110, nullptr, "GetFriendProfileImage"}, |
| 30 | {10120, nullptr, "Unknown10120"}, | 30 | {10120, nullptr, "IsFriendListCacheAvailable"}, |
| 31 | {10121, nullptr, "Unknown10121"}, | 31 | {10121, nullptr, "EnsureFriendListAvailable"}, |
| 32 | {10200, nullptr, "SendFriendRequestForApplication"}, | 32 | {10200, nullptr, "SendFriendRequestForApplication"}, |
| 33 | {10211, nullptr, "AddFacedFriendRequestForApplication"}, | 33 | {10211, nullptr, "AddFacedFriendRequestForApplication"}, |
| 34 | {10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"}, | 34 | {10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"}, |
| 35 | {10420, nullptr, "Unknown10420"}, | 35 | {10420, nullptr, "IsBlockedUserListCacheAvailable"}, |
| 36 | {10421, nullptr, "Unknown10421"}, | 36 | {10421, nullptr, "EnsureBlockedUserListAvailable"}, |
| 37 | {10500, nullptr, "GetProfileList"}, | 37 | {10500, nullptr, "GetProfileList"}, |
| 38 | {10600, nullptr, "DeclareOpenOnlinePlaySession"}, | 38 | {10600, nullptr, "DeclareOpenOnlinePlaySession"}, |
| 39 | {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"}, | 39 | {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"}, |
| @@ -103,8 +103,8 @@ public: | |||
| 103 | {30900, nullptr, "SendFriendInvitation"}, | 103 | {30900, nullptr, "SendFriendInvitation"}, |
| 104 | {30910, nullptr, "ReadFriendInvitation"}, | 104 | {30910, nullptr, "ReadFriendInvitation"}, |
| 105 | {30911, nullptr, "ReadAllFriendInvitations"}, | 105 | {30911, nullptr, "ReadAllFriendInvitations"}, |
| 106 | {40100, nullptr, "Unknown40100"}, | 106 | {40100, nullptr, "DeleteFriendListCache"}, |
| 107 | {40400, nullptr, "Unknown40400"}, | 107 | {40400, nullptr, "DeleteBlockedUserListCache"}, |
| 108 | {49900, nullptr, "DeleteNetworkServiceAccountCache"}, | 108 | {49900, nullptr, "DeleteNetworkServiceAccountCache"}, |
| 109 | }; | 109 | }; |
| 110 | // clang-format on | 110 | // clang-format on |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 84da38b3b..a2bf7defb 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -1176,7 +1176,8 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) { | |||
| 1176 | 1176 | ||
| 1177 | const auto parameters{rp.PopRaw<Parameters>()}; | 1177 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1178 | 1178 | ||
| 1179 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1179 | GetAppletResource() |
| 1180 | ->GetController<Controller_NPad>(HidController::NPad) | ||
| 1180 | .SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp); | 1181 | .SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp); |
| 1181 | 1182 | ||
| 1182 | LOG_WARNING(Service_HID, | 1183 | LOG_WARNING(Service_HID, |
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index 196f274e1..4fc23a958 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp | |||
| @@ -211,6 +211,11 @@ public: | |||
| 211 | {127, nullptr, "Unknown127"}, | 211 | {127, nullptr, "Unknown127"}, |
| 212 | {128, nullptr, "Unknown128"}, | 212 | {128, nullptr, "Unknown128"}, |
| 213 | {129, nullptr, "Unknown129"}, | 213 | {129, nullptr, "Unknown129"}, |
| 214 | {130, nullptr, "Unknown130"}, | ||
| 215 | {131, nullptr, "Unknown131"}, | ||
| 216 | {132, nullptr, "Unknown132"}, | ||
| 217 | {133, nullptr, "Unknown133"}, | ||
| 218 | {134, nullptr, "Unknown134"}, | ||
| 214 | }; | 219 | }; |
| 215 | // clang-format on | 220 | // clang-format on |
| 216 | 221 | ||
| @@ -287,6 +292,7 @@ public: | |||
| 287 | {502, nullptr, "RequestDownloadTicketForPrepurchasedContents"}, | 292 | {502, nullptr, "RequestDownloadTicketForPrepurchasedContents"}, |
| 288 | {503, nullptr, "RequestSyncTicket"}, | 293 | {503, nullptr, "RequestSyncTicket"}, |
| 289 | {504, nullptr, "RequestDownloadTicketForPrepurchasedContents2"}, | 294 | {504, nullptr, "RequestDownloadTicketForPrepurchasedContents2"}, |
| 295 | {505, nullptr, "RequestDownloadTicketForPrepurchasedContentsForAccount"}, | ||
| 290 | }; | 296 | }; |
| 291 | // clang-format on | 297 | // clang-format on |
| 292 | 298 | ||
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 382ddcae5..5eaad0474 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp | |||
| @@ -158,6 +158,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_ | |||
| 158 | {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, | 158 | {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, |
| 159 | {606, nullptr, "GetContentMetaStorage"}, | 159 | {606, nullptr, "GetContentMetaStorage"}, |
| 160 | {607, nullptr, "ListAvailableAddOnContent"}, | 160 | {607, nullptr, "ListAvailableAddOnContent"}, |
| 161 | {609, nullptr, "ListAvailabilityAssuredAddOnContent"}, | ||
| 161 | {700, nullptr, "PushDownloadTaskList"}, | 162 | {700, nullptr, "PushDownloadTaskList"}, |
| 162 | {701, nullptr, "ClearTaskStatusList"}, | 163 | {701, nullptr, "ClearTaskStatusList"}, |
| 163 | {702, nullptr, "RequestDownloadTaskList"}, | 164 | {702, nullptr, "RequestDownloadTaskList"}, |
| @@ -289,6 +290,11 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_ | |||
| 289 | {2514, nullptr, "ClearTaskOfAsyncTaskManager"}, | 290 | {2514, nullptr, "ClearTaskOfAsyncTaskManager"}, |
| 290 | {2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"}, | 291 | {2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"}, |
| 291 | {2516, nullptr, "EnsureApplicationCertificate"}, | 292 | {2516, nullptr, "EnsureApplicationCertificate"}, |
| 293 | {2517, nullptr, "CreateApplicationInstance"}, | ||
| 294 | {2518, nullptr, "UpdateQualificationForDebug"}, | ||
| 295 | {2519, nullptr, "IsQualificationTransitionSupported"}, | ||
| 296 | {2520, nullptr, "IsQualificationTransitionSupportedByProcessId"}, | ||
| 297 | {2521, nullptr, "GetRightsUserChangedEvent"}, | ||
| 292 | {2800, nullptr, "GetApplicationIdOfPreomia"}, | 298 | {2800, nullptr, "GetApplicationIdOfPreomia"}, |
| 293 | {3000, nullptr, "RegisterDeviceLockKey"}, | 299 | {3000, nullptr, "RegisterDeviceLockKey"}, |
| 294 | {3001, nullptr, "UnregisterDeviceLockKey"}, | 300 | {3001, nullptr, "UnregisterDeviceLockKey"}, |
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index 286578b17..38e6eae04 100644 --- a/src/core/hle/service/set/set_sys.cpp +++ b/src/core/hle/service/set/set_sys.cpp | |||
| @@ -307,6 +307,8 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { | |||
| 307 | {202, nullptr, "SetFieldTestingFlag"}, | 307 | {202, nullptr, "SetFieldTestingFlag"}, |
| 308 | {203, nullptr, "GetPanelCrcMode"}, | 308 | {203, nullptr, "GetPanelCrcMode"}, |
| 309 | {204, nullptr, "SetPanelCrcMode"}, | 309 | {204, nullptr, "SetPanelCrcMode"}, |
| 310 | {205, nullptr, "GetNxControllerSettingsEx"}, | ||
| 311 | {206, nullptr, "SetNxControllerSettingsEx"}, | ||
| 310 | }; | 312 | }; |
| 311 | // clang-format on | 313 | // clang-format on |
| 312 | 314 | ||
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp index 502dfbb4a..0747c33cd 100644 --- a/src/core/hle/service/usb/usb.cpp +++ b/src/core/hle/service/usb/usb.cpp | |||
| @@ -17,34 +17,9 @@ public: | |||
| 17 | explicit IDsInterface(Core::System& system_) : ServiceFramework{system_, "IDsInterface"} { | 17 | explicit IDsInterface(Core::System& system_) : ServiceFramework{system_, "IDsInterface"} { |
| 18 | // clang-format off | 18 | // clang-format off |
| 19 | static const FunctionInfo functions[] = { | 19 | static const FunctionInfo functions[] = { |
| 20 | {0, nullptr, "GetDsEndpoint"}, | ||
| 21 | {1, nullptr, "GetSetupEvent"}, | ||
| 22 | {2, nullptr, "Unknown2"}, | ||
| 23 | {3, nullptr, "EnableInterface"}, | ||
| 24 | {4, nullptr, "DisableInterface"}, | ||
| 25 | {5, nullptr, "CtrlInPostBufferAsync"}, | ||
| 26 | {6, nullptr, "CtrlOutPostBufferAsync"}, | ||
| 27 | {7, nullptr, "GetCtrlInCompletionEvent"}, | ||
| 28 | {8, nullptr, "GetCtrlInReportData"}, | ||
| 29 | {9, nullptr, "GetCtrlOutCompletionEvent"}, | ||
| 30 | {10, nullptr, "GetCtrlOutReportData"}, | ||
| 31 | {11, nullptr, "StallCtrl"}, | ||
| 32 | {12, nullptr, "AppendConfigurationData"}, | ||
| 33 | }; | ||
| 34 | // clang-format on | ||
| 35 | |||
| 36 | RegisterHandlers(functions); | ||
| 37 | } | ||
| 38 | }; | ||
| 39 | |||
| 40 | class USB_DS final : public ServiceFramework<USB_DS> { | ||
| 41 | public: | ||
| 42 | explicit USB_DS(Core::System& system_) : ServiceFramework{system_, "usb:ds"} { | ||
| 43 | // clang-format off | ||
| 44 | static const FunctionInfo functions[] = { | ||
| 45 | {0, nullptr, "BindDevice"}, | 20 | {0, nullptr, "BindDevice"}, |
| 46 | {1, nullptr, "BindClientProcess"}, | 21 | {1, nullptr, "BindClientProcess"}, |
| 47 | {2, nullptr, "GetDsInterface"}, | 22 | {2, nullptr, "AddInterface"}, |
| 48 | {3, nullptr, "GetStateChangeEvent"}, | 23 | {3, nullptr, "GetStateChangeEvent"}, |
| 49 | {4, nullptr, "GetState"}, | 24 | {4, nullptr, "GetState"}, |
| 50 | {5, nullptr, "ClearDeviceData"}, | 25 | {5, nullptr, "ClearDeviceData"}, |
| @@ -62,6 +37,19 @@ public: | |||
| 62 | } | 37 | } |
| 63 | }; | 38 | }; |
| 64 | 39 | ||
| 40 | class USB_DS final : public ServiceFramework<USB_DS> { | ||
| 41 | public: | ||
| 42 | explicit USB_DS(Core::System& system_) : ServiceFramework{system_, "usb:ds"} { | ||
| 43 | // clang-format off | ||
| 44 | static const FunctionInfo functions[] = { | ||
| 45 | {0, nullptr, "OpenDsService"}, | ||
| 46 | }; | ||
| 47 | // clang-format on | ||
| 48 | |||
| 49 | RegisterHandlers(functions); | ||
| 50 | } | ||
| 51 | }; | ||
| 52 | |||
| 65 | class IClientEpSession final : public ServiceFramework<IClientEpSession> { | 53 | class IClientEpSession final : public ServiceFramework<IClientEpSession> { |
| 66 | public: | 54 | public: |
| 67 | explicit IClientEpSession(Core::System& system_) | 55 | explicit IClientEpSession(Core::System& system_) |
| @@ -120,7 +108,7 @@ public: | |||
| 120 | {5, nullptr, "DestroyInterfaceAvailableEvent"}, | 108 | {5, nullptr, "DestroyInterfaceAvailableEvent"}, |
| 121 | {6, nullptr, "GetInterfaceStateChangeEvent"}, | 109 | {6, nullptr, "GetInterfaceStateChangeEvent"}, |
| 122 | {7, nullptr, "AcquireUsbIf"}, | 110 | {7, nullptr, "AcquireUsbIf"}, |
| 123 | {8, nullptr, "Unknown8"}, | 111 | {8, nullptr, "ResetDevice"}, |
| 124 | }; | 112 | }; |
| 125 | // clang-format on | 113 | // clang-format on |
| 126 | 114 | ||
diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp index 44957e01d..f10b8c853 100644 --- a/src/core/hle/service/wlan/wlan.cpp +++ b/src/core/hle/service/wlan/wlan.cpp | |||
| @@ -53,6 +53,7 @@ public: | |||
| 53 | {35, nullptr, "Unknown35"}, | 53 | {35, nullptr, "Unknown35"}, |
| 54 | {36, nullptr, "Unknown36"}, | 54 | {36, nullptr, "Unknown36"}, |
| 55 | {37, nullptr, "Unknown37"}, | 55 | {37, nullptr, "Unknown37"}, |
| 56 | {38, nullptr, "Unknown38"}, | ||
| 56 | }; | 57 | }; |
| 57 | // clang-format on | 58 | // clang-format on |
| 58 | 59 | ||
| @@ -117,7 +118,6 @@ public: | |||
| 117 | {49, nullptr, "Unknown49"}, | 118 | {49, nullptr, "Unknown49"}, |
| 118 | {50, nullptr, "Unknown50"}, | 119 | {50, nullptr, "Unknown50"}, |
| 119 | {51, nullptr, "Unknown51"}, | 120 | {51, nullptr, "Unknown51"}, |
| 120 | {52, nullptr, "Unknown52"}, | ||
| 121 | }; | 121 | }; |
| 122 | // clang-format on | 122 | // clang-format on |
| 123 | 123 | ||
diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index aa69216c8..d8ae7f0c1 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp | |||
| @@ -16,6 +16,7 @@ constexpr int mouse_axis_x = 0; | |||
| 16 | constexpr int mouse_axis_y = 1; | 16 | constexpr int mouse_axis_y = 1; |
| 17 | constexpr int wheel_axis_x = 2; | 17 | constexpr int wheel_axis_x = 2; |
| 18 | constexpr int wheel_axis_y = 3; | 18 | constexpr int wheel_axis_y = 3; |
| 19 | constexpr int motion_wheel_y = 4; | ||
| 19 | constexpr int touch_axis_x = 10; | 20 | constexpr int touch_axis_x = 10; |
| 20 | constexpr int touch_axis_y = 11; | 21 | constexpr int touch_axis_y = 11; |
| 21 | constexpr PadIdentifier identifier = { | 22 | constexpr PadIdentifier identifier = { |
| @@ -30,8 +31,9 @@ Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) | |||
| 30 | PreSetAxis(identifier, mouse_axis_y); | 31 | PreSetAxis(identifier, mouse_axis_y); |
| 31 | PreSetAxis(identifier, wheel_axis_x); | 32 | PreSetAxis(identifier, wheel_axis_x); |
| 32 | PreSetAxis(identifier, wheel_axis_y); | 33 | PreSetAxis(identifier, wheel_axis_y); |
| 34 | PreSetAxis(identifier, motion_wheel_y); | ||
| 33 | PreSetAxis(identifier, touch_axis_x); | 35 | PreSetAxis(identifier, touch_axis_x); |
| 34 | PreSetAxis(identifier, touch_axis_x); | 36 | PreSetAxis(identifier, touch_axis_y); |
| 35 | update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); }); | 37 | update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); }); |
| 36 | } | 38 | } |
| 37 | 39 | ||
| @@ -48,6 +50,8 @@ void Mouse::UpdateThread(std::stop_token stop_token) { | |||
| 48 | SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity); | 50 | SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity); |
| 49 | } | 51 | } |
| 50 | 52 | ||
| 53 | SetAxis(identifier, motion_wheel_y, 0.0f); | ||
| 54 | |||
| 51 | if (mouse_panning_timout++ > 20) { | 55 | if (mouse_panning_timout++ > 20) { |
| 52 | StopPanning(); | 56 | StopPanning(); |
| 53 | } | 57 | } |
| @@ -136,6 +140,7 @@ void Mouse::MouseWheelChange(int x, int y) { | |||
| 136 | wheel_position.y += y; | 140 | wheel_position.y += y; |
| 137 | SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x)); | 141 | SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x)); |
| 138 | SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y)); | 142 | SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y)); |
| 143 | SetAxis(identifier, motion_wheel_y, static_cast<f32>(y) / 100.0f); | ||
| 139 | } | 144 | } |
| 140 | 145 | ||
| 141 | void Mouse::ReleaseAllButtons() { | 146 | void Mouse::ReleaseAllButtons() { |
| @@ -171,13 +176,39 @@ AnalogMapping Mouse::GetAnalogMappingForDevice( | |||
| 171 | return mapping; | 176 | return mapping; |
| 172 | } | 177 | } |
| 173 | 178 | ||
| 179 | Common::Input::ButtonNames Mouse::GetUIButtonName(const Common::ParamPackage& params) const { | ||
| 180 | const auto button = static_cast<MouseButton>(params.Get("button", 0)); | ||
| 181 | switch (button) { | ||
| 182 | case MouseButton::Left: | ||
| 183 | return Common::Input::ButtonNames::ButtonLeft; | ||
| 184 | case MouseButton::Right: | ||
| 185 | return Common::Input::ButtonNames::ButtonRight; | ||
| 186 | case MouseButton::Wheel: | ||
| 187 | return Common::Input::ButtonNames::ButtonMouseWheel; | ||
| 188 | case MouseButton::Backward: | ||
| 189 | return Common::Input::ButtonNames::ButtonBackward; | ||
| 190 | case MouseButton::Forward: | ||
| 191 | return Common::Input::ButtonNames::ButtonForward; | ||
| 192 | case MouseButton::Task: | ||
| 193 | return Common::Input::ButtonNames::ButtonTask; | ||
| 194 | case MouseButton::Extra: | ||
| 195 | return Common::Input::ButtonNames::ButtonExtra; | ||
| 196 | case MouseButton::Undefined: | ||
| 197 | default: | ||
| 198 | return Common::Input::ButtonNames::Undefined; | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 174 | Common::Input::ButtonNames Mouse::GetUIName(const Common::ParamPackage& params) const { | 202 | Common::Input::ButtonNames Mouse::GetUIName(const Common::ParamPackage& params) const { |
| 175 | if (params.Has("button")) { | 203 | if (params.Has("button")) { |
| 176 | return Common::Input::ButtonNames::Value; | 204 | return GetUIButtonName(params); |
| 177 | } | 205 | } |
| 178 | if (params.Has("axis")) { | 206 | if (params.Has("axis")) { |
| 179 | return Common::Input::ButtonNames::Value; | 207 | return Common::Input::ButtonNames::Value; |
| 180 | } | 208 | } |
| 209 | if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) { | ||
| 210 | return Common::Input::ButtonNames::Engine; | ||
| 211 | } | ||
| 181 | 212 | ||
| 182 | return Common::Input::ButtonNames::Invalid; | 213 | return Common::Input::ButtonNames::Invalid; |
| 183 | } | 214 | } |
diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 040446178..c5833b8ed 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h | |||
| @@ -69,6 +69,8 @@ private: | |||
| 69 | void UpdateThread(std::stop_token stop_token); | 69 | void UpdateThread(std::stop_token stop_token); |
| 70 | void StopPanning(); | 70 | void StopPanning(); |
| 71 | 71 | ||
| 72 | Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; | ||
| 73 | |||
| 72 | Common::Vec2<int> mouse_origin; | 74 | Common::Vec2<int> mouse_origin; |
| 73 | Common::Vec2<int> last_mouse_position; | 75 | Common::Vec2<int> last_mouse_position; |
| 74 | Common::Vec2<float> last_mouse_change; | 76 | Common::Vec2<float> last_mouse_change; |
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 41701e24d..ed6281772 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp | |||
| @@ -198,9 +198,9 @@ public: | |||
| 198 | if (sdl_controller) { | 198 | if (sdl_controller) { |
| 199 | switch (SDL_GameControllerGetType(sdl_controller.get())) { | 199 | switch (SDL_GameControllerGetType(sdl_controller.get())) { |
| 200 | case SDL_CONTROLLER_TYPE_XBOX360: | 200 | case SDL_CONTROLLER_TYPE_XBOX360: |
| 201 | return "XBox 360 Controller"; | 201 | return "Xbox 360 Controller"; |
| 202 | case SDL_CONTROLLER_TYPE_XBOXONE: | 202 | case SDL_CONTROLLER_TYPE_XBOXONE: |
| 203 | return "XBox One Controller"; | 203 | return "Xbox One Controller"; |
| 204 | case SDL_CONTROLLER_TYPE_PS3: | 204 | case SDL_CONTROLLER_TYPE_PS3: |
| 205 | return "DualShock 3 Controller"; | 205 | return "DualShock 3 Controller"; |
| 206 | case SDL_CONTROLLER_TYPE_PS4: | 206 | case SDL_CONTROLLER_TYPE_PS4: |
diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index b57330e51..0508b408d 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp | |||
| @@ -173,7 +173,7 @@ void InputEngine::ResetButtonState() { | |||
| 173 | SetButton(controller.first, button.first, false); | 173 | SetButton(controller.first, button.first, false); |
| 174 | } | 174 | } |
| 175 | for (const auto& button : controller.second.hat_buttons) { | 175 | for (const auto& button : controller.second.hat_buttons) { |
| 176 | SetHatButton(controller.first, button.first, false); | 176 | SetHatButton(controller.first, button.first, 0); |
| 177 | } | 177 | } |
| 178 | } | 178 | } |
| 179 | } | 179 | } |
diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp index 6e0024b2d..475257f42 100644 --- a/src/input_common/input_mapping.cpp +++ b/src/input_common/input_mapping.cpp | |||
| @@ -143,6 +143,19 @@ void MappingFactory::RegisterMotion(const MappingData& data) { | |||
| 143 | } | 143 | } |
| 144 | new_input.Set("port", static_cast<int>(data.pad.port)); | 144 | new_input.Set("port", static_cast<int>(data.pad.port)); |
| 145 | new_input.Set("pad", static_cast<int>(data.pad.pad)); | 145 | new_input.Set("pad", static_cast<int>(data.pad.pad)); |
| 146 | |||
| 147 | // If engine is mouse map the mouse position as 3 axis motion | ||
| 148 | if (data.engine == "mouse") { | ||
| 149 | new_input.Set("axis_x", 1); | ||
| 150 | new_input.Set("invert_x", "-"); | ||
| 151 | new_input.Set("axis_y", 0); | ||
| 152 | new_input.Set("axis_z", 4); | ||
| 153 | new_input.Set("range", 1.0f); | ||
| 154 | new_input.Set("deadzone", 0.0f); | ||
| 155 | input_queue.Push(new_input); | ||
| 156 | return; | ||
| 157 | } | ||
| 158 | |||
| 146 | switch (data.type) { | 159 | switch (data.type) { |
| 147 | case EngineInputType::Button: | 160 | case EngineInputType::Button: |
| 148 | case EngineInputType::HatButton: | 161 | case EngineInputType::HatButton: |
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp index bb7f1a0fd..e816a93ec 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp | |||
| @@ -458,9 +458,10 @@ void EmitContext::DefineGenericOutput(size_t index, u32 invocations) { | |||
| 458 | std::string definition{fmt::format("layout(location={}", index)}; | 458 | std::string definition{fmt::format("layout(location={}", index)}; |
| 459 | const u32 remainder{4 - element}; | 459 | const u32 remainder{4 - element}; |
| 460 | const TransformFeedbackVarying* xfb_varying{}; | 460 | const TransformFeedbackVarying* xfb_varying{}; |
| 461 | if (!runtime_info.xfb_varyings.empty()) { | 461 | const size_t xfb_varying_index{base_index + element}; |
| 462 | xfb_varying = &runtime_info.xfb_varyings[base_index + element]; | 462 | if (xfb_varying_index < runtime_info.xfb_varyings.size()) { |
| 463 | xfb_varying = xfb_varying && xfb_varying->components > 0 ? xfb_varying : nullptr; | 463 | xfb_varying = &runtime_info.xfb_varyings[xfb_varying_index]; |
| 464 | xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; | ||
| 464 | } | 465 | } |
| 465 | const u32 num_components{xfb_varying ? xfb_varying->components : remainder}; | 466 | const u32 num_components{xfb_varying ? xfb_varying->components : remainder}; |
| 466 | if (element > 0) { | 467 | if (element > 0) { |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index d3ba66569..cd90c084a 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | |||
| @@ -164,9 +164,10 @@ void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invo | |||
| 164 | while (element < 4) { | 164 | while (element < 4) { |
| 165 | const u32 remainder{4 - element}; | 165 | const u32 remainder{4 - element}; |
| 166 | const TransformFeedbackVarying* xfb_varying{}; | 166 | const TransformFeedbackVarying* xfb_varying{}; |
| 167 | if (!ctx.runtime_info.xfb_varyings.empty()) { | 167 | const size_t xfb_varying_index{base_attr_index + element}; |
| 168 | xfb_varying = &ctx.runtime_info.xfb_varyings[base_attr_index + element]; | 168 | if (xfb_varying_index < ctx.runtime_info.xfb_varyings.size()) { |
| 169 | xfb_varying = xfb_varying && xfb_varying->components > 0 ? xfb_varying : nullptr; | 169 | xfb_varying = &ctx.runtime_info.xfb_varyings[xfb_varying_index]; |
| 170 | xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; | ||
| 170 | } | 171 | } |
| 171 | const u32 num_components{xfb_varying ? xfb_varying->components : remainder}; | 172 | const u32 num_components{xfb_varying ? xfb_varying->components : remainder}; |
| 172 | 173 | ||
diff --git a/src/video_core/command_classes/codecs/codec.h b/src/video_core/command_classes/codecs/codec.h index 13ed88382..de5672155 100644 --- a/src/video_core/command_classes/codecs/codec.h +++ b/src/video_core/command_classes/codecs/codec.h | |||
| @@ -66,7 +66,7 @@ private: | |||
| 66 | bool initialized{}; | 66 | bool initialized{}; |
| 67 | NvdecCommon::VideoCodec current_codec{NvdecCommon::VideoCodec::None}; | 67 | NvdecCommon::VideoCodec current_codec{NvdecCommon::VideoCodec::None}; |
| 68 | 68 | ||
| 69 | AVCodec* av_codec{nullptr}; | 69 | const AVCodec* av_codec{nullptr}; |
| 70 | AVCodecContext* av_codec_ctx{nullptr}; | 70 | AVCodecContext* av_codec_ctx{nullptr}; |
| 71 | AVBufferRef* av_gpu_decoder{nullptr}; | 71 | AVBufferRef* av_gpu_decoder{nullptr}; |
| 72 | 72 | ||
diff --git a/src/video_core/host_shaders/astc_decoder.comp b/src/video_core/host_shaders/astc_decoder.comp index f34c5f5d9..3a10578cb 100644 --- a/src/video_core/host_shaders/astc_decoder.comp +++ b/src/video_core/host_shaders/astc_decoder.comp | |||
| @@ -155,9 +155,6 @@ uint SwizzleOffset(uvec2 pos) { | |||
| 155 | // Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)] | 155 | // Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)] |
| 156 | // is the same as [(num_bits - 1):0] and repeats all the way down. | 156 | // is the same as [(num_bits - 1):0] and repeats all the way down. |
| 157 | uint Replicate(uint val, uint num_bits, uint to_bit) { | 157 | uint Replicate(uint val, uint num_bits, uint to_bit) { |
| 158 | if (num_bits == 0 || to_bit == 0) { | ||
| 159 | return 0; | ||
| 160 | } | ||
| 161 | const uint v = val & uint((1 << num_bits) - 1); | 158 | const uint v = val & uint((1 << num_bits) - 1); |
| 162 | uint res = v; | 159 | uint res = v; |
| 163 | uint reslen = num_bits; | 160 | uint reslen = num_bits; |
| @@ -187,42 +184,57 @@ uint ReplicateBitTo9(uint value) { | |||
| 187 | return REPLICATE_1_BIT_TO_9_TABLE[value]; | 184 | return REPLICATE_1_BIT_TO_9_TABLE[value]; |
| 188 | } | 185 | } |
| 189 | 186 | ||
| 190 | uint FastReplicateTo8(uint value, uint num_bits) { | 187 | uint FastReplicate(uint value, uint num_bits, uint to_bit) { |
| 191 | switch (num_bits) { | 188 | if (num_bits == 0) { |
| 192 | case 1: | 189 | return 0; |
| 193 | return REPLICATE_1_BIT_TO_8_TABLE[value]; | 190 | } |
| 194 | case 2: | 191 | if (num_bits == to_bit) { |
| 195 | return REPLICATE_2_BIT_TO_8_TABLE[value]; | ||
| 196 | case 3: | ||
| 197 | return REPLICATE_3_BIT_TO_8_TABLE[value]; | ||
| 198 | case 4: | ||
| 199 | return REPLICATE_4_BIT_TO_8_TABLE[value]; | ||
| 200 | case 5: | ||
| 201 | return REPLICATE_5_BIT_TO_8_TABLE[value]; | ||
| 202 | case 6: | ||
| 203 | return REPLICATE_6_BIT_TO_8_TABLE[value]; | ||
| 204 | case 7: | ||
| 205 | return REPLICATE_7_BIT_TO_8_TABLE[value]; | ||
| 206 | case 8: | ||
| 207 | return value; | 192 | return value; |
| 208 | } | 193 | } |
| 209 | return Replicate(value, num_bits, 8); | 194 | if (to_bit == 6) { |
| 195 | switch (num_bits) { | ||
| 196 | case 1: | ||
| 197 | return REPLICATE_1_BIT_TO_6_TABLE[value]; | ||
| 198 | case 2: | ||
| 199 | return REPLICATE_2_BIT_TO_6_TABLE[value]; | ||
| 200 | case 3: | ||
| 201 | return REPLICATE_3_BIT_TO_6_TABLE[value]; | ||
| 202 | case 4: | ||
| 203 | return REPLICATE_4_BIT_TO_6_TABLE[value]; | ||
| 204 | case 5: | ||
| 205 | return REPLICATE_5_BIT_TO_6_TABLE[value]; | ||
| 206 | default: | ||
| 207 | break; | ||
| 208 | } | ||
| 209 | } else { /* if (to_bit == 8) */ | ||
| 210 | switch (num_bits) { | ||
| 211 | case 1: | ||
| 212 | return REPLICATE_1_BIT_TO_8_TABLE[value]; | ||
| 213 | case 2: | ||
| 214 | return REPLICATE_2_BIT_TO_8_TABLE[value]; | ||
| 215 | case 3: | ||
| 216 | return REPLICATE_3_BIT_TO_8_TABLE[value]; | ||
| 217 | case 4: | ||
| 218 | return REPLICATE_4_BIT_TO_8_TABLE[value]; | ||
| 219 | case 5: | ||
| 220 | return REPLICATE_5_BIT_TO_8_TABLE[value]; | ||
| 221 | case 6: | ||
| 222 | return REPLICATE_6_BIT_TO_8_TABLE[value]; | ||
| 223 | case 7: | ||
| 224 | return REPLICATE_7_BIT_TO_8_TABLE[value]; | ||
| 225 | default: | ||
| 226 | break; | ||
| 227 | } | ||
| 228 | } | ||
| 229 | return Replicate(value, num_bits, to_bit); | ||
| 230 | } | ||
| 231 | |||
| 232 | uint FastReplicateTo8(uint value, uint num_bits) { | ||
| 233 | return FastReplicate(value, num_bits, 8); | ||
| 210 | } | 234 | } |
| 211 | 235 | ||
| 212 | uint FastReplicateTo6(uint value, uint num_bits) { | 236 | uint FastReplicateTo6(uint value, uint num_bits) { |
| 213 | switch (num_bits) { | 237 | return FastReplicate(value, num_bits, 6); |
| 214 | case 1: | ||
| 215 | return REPLICATE_1_BIT_TO_6_TABLE[value]; | ||
| 216 | case 2: | ||
| 217 | return REPLICATE_2_BIT_TO_6_TABLE[value]; | ||
| 218 | case 3: | ||
| 219 | return REPLICATE_3_BIT_TO_6_TABLE[value]; | ||
| 220 | case 4: | ||
| 221 | return REPLICATE_4_BIT_TO_6_TABLE[value]; | ||
| 222 | case 5: | ||
| 223 | return REPLICATE_5_BIT_TO_6_TABLE[value]; | ||
| 224 | } | ||
| 225 | return Replicate(value, num_bits, 6); | ||
| 226 | } | 238 | } |
| 227 | 239 | ||
| 228 | uint Div3Floor(uint v) { | 240 | uint Div3Floor(uint v) { |
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 3d78efddc..153702c0b 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -1038,7 +1038,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) { | |||
| 1038 | } | 1038 | } |
| 1039 | if (has_ext_shader_atomic_int64) { | 1039 | if (has_ext_shader_atomic_int64) { |
| 1040 | VkPhysicalDeviceShaderAtomicInt64Features atomic_int64; | 1040 | VkPhysicalDeviceShaderAtomicInt64Features atomic_int64; |
| 1041 | atomic_int64.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; | 1041 | atomic_int64.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES; |
| 1042 | atomic_int64.pNext = nullptr; | 1042 | atomic_int64.pNext = nullptr; |
| 1043 | features.pNext = &atomic_int64; | 1043 | features.pNext = &atomic_int64; |
| 1044 | physical.GetFeatures2KHR(features); | 1044 | physical.GetFeatures2KHR(features); |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 99a7397fc..8c370ff91 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -743,7 +743,9 @@ void Config::ReadUIValues() { | |||
| 743 | qt_config->beginGroup(QStringLiteral("UI")); | 743 | qt_config->beginGroup(QStringLiteral("UI")); |
| 744 | 744 | ||
| 745 | UISettings::values.theme = | 745 | UISettings::values.theme = |
| 746 | ReadSetting(QStringLiteral("theme"), QString::fromUtf8(UISettings::themes[0].second)) | 746 | ReadSetting( |
| 747 | QStringLiteral("theme"), | ||
| 748 | QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second)) | ||
| 747 | .toString(); | 749 | .toString(); |
| 748 | ReadBasicSetting(UISettings::values.enable_discord_presence); | 750 | ReadBasicSetting(UISettings::values.enable_discord_presence); |
| 749 | ReadBasicSetting(UISettings::values.select_user_on_boot); | 751 | ReadBasicSetting(UISettings::values.select_user_on_boot); |
| @@ -1271,7 +1273,7 @@ void Config::SaveUIValues() { | |||
| 1271 | qt_config->beginGroup(QStringLiteral("UI")); | 1273 | qt_config->beginGroup(QStringLiteral("UI")); |
| 1272 | 1274 | ||
| 1273 | WriteSetting(QStringLiteral("theme"), UISettings::values.theme, | 1275 | WriteSetting(QStringLiteral("theme"), UISettings::values.theme, |
| 1274 | QString::fromUtf8(UISettings::themes[0].second)); | 1276 | QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second)); |
| 1275 | WriteBasicSetting(UISettings::values.enable_discord_presence); | 1277 | WriteBasicSetting(UISettings::values.enable_discord_presence); |
| 1276 | WriteBasicSetting(UISettings::values.select_user_on_boot); | 1278 | WriteBasicSetting(UISettings::values.select_user_on_boot); |
| 1277 | 1279 | ||
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index d673c1cdc..8f4576def 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h | |||
| @@ -48,6 +48,14 @@ public: | |||
| 48 | static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods; | 48 | static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods; |
| 49 | static const std::array<UISettings::Shortcut, 21> default_hotkeys; | 49 | static const std::array<UISettings::Shortcut, 21> default_hotkeys; |
| 50 | 50 | ||
| 51 | static constexpr UISettings::Theme default_theme{ | ||
| 52 | #ifdef _WIN32 | ||
| 53 | UISettings::Theme::DarkColorful | ||
| 54 | #else | ||
| 55 | UISettings::Theme::DefaultColorful | ||
| 56 | #endif | ||
| 57 | }; | ||
| 58 | |||
| 51 | private: | 59 | private: |
| 52 | void Initialize(const std::string& config_name); | 60 | void Initialize(const std::string& config_name); |
| 53 | 61 | ||
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index b9342466e..d2132b408 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -102,6 +102,16 @@ QString GetButtonName(Common::Input::ButtonNames button_name) { | |||
| 102 | return QObject::tr("Share"); | 102 | return QObject::tr("Share"); |
| 103 | case Common::Input::ButtonNames::Options: | 103 | case Common::Input::ButtonNames::Options: |
| 104 | return QObject::tr("Options"); | 104 | return QObject::tr("Options"); |
| 105 | case Common::Input::ButtonNames::ButtonMouseWheel: | ||
| 106 | return QObject::tr("Wheel", "Indicates the mouse wheel"); | ||
| 107 | case Common::Input::ButtonNames::ButtonBackward: | ||
| 108 | return QObject::tr("Backward"); | ||
| 109 | case Common::Input::ButtonNames::ButtonForward: | ||
| 110 | return QObject::tr("Forward"); | ||
| 111 | case Common::Input::ButtonNames::ButtonTask: | ||
| 112 | return QObject::tr("Task"); | ||
| 113 | case Common::Input::ButtonNames::ButtonExtra: | ||
| 114 | return QObject::tr("Extra"); | ||
| 105 | default: | 115 | default: |
| 106 | return QObject::tr("[undefined]"); | 116 | return QObject::tr("[undefined]"); |
| 107 | } | 117 | } |
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 1f41c46c4..2d1a2d9cb 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp | |||
| @@ -95,7 +95,7 @@ std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList( | |||
| 95 | std::size_t row = 0; | 95 | std::size_t row = 0; |
| 96 | auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) { | 96 | auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) { |
| 97 | for (std::size_t i = 0; i < threads.size(); ++i) { | 97 | for (std::size_t i = 0; i < threads.size(); ++i) { |
| 98 | if (threads[i]->GetThreadTypeForDebugging() == Kernel::ThreadType::User) { | 98 | if (threads[i]->GetThreadType() == Kernel::ThreadType::User) { |
| 99 | item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i], system)); | 99 | item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i], system)); |
| 100 | item_list.back()->row = row; | 100 | item_list.back()->row = row; |
| 101 | } | 101 | } |
| @@ -153,7 +153,7 @@ QString WaitTreeCallstack::GetText() const { | |||
| 153 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const { | 153 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const { |
| 154 | std::vector<std::unique_ptr<WaitTreeItem>> list; | 154 | std::vector<std::unique_ptr<WaitTreeItem>> list; |
| 155 | 155 | ||
| 156 | if (thread.GetThreadTypeForDebugging() != Kernel::ThreadType::User) { | 156 | if (thread.GetThreadType() != Kernel::ThreadType::User) { |
| 157 | return list; | 157 | return list; |
| 158 | } | 158 | } |
| 159 | 159 | ||
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 402c4556d..f7298ddad 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -29,6 +29,15 @@ struct Shortcut { | |||
| 29 | ContextualShortcut shortcut; | 29 | ContextualShortcut shortcut; |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | enum class Theme { | ||
| 33 | Default, | ||
| 34 | DefaultColorful, | ||
| 35 | Dark, | ||
| 36 | DarkColorful, | ||
| 37 | MidnightBlue, | ||
| 38 | MidnightBlueColorful, | ||
| 39 | }; | ||
| 40 | |||
| 32 | using Themes = std::array<std::pair<const char*, const char*>, 6>; | 41 | using Themes = std::array<std::pair<const char*, const char*>, 6>; |
| 33 | extern const Themes themes; | 42 | extern const Themes themes; |
| 34 | 43 | ||