summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/bit_util.h6
-rw-r--r--src/common/fiber.cpp5
-rw-r--r--src/common/input.h7
-rw-r--r--src/core/CMakeLists.txt3
-rw-r--r--src/core/hid/emulated_console.cpp2
-rw-r--r--src/core/hid/emulated_controller.cpp2
-rw-r--r--src/core/hid/input_converter.cpp2
-rw-r--r--src/core/hle/kernel/hle_ipc.h5
-rw-r--r--src/core/hle/kernel/k_memory_manager.cpp15
-rw-r--r--src/core/hle/kernel/k_memory_manager.h15
-rw-r--r--src/core/hle/kernel/k_page_table.cpp17
-rw-r--r--src/core/hle/kernel/k_page_table.h1
-rw-r--r--src/core/hle/kernel/k_priority_queue.h36
-rw-r--r--src/core/hle/kernel/k_process.cpp6
-rw-r--r--src/core/hle/kernel/k_process.h6
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp11
-rw-r--r--src/core/hle/kernel/k_server_session.cpp20
-rw-r--r--src/core/hle/kernel/k_thread.cpp127
-rw-r--r--src/core/hle/kernel/k_thread.h31
-rw-r--r--src/core/hle/kernel/k_worker_task.h18
-rw-r--r--src/core/hle/kernel/k_worker_task_manager.cpp42
-rw-r--r--src/core/hle/kernel/k_worker_task_manager.h33
-rw-r--r--src/core/hle/kernel/kernel.cpp25
-rw-r--r--src/core/hle/kernel/kernel.h7
-rw-r--r--src/core/hle/kernel/service_thread.cpp5
-rw-r--r--src/core/hle/service/acc/acc_su.cpp4
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp4
-rw-r--r--src/core/hle/service/am/omm.cpp1
-rw-r--r--src/core/hle/service/apm/apm_interface.cpp14
-rw-r--r--src/core/hle/service/audio/audctl.cpp16
-rw-r--r--src/core/hle/service/btm/btm.cpp30
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp3
-rw-r--r--src/core/hle/service/friend/friend.cpp12
-rw-r--r--src/core/hle/service/hid/hid.cpp3
-rw-r--r--src/core/hle/service/nim/nim.cpp6
-rw-r--r--src/core/hle/service/ns/ns.cpp6
-rw-r--r--src/core/hle/service/set/set_sys.cpp2
-rw-r--r--src/core/hle/service/usb/usb.cpp42
-rw-r--r--src/core/hle/service/wlan/wlan.cpp2
-rw-r--r--src/input_common/drivers/mouse.cpp35
-rw-r--r--src/input_common/drivers/mouse.h2
-rw-r--r--src/input_common/drivers/sdl_driver.cpp4
-rw-r--r--src/input_common/input_engine.cpp2
-rw-r--r--src/input_common/input_mapping.cpp13
-rw-r--r--src/shader_recompiler/backend/glsl/glsl_emit_context.cpp7
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp7
-rw-r--r--src/video_core/command_classes/codecs/codec.h2
-rw-r--r--src/video_core/host_shaders/astc_decoder.comp80
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp6
-rw-r--r--src/yuzu/configuration/config.h8
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp10
-rw-r--r--src/yuzu/debugger/wait_tree.cpp4
-rw-r--r--src/yuzu/uisettings.h9
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
48template <typename T> 48template <typename T>
49requires std::is_unsigned_v<T>
50[[nodiscard]] constexpr bool IsPow2(T value) {
51 return std::has_single_bit(value);
52}
53
54template <typename T>
49requires std::is_integral_v<T> 55requires 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
348private: 344private:
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
15namespace Kernel { 17namespace Kernel {
16 18
19KMemoryManager::KMemoryManager(Core::System& system_) : system{system_} {}
20
17std::size_t KMemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u64 end_address) { 21std::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
83ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, 87ResultCode 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
152ResultCode KMemoryManager::Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, 163ResultCode 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
15namespace Core {
16class System;
17}
18
15namespace Kernel { 19namespace Kernel {
16 20
17class KPageLinkedList; 21class 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
131private: 135private:
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
50template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority> 51template <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
152void KProcess::DoWorkerTaskImpl() {
153 UNIMPLEMENTED();
154}
155
152KResourceLimit* KProcess::GetResourceLimit() const { 156KResourceLimit* 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
65class KProcess final 66class 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
69public: 69public:
@@ -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
413u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { 414u64 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;
105ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, 106ResultCode 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
263ResultCode KThread::InitializeDummyThread(KThread* thread) { 264ResultCode KThread::InitializeDummyThread(KThread* thread) {
264 return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Dummy); 265 return thread->Initialize({}, {}, {}, DummyThreadPriority, 3, {}, ThreadType::Dummy);
265} 266}
266 267
267ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { 268ResultCode 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
338bool KThread::IsSignaled() const { 339bool 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
382void 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
397void KThread::DoWorkerTaskImpl() {
398 // Finish the termination that was begun by Exit().
399 this->FinishTermination();
400}
401
384void KThread::Pin(s32 current_core) { 402void 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
700void KThread::WaitCancel() { 701void 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
727void KThread::Suspend() { 728void 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
739void KThread::Continue() { 743void 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
1078void 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
1091void 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
1100void KThread::IfDummyThreadEndWait() {
1101 if (!IsDummyThread()) {
1102 return;
1103 }
1104
1105 // Ensure the thread will no longer block.
1106 dummy_wait_lock.Unlock();
1107}
1108
1064void KThread::BeginWait(KThreadQueue* queue) { 1109void 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
1072void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { 1120void 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
103class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>, 104class 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:
111public: 112public:
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
631private: 647private:
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
758public: 777public:
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
9namespace Kernel {
10
11class KWorkerTask : public KSynchronizationObject {
12public:
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
12namespace Kernel {
13
14KWorkerTask::KWorkerTask(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
15
16void 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
27KWorkerTaskManager::KWorkerTaskManager() : m_waiting_thread(1, "yuzu:KWorkerTaskManager") {}
28
29void KWorkerTaskManager::AddTask(KernelCore& kernel, WorkerType type, KWorkerTask* task) {
30 ASSERT(type <= WorkerType::Count);
31 kernel.WorkerTaskManager().AddTask(kernel, task);
32}
33
34void 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
10namespace Kernel {
11
12class KernelCore;
13class KWorkerTask;
14
15class KWorkerTaskManager final {
16public:
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
26private:
27 void AddTask(KernelCore& kernel, KWorkerTask* task);
28
29private:
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
1137KWorkerTaskManager& KernelCore::WorkerTaskManager() {
1138 return impl->worker_task_manager;
1139}
1140
1141const KWorkerTaskManager& KernelCore::WorkerTaskManager() const {
1142 return impl->worker_task_manager;
1143}
1144
1140bool KernelCore::IsPhantomModeForSingleCore() const { 1145bool 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;
52class KSharedMemoryInfo; 52class KSharedMemoryInfo;
53class KThread; 53class KThread;
54class KTransferMemory; 54class KTransferMemory;
55class KWorkerTaskManager;
55class KWritableEvent; 56class KWritableEvent;
56class KCodeMemory; 57class KCodeMemory;
57class PhysicalCore; 58class 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
346private: 353private:
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
40class USB_DS final : public ServiceFramework<USB_DS> {
41public:
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
40class USB_DS final : public ServiceFramework<USB_DS> {
41public:
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
65class IClientEpSession final : public ServiceFramework<IClientEpSession> { 53class IClientEpSession final : public ServiceFramework<IClientEpSession> {
66public: 54public:
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;
16constexpr int mouse_axis_y = 1; 16constexpr int mouse_axis_y = 1;
17constexpr int wheel_axis_x = 2; 17constexpr int wheel_axis_x = 2;
18constexpr int wheel_axis_y = 3; 18constexpr int wheel_axis_y = 3;
19constexpr int motion_wheel_y = 4;
19constexpr int touch_axis_x = 10; 20constexpr int touch_axis_x = 10;
20constexpr int touch_axis_y = 11; 21constexpr int touch_axis_y = 11;
21constexpr PadIdentifier identifier = { 22constexpr 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
141void Mouse::ReleaseAllButtons() { 146void Mouse::ReleaseAllButtons() {
@@ -171,13 +176,39 @@ AnalogMapping Mouse::GetAnalogMappingForDevice(
171 return mapping; 176 return mapping;
172} 177}
173 178
179Common::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
174Common::Input::ButtonNames Mouse::GetUIName(const Common::ParamPackage& params) const { 202Common::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.
157uint Replicate(uint val, uint num_bits, uint to_bit) { 157uint 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
190uint FastReplicateTo8(uint value, uint num_bits) { 187uint 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
232uint FastReplicateTo8(uint value, uint num_bits) {
233 return FastReplicate(value, num_bits, 8);
210} 234}
211 235
212uint FastReplicateTo6(uint value, uint num_bits) { 236uint 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
228uint Div3Floor(uint v) { 240uint 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
51private: 59private:
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 {
153std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const { 153std::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
32enum class Theme {
33 Default,
34 DefaultColorful,
35 Dark,
36 DarkColorful,
37 MidnightBlue,
38 MidnightBlueColorful,
39};
40
32using Themes = std::array<std::pair<const char*, const char*>, 6>; 41using Themes = std::array<std::pair<const char*, const char*>, 6>;
33extern const Themes themes; 42extern const Themes themes;
34 43