diff options
56 files changed, 611 insertions, 197 deletions
diff --git a/src/common/bit_util.h b/src/common/bit_util.h index eef8c1c5a7..f50d3308a9 100644 --- a/src/common/bit_util.h +++ b/src/common/bit_util.h @@ -46,6 +46,12 @@ template <typename T> } template <typename T> +requires std::is_unsigned_v<T> +[[nodiscard]] constexpr bool IsPow2(T value) { + return std::has_single_bit(value); +} + +template <typename T> requires std::is_integral_v<T> [[nodiscard]] T NextPow2(T value) { 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 62010d7625..81b212e4b8 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) { // "from" might no longer be valid if the thread was killed if (auto from = weak_from.lock()) { - ASSERT(from->impl->previous_fiber != nullptr); + if (from->impl->previous_fiber == nullptr) { + ASSERT_MSG(false, "previous_fiber is nullptr!"); + return; + } from->impl->previous_fiber->impl->context = transfer.fctx; from->impl->previous_fiber->impl->guard.unlock(); from->impl->previous_fiber.reset(); diff --git a/src/common/input.h b/src/common/input.h index f775a4c011..f4f9eb30a7 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -209,6 +209,13 @@ enum class ButtonNames { Triangle, Share, Options, + + // Mouse buttons + ButtonMouseWheel, + ButtonBackward, + ButtonForward, + ButtonTask, + ButtonExtra, }; // 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 b1a7467276..6e8d119196 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -247,6 +247,9 @@ add_library(core STATIC hle/kernel/k_trace.h hle/kernel/k_transfer_memory.cpp hle/kernel/k_transfer_memory.h + hle/kernel/k_worker_task.h + hle/kernel/k_worker_task_manager.cpp + hle/kernel/k_worker_task_manager.h hle/kernel/k_writable_event.cpp hle/kernel/k_writable_event.h hle/kernel/kernel.cpp diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 08f8af551f..eef0ff4937 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) { auto& motion = console.motion_state; motion.accel = emulated.GetAcceleration(); motion.gyro = emulated.GetGyroscope(); - motion.rotation = emulated.GetGyroscope(); + motion.rotation = emulated.GetRotations(); motion.orientation = emulated.GetOrientation(); motion.quaternion = emulated.GetQuaternion(); motion.gyro_bias = emulated.GetGyroBias(); diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 13edb7332a..d12037b115 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -145,7 +145,7 @@ void EmulatedController::LoadDevices() { motion_devices.begin(), Common::Input::CreateDevice<Common::Input::InputDevice>); std::transform(trigger_params.begin(), trigger_params.end(), trigger_devices.begin(), Common::Input::CreateDevice<Common::Input::InputDevice>); - std::transform(battery_params.begin(), battery_params.begin(), battery_devices.end(), + std::transform(battery_params.begin(), battery_params.end(), battery_devices.begin(), Common::Input::CreateDevice<Common::Input::InputDevice>); std::transform(output_params.begin(), output_params.end(), output_devices.begin(), Common::Input::CreateDevice<Common::Input::OutputDevice>); diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index f5acff6e0f..860aab4002 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 if (TransformToButton(callback).value) { std::random_device device; std::mt19937 gen(device()); - std::uniform_int_distribution<s16> distribution(-1000, 1000); + std::uniform_int_distribution<s16> distribution(-5000, 5000); status.accel.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f; status.accel.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f; 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 55e6fb9f75..754b41ff67 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -341,10 +341,6 @@ public: return *thread; } - bool IsThreadWaiting() const { - return is_thread_waiting; - } - private: friend class IPC::ResponseBuilder; @@ -379,7 +375,6 @@ private: u32 domain_offset{}; std::shared_ptr<SessionRequestManager> manager; - bool is_thread_waiting{}; KernelCore& kernel; 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 0166df0a5e..1b44541b10 100644 --- a/src/core/hle/kernel/k_memory_manager.cpp +++ b/src/core/hle/kernel/k_memory_manager.cpp @@ -8,12 +8,16 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/scope_exit.h" +#include "core/core.h" +#include "core/device_memory.h" #include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_page_linked_list.h" #include "core/hle/kernel/svc_results.h" namespace Kernel { +KMemoryManager::KMemoryManager(Core::System& system_) : system{system_} {} + std::size_t KMemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u64 end_address) { const auto size{end_address - start_address}; @@ -81,7 +85,7 @@ VAddr KMemoryManager::AllocateAndOpenContinuous(std::size_t num_pages, std::size } ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, - Direction dir) { + Direction dir, u32 heap_fill_value) { ASSERT(page_list.GetNumPages() == 0); // Early return if we're allocating no pages @@ -139,6 +143,12 @@ ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_ } } + // Clear allocated memory. + for (const auto& it : page_list.Nodes()) { + std::memset(system.DeviceMemory().GetPointer(it.GetAddress()), heap_fill_value, + it.GetSize()); + } + // Only succeed if we allocated as many pages as we wanted if (num_pages) { return ResultOutOfMemory; @@ -146,11 +156,12 @@ ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_ // We succeeded! group_guard.Cancel(); + return ResultSuccess; } ResultCode KMemoryManager::Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, - Direction dir) { + Direction dir, u32 heap_fill_value) { // Early return if we're freeing no pages if (!num_pages) { return ResultSuccess; diff --git a/src/core/hle/kernel/k_memory_manager.h b/src/core/hle/kernel/k_memory_manager.h index 39badc5f11..abd6c8ace2 100644 --- a/src/core/hle/kernel/k_memory_manager.h +++ b/src/core/hle/kernel/k_memory_manager.h @@ -12,6 +12,10 @@ #include "core/hle/kernel/k_page_heap.h" #include "core/hle/result.h" +namespace Core { +class System; +} + namespace Kernel { class KPageLinkedList; @@ -42,7 +46,7 @@ public: Mask = (0xF << Shift), }; - KMemoryManager() = default; + explicit KMemoryManager(Core::System& system_); constexpr std::size_t GetSize(Pool pool) const { return managers[static_cast<std::size_t>(pool)].GetSize(); @@ -51,10 +55,10 @@ public: void InitializeManager(Pool pool, u64 start_address, u64 end_address); VAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option); - ResultCode Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, - Direction dir = Direction::FromFront); - ResultCode Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, - Direction dir = Direction::FromFront); + ResultCode Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, Direction dir, + u32 heap_fill_value = 0); + ResultCode Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, Direction dir, + u32 heap_fill_value = 0); static constexpr std::size_t MaxManagerCount = 10; @@ -129,6 +133,7 @@ private: }; private: + Core::System& system; std::array<std::mutex, static_cast<std::size_t>(Pool::Count)> pool_locks; std::array<Impl, MaxManagerCount> managers; }; diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 27d86c9a4f..b650ea31de 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 } KPageLinkedList page_linked_list; - CASCADE_CODE( - system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool)); + CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool, + allocation_option)); CASCADE_CODE(Operate(addr, num_pages, page_linked_list, OperationType::MapGroup)); block_manager->Update(addr, num_pages, state, perm); @@ -457,8 +457,8 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { KPageLinkedList page_linked_list; - CASCADE_CODE( - system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, memory_pool)); + CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, + memory_pool, allocation_option)); // We succeeded, so commit the memory reservation. memory_reservation.Commit(); @@ -541,7 +541,8 @@ ResultCode KPageTable::UnmapMemory(VAddr addr, std::size_t size) { } const std::size_t num_pages{size / PageSize}; - system.Kernel().MemoryManager().Free(page_linked_list, num_pages, memory_pool); + system.Kernel().MemoryManager().Free(page_linked_list, num_pages, memory_pool, + allocation_option); block_manager->Update(addr, num_pages, KMemoryState::Free); @@ -960,7 +961,7 @@ ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) { // Allocate pages for the heap extension. KPageLinkedList page_linked_list; R_TRY(system.Kernel().MemoryManager().Allocate(page_linked_list, allocation_size / PageSize, - memory_pool)); + memory_pool, allocation_option)); // Map the pages. { @@ -1027,8 +1028,8 @@ ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages, CASCADE_CODE(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr)); } else { KPageLinkedList page_group; - CASCADE_CODE( - system.Kernel().MemoryManager().Allocate(page_group, needed_num_pages, memory_pool)); + CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_group, needed_num_pages, + memory_pool, allocation_option)); CASCADE_CODE(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup)); } diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 274644181c..f67986e91f 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -303,6 +303,7 @@ private: bool is_aslr_enabled{}; KMemoryManager::Pool memory_pool{KMemoryManager::Pool::Application}; + KMemoryManager::Direction allocation_option{KMemoryManager::Direction::FromFront}; Common::PageTable page_table_impl; diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h index f4d71ad7ee..0b894c8cfe 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) { { t.GetActiveCore() } -> Common::ConvertibleTo<s32>; { t.GetPriority() } -> Common::ConvertibleTo<s32>; + { t.IsDummyThread() } -> Common::ConvertibleTo<bool>; }; template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority> @@ -349,24 +350,49 @@ public: // Mutators. constexpr void PushBack(Member* member) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return; + } + this->PushBack(member->GetPriority(), member); } constexpr void Remove(Member* member) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return; + } + this->Remove(member->GetPriority(), member); } constexpr void MoveToScheduledFront(Member* member) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return; + } + this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member); } constexpr KThread* MoveToScheduledBack(Member* member) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return {}; + } + return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(), member); } // First class fancy operations. constexpr void ChangePriority(s32 prev_priority, bool is_running, Member* member) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return; + } + ASSERT(IsValidPriority(prev_priority)); // Remove the member from the queues. @@ -383,6 +409,11 @@ public: constexpr void ChangeAffinityMask(s32 prev_core, const AffinityMaskType& prev_affinity, Member* member) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return; + } + // Get the new information. const s32 priority = member->GetPriority(); const AffinityMaskType& new_affinity = member->GetAffinityMask(); @@ -412,6 +443,11 @@ public: } constexpr void ChangeCore(s32 prev_core, Member* member, bool to_front = false) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return; + } + // Get the new information. const s32 new_core = member->GetActiveCore(); const s32 priority = member->GetPriority(); diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index cca405fed8..265ac6fa1e 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 return ResultSuccess; } +void KProcess::DoWorkerTaskImpl() { + UNIMPLEMENTED(); +} + KResourceLimit* KProcess::GetResourceLimit() const { return resource_limit; } @@ -477,7 +481,7 @@ void KProcess::Finalize() { } // Perform inherited finalization. - KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize(); + KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask>::Finalize(); } /** diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index e7c8b5838c..c2a6720211 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -15,6 +15,7 @@ #include "core/hle/kernel/k_condition_variable.h" #include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/k_worker_task.h" #include "core/hle/kernel/process_capability.h" #include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" @@ -62,8 +63,7 @@ enum class ProcessStatus { DebugBreak, }; -class KProcess final - : public KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject> { +class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> { KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject); public: @@ -345,6 +345,8 @@ public: bool IsSignaled() const override; + void DoWorkerTaskImpl(); + void PinCurrentThread(s32 core_id); void UnpinCurrentThread(s32 core_id); void UnpinThread(KThread* thread); diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 31cec990ed..b32d4f2857 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 if (!must_context_switch || core != current_core) { auto& phys_core = kernel.PhysicalCore(core); phys_core.Interrupt(); - } else { - must_context_switch = true; } cores_pending_reschedule &= ~(1ULL << core); } @@ -408,6 +406,9 @@ void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduli } else { RescheduleCores(kernel, cores_needing_scheduling); } + + // Special case to ensure dummy threads that are waiting block. + current_thread->IfDummyThreadTryWait(); } u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { @@ -741,6 +742,12 @@ void KScheduler::ScheduleImpl() { next_thread = idle_thread; } + // We never want to schedule a dummy thread, as these are only used by host threads for locking. + if (next_thread->GetThreadType() == ThreadType::Dummy) { + ASSERT_MSG(false, "Dummy threads should never be scheduled!"); + next_thread = idle_thread; + } + // If we're not actually switching thread, there's nothing to do. if (next_thread == current_thread.load()) { previous_thread->EnableDispatch(); diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index d4e4a6b064..4d94eb9cfd 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -8,7 +8,6 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" -#include "common/scope_exit.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" @@ -123,20 +122,10 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); - // In the event that something fails here, stub a result to prevent the game from crashing. - // This is a work-around in the event that somehow we process a service request after the - // session has been closed by the game. This has been observed to happen rarely in Pokemon - // Sword/Shield and is likely a result of us using host threads/scheduling for services. - // TODO(bunnei): Find a better solution here. - auto error_guard = SCOPE_GUARD({ CompleteSyncRequest(*context); }); - // Ensure we have a session request handler if (manager->HasSessionRequestHandler(*context)) { if (auto strong_ptr = manager->GetServiceThread().lock()) { strong_ptr->QueueSyncRequest(*parent, std::move(context)); - - // We succeeded. - error_guard.Cancel(); } else { ASSERT_MSG(false, "strong_ptr is nullptr!"); } @@ -171,13 +160,8 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { convert_to_domain = false; } - // Some service requests require the thread to block - { - KScopedSchedulerLock lock(kernel); - if (!context.IsThreadWaiting()) { - context.GetThread().EndWait(result); - } - } + // The calling thread is waiting for this request to complete, so wake it up. + context.GetThread().EndWait(result); return result; } diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 71e029a3f0..f42abb8a11 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -30,6 +30,7 @@ #include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread_queue.h" +#include "core/hle/kernel/k_worker_task_manager.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/time_manager.h" @@ -105,7 +106,7 @@ KThread::~KThread() = default; ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, s32 virt_core, KProcess* owner, ThreadType type) { // Assert parameters are valid. - ASSERT((type == ThreadType::Main) || + ASSERT((type == ThreadType::Main) || (type == ThreadType::Dummy) || (Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority)); ASSERT((owner != nullptr) || (type != ThreadType::User)); 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 UNREACHABLE_MSG("KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type)); break; } - thread_type_for_debugging = type; + thread_type = type; // Set the ideal core ID and affinity mask. virtual_ideal_core_id = virt_core; @@ -261,7 +262,7 @@ ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uint } ResultCode KThread::InitializeDummyThread(KThread* thread) { - return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Dummy); + return thread->Initialize({}, {}, {}, DummyThreadPriority, 3, {}, ThreadType::Dummy); } ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { @@ -332,7 +333,7 @@ void KThread::Finalize() { } // Perform inherited finalization. - KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>::Finalize(); + KSynchronizationObject::Finalize(); } bool KThread::IsSignaled() const { @@ -376,11 +377,28 @@ void KThread::StartTermination() { // Register terminated dpc flag. RegisterDpc(DpcFlag::Terminated); +} + +void KThread::FinishTermination() { + // Ensure that the thread is not executing on any core. + if (parent != nullptr) { + for (std::size_t i = 0; i < static_cast<std::size_t>(Core::Hardware::NUM_CPU_CORES); ++i) { + KThread* core_thread{}; + do { + core_thread = kernel.Scheduler(i).GetCurrentThread(); + } while (core_thread == this); + } + } // Close the thread. this->Close(); } +void KThread::DoWorkerTaskImpl() { + // Finish the termination that was begun by Exit(). + this->FinishTermination(); +} + void KThread::Pin(s32 current_core) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); @@ -417,12 +435,7 @@ void KThread::Pin(s32 current_core) { static_cast<u32>(ThreadState::SuspendShift))); // Update our state. - const ThreadState old_state = thread_state; - thread_state = static_cast<ThreadState>(GetSuspendFlags() | - static_cast<u32>(old_state & ThreadState::Mask)); - if (thread_state != old_state) { - KScheduler::OnThreadStateChanged(kernel, this, old_state); - } + UpdateState(); } // TODO(bunnei): Update our SVC access permissions. @@ -463,20 +476,13 @@ void KThread::Unpin() { } // Allow performing thread suspension (if termination hasn't been requested). - { + if (!IsTerminationRequested()) { // Update our allow flags. - if (!IsTerminationRequested()) { - suspend_allowed_flags |= (1 << (static_cast<u32>(SuspendType::Thread) + - static_cast<u32>(ThreadState::SuspendShift))); - } + suspend_allowed_flags |= (1 << (static_cast<u32>(SuspendType::Thread) + + static_cast<u32>(ThreadState::SuspendShift))); // Update our state. - const ThreadState old_state = thread_state; - thread_state = static_cast<ThreadState>(GetSuspendFlags() | - static_cast<u32>(old_state & ThreadState::Mask)); - if (thread_state != old_state) { - KScheduler::OnThreadStateChanged(kernel, this, old_state); - } + UpdateState(); } // TODO(bunnei): Update our SVC access permissions. @@ -689,12 +695,7 @@ void KThread::Resume(SuspendType type) { ~(1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type))); // Update our state. - const ThreadState old_state = thread_state; - thread_state = static_cast<ThreadState>(GetSuspendFlags() | - static_cast<u32>(old_state & ThreadState::Mask)); - if (thread_state != old_state) { - KScheduler::OnThreadStateChanged(kernel, this, old_state); - } + this->UpdateState(); } void KThread::WaitCancel() { @@ -721,19 +722,22 @@ void KThread::TrySuspend() { ASSERT(GetNumKernelWaiters() == 0); // Perform the suspend. - Suspend(); + this->UpdateState(); } -void KThread::Suspend() { +void KThread::UpdateState() { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); - ASSERT(IsSuspendRequested()); // Set our suspend flags in state. const auto old_state = thread_state; - thread_state = static_cast<ThreadState>(GetSuspendFlags()) | (old_state & ThreadState::Mask); + const auto new_state = + static_cast<ThreadState>(this->GetSuspendFlags()) | (old_state & ThreadState::Mask); + thread_state = new_state; // Note the state change in scheduler. - KScheduler::OnThreadStateChanged(kernel, this, old_state); + if (new_state != old_state) { + KScheduler::OnThreadStateChanged(kernel, this, old_state); + } } void KThread::Continue() { @@ -998,13 +1002,16 @@ ResultCode KThread::Run() { // If the current thread has been asked to suspend, suspend it and retry. if (GetCurrentThread(kernel).IsSuspended()) { - GetCurrentThread(kernel).Suspend(); + GetCurrentThread(kernel).UpdateState(); continue; } // If we're not a kernel thread and we've been asked to suspend, suspend ourselves. - if (IsUserThread() && IsSuspended()) { - Suspend(); + if (KProcess* owner = this->GetOwnerProcess(); owner != nullptr) { + if (IsUserThread() && IsSuspended()) { + this->UpdateState(); + } + owner->IncrementThreadCount(); } // Set our state and finish. @@ -1031,9 +1038,16 @@ void KThread::Exit() { // Disallow all suspension. suspend_allowed_flags = 0; + this->UpdateState(); + + // Disallow all suspension. + suspend_allowed_flags = 0; // Start termination. StartTermination(); + + // Register the thread as a work task. + KWorkerTaskManager::AddTask(kernel, KWorkerTaskManager::WorkerType::Exit, this); } } @@ -1061,12 +1075,46 @@ ResultCode KThread::Sleep(s64 timeout) { return ResultSuccess; } +void KThread::IfDummyThreadTryWait() { + if (!IsDummyThread()) { + return; + } + + if (GetState() != ThreadState::Waiting) { + return; + } + + // Block until we can grab the lock. + KScopedSpinLock lk{dummy_wait_lock}; +} + +void KThread::IfDummyThreadBeginWait() { + if (!IsDummyThread()) { + return; + } + + // Ensure the thread will block when IfDummyThreadTryWait is called. + dummy_wait_lock.Lock(); +} + +void KThread::IfDummyThreadEndWait() { + if (!IsDummyThread()) { + return; + } + + // Ensure the thread will no longer block. + dummy_wait_lock.Unlock(); +} + void KThread::BeginWait(KThreadQueue* queue) { // Set our state as waiting. SetState(ThreadState::Waiting); // Set our wait queue. wait_queue = queue; + + // Special case for dummy threads to ensure they block. + IfDummyThreadBeginWait(); } void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { @@ -1085,7 +1133,16 @@ void KThread::EndWait(ResultCode wait_result_) { // If we're waiting, notify our queue that we're available. if (GetState() == ThreadState::Waiting) { + if (wait_queue == nullptr) { + // This should never happen, but avoid a hard crash below to get this logged. + ASSERT_MSG(false, "wait_queue is nullptr!"); + return; + } + wait_queue->EndWait(this, wait_result_); + + // Special case for dummy threads to wakeup if necessary. + IfDummyThreadEndWait(); } } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 83dfde69b4..d058db62ce 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -19,6 +19,7 @@ #include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_spin_lock.h" #include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/k_worker_task.h" #include "core/hle/kernel/slab_helpers.h" #include "core/hle/kernel/svc_common.h" #include "core/hle/kernel/svc_types.h" @@ -100,7 +101,7 @@ enum class ThreadWaitReasonForDebugging : u32 { [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); -class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>, +class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>, public boost::intrusive::list_base_hook<> { KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); @@ -111,6 +112,7 @@ private: public: static constexpr s32 DefaultThreadPriority = 44; static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1; + static constexpr s32 DummyThreadPriority = Svc::LowestThreadPriority + 2; explicit KThread(KernelCore& kernel_); ~KThread() override; @@ -192,9 +194,9 @@ public: void TrySuspend(); - void Continue(); + void UpdateState(); - void Suspend(); + void Continue(); constexpr void SetSyncedIndex(s32 index) { synced_index = index; @@ -385,6 +387,8 @@ public: void OnTimer(); + void DoWorkerTaskImpl(); + static void PostDestroy(uintptr_t arg); [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread); @@ -550,8 +554,12 @@ public: return wait_reason_for_debugging; } - [[nodiscard]] ThreadType GetThreadTypeForDebugging() const { - return thread_type_for_debugging; + [[nodiscard]] ThreadType GetThreadType() const { + return thread_type; + } + + [[nodiscard]] bool IsDummyThread() const { + return GetThreadType() == ThreadType::Dummy; } void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { @@ -628,6 +636,14 @@ public: return condvar_key; } + // Dummy threads (used for HLE host threads) cannot wait based on the guest scheduler, and + // therefore will not block on guest kernel synchronization primitives. These methods handle + // blocking as needed. + + void IfDummyThreadTryWait(); + void IfDummyThreadBeginWait(); + void IfDummyThreadEndWait(); + private: static constexpr size_t PriorityInheritanceCountMax = 10; union SyncObjectBuffer { @@ -679,6 +695,8 @@ private: void StartTermination(); + void FinishTermination(); + [[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, s32 virt_core, KProcess* owner, ThreadType type); @@ -744,16 +762,17 @@ private: bool resource_limit_release_hint{}; StackParameters stack_parameters{}; KSpinLock context_guard{}; + KSpinLock dummy_wait_lock{}; // For emulation std::shared_ptr<Common::Fiber> host_context{}; bool is_single_core{}; + ThreadType thread_type{}; // For debugging std::vector<KSynchronizationObject*> wait_objects_for_debugging; VAddr mutex_wait_address_for_debugging{}; ThreadWaitReasonForDebugging wait_reason_for_debugging{}; - ThreadType thread_type_for_debugging{}; public: 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 0000000000..b7794c6a84 --- /dev/null +++ b/src/core/hle/kernel/k_worker_task.h @@ -0,0 +1,18 @@ +// Copyright 2022 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/k_synchronization_object.h" + +namespace Kernel { + +class KWorkerTask : public KSynchronizationObject { +public: + explicit KWorkerTask(KernelCore& kernel_); + + void DoWorkerTask(); +}; + +} // 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 0000000000..785e081110 --- /dev/null +++ b/src/core/hle/kernel/k_worker_task_manager.cpp @@ -0,0 +1,42 @@ +// Copyright 2022 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_worker_task.h" +#include "core/hle/kernel/k_worker_task_manager.h" +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +KWorkerTask::KWorkerTask(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} + +void KWorkerTask::DoWorkerTask() { + if (auto* const thread = this->DynamicCast<KThread*>(); thread != nullptr) { + return thread->DoWorkerTaskImpl(); + } else { + auto* const process = this->DynamicCast<KProcess*>(); + ASSERT(process != nullptr); + + return process->DoWorkerTaskImpl(); + } +} + +KWorkerTaskManager::KWorkerTaskManager() : m_waiting_thread(1, "yuzu:KWorkerTaskManager") {} + +void KWorkerTaskManager::AddTask(KernelCore& kernel, WorkerType type, KWorkerTask* task) { + ASSERT(type <= WorkerType::Count); + kernel.WorkerTaskManager().AddTask(kernel, task); +} + +void KWorkerTaskManager::AddTask(KernelCore& kernel, KWorkerTask* task) { + KScopedSchedulerLock sl(kernel); + m_waiting_thread.QueueWork([task]() { + // Do the task. + task->DoWorkerTask(); + }); +} + +} // 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 0000000000..43d1bfcec4 --- /dev/null +++ b/src/core/hle/kernel/k_worker_task_manager.h @@ -0,0 +1,33 @@ +// Copyright 2022 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" +#include "common/thread_worker.h" + +namespace Kernel { + +class KernelCore; +class KWorkerTask; + +class KWorkerTaskManager final { +public: + enum class WorkerType : u32 { + Exit, + Count, + }; + + KWorkerTaskManager(); + + static void AddTask(KernelCore& kernel_, WorkerType type, KWorkerTask* task); + +private: + void AddTask(KernelCore& kernel, KWorkerTask* task); + +private: + Common::ThreadWorker m_waiting_thread; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0b618fb46f..49c0714ed0 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -37,6 +37,7 @@ #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_slab_heap.h" #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_worker_task_manager.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/service_thread.h" @@ -300,12 +301,10 @@ struct KernelCore::Impl { // Gets the dummy KThread for the caller, allocating a new one if this is the first time KThread* GetHostDummyThread() { auto make_thread = [this]() { - std::lock_guard lk(dummy_thread_lock); - auto& thread = dummy_threads.emplace_back(std::make_unique<KThread>(system.Kernel())); - KAutoObject::Create(thread.get()); - ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess()); + KThread* thread = KThread::Create(system.Kernel()); + ASSERT(KThread::InitializeDummyThread(thread).IsSuccess()); thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); - return thread.get(); + return thread; }; thread_local KThread* saved_thread = make_thread(); @@ -630,7 +629,7 @@ struct KernelCore::Impl { const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents(); // Initialize memory managers - memory_manager = std::make_unique<KMemoryManager>(); + memory_manager = std::make_unique<KMemoryManager>(system); memory_manager->InitializeManager(KMemoryManager::Pool::Application, application_pool.GetAddress(), application_pool.GetEndAddress()); @@ -730,7 +729,6 @@ struct KernelCore::Impl { std::mutex server_sessions_lock; std::mutex registered_objects_lock; std::mutex registered_in_use_objects_lock; - std::mutex dummy_thread_lock; std::atomic<u32> next_object_id{0}; std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin}; @@ -787,9 +785,6 @@ struct KernelCore::Impl { std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; - // Specifically tracked to be automatically destroyed with kernel - std::vector<std::unique_ptr<KThread>> dummy_threads; - bool is_multicore{}; std::atomic_bool is_shutting_down{}; bool is_phantom_mode_for_singlecore{}; @@ -797,6 +792,8 @@ struct KernelCore::Impl { std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{}; + KWorkerTaskManager worker_task_manager; + // System context Core::System& system; }; @@ -1137,6 +1134,14 @@ const Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() const { return impl->slab_resource_counts; } +KWorkerTaskManager& KernelCore::WorkerTaskManager() { + return impl->worker_task_manager; +} + +const KWorkerTaskManager& KernelCore::WorkerTaskManager() const { + return impl->worker_task_manager; +} + bool KernelCore::IsPhantomModeForSingleCore() const { return impl->IsPhantomModeForSingleCore(); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index b9b4239082..0e04fc3bb3 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -52,6 +52,7 @@ class KSharedMemory; class KSharedMemoryInfo; class KThread; class KTransferMemory; +class KWorkerTaskManager; class KWritableEvent; class KCodeMemory; class PhysicalCore; @@ -343,6 +344,12 @@ public: /// Gets the current slab resource counts. const Init::KSlabResourceCounts& SlabResourceCounts() const; + /// Gets the current worker task manager, used for dispatching KThread/KProcess tasks. + KWorkerTaskManager& WorkerTaskManager(); + + /// Gets the current worker task manager, used for dispatching KThread/KProcess tasks. + const KWorkerTaskManager& WorkerTaskManager() const; + private: friend class KProcess; friend class KThread; diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index 03f3dec104..4eb3a5988c 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp @@ -12,6 +12,7 @@ #include "common/scope_exit.h" #include "common/thread.h" #include "core/hle/kernel/k_session.h" +#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/service_thread.h" @@ -50,6 +51,10 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std kernel.RegisterHostThread(); + // Ensure the dummy thread allocated for this host thread is closed on exit. + auto* dummy_thread = kernel.GetCurrentEmuThread(); + SCOPE_EXIT({ dummy_thread->Close(); }); + while (true) { std::function<void()> task; diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index 94a1b8814b..f4034d5916 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> {130, nullptr, "ActivateOpenContextRetention"}, {140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"}, {150, nullptr, "AuthenticateApplicationAsync"}, - {151, nullptr, "Unknown151"}, - {152, nullptr, "Unknown152"}, + {151, nullptr, "EnsureSignedDeviceIdentifierCacheForNintendoAccountAsync"}, + {152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"}, {190, nullptr, "GetUserLastOpenedApplication"}, {191, nullptr, "ActivateOpenContextHolder"}, {200, nullptr, "BeginUserRegistration"}, diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index 6ce7fe8e67..991921984e 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> {130, nullptr, "ActivateOpenContextRetention"}, {140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"}, {150, nullptr, "AuthenticateApplicationAsync"}, - {151, nullptr, "Unknown151"}, - {152, nullptr, "Unknown152"}, + {151, nullptr, "EnsureSignedDeviceIdentifierCacheForNintendoAccountAsync"}, + {152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"}, {190, nullptr, "GetUserLastOpenedApplication"}, {191, nullptr, "ActivateOpenContextHolder"}, {997, nullptr, "DebugInvalidateTokenCacheForUser"}, diff --git a/src/core/hle/service/am/omm.cpp b/src/core/hle/service/am/omm.cpp index 55de67e1d4..6da9b9f583 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"} { {25, nullptr, "SetApplicationCecSettingsAndNotifyChanged"}, {26, nullptr, "GetOperationModeSystemInfo"}, {27, nullptr, "GetAppletFullAwakingSystemEvent"}, + {28, nullptr, "CreateCradleFirmwareUpdater"}, }; // clang-format on diff --git a/src/core/hle/service/apm/apm_interface.cpp b/src/core/hle/service/apm/apm_interface.cpp index e58bad0833..6163e3294e 100644 --- a/src/core/hle/service/apm/apm_interface.cpp +++ b/src/core/hle/service/apm/apm_interface.cpp @@ -17,7 +17,7 @@ public: static const FunctionInfo functions[] = { {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"}, {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"}, - {2, nullptr, "SetCpuOverclockEnabled"}, + {2, &ISession::SetCpuOverclockEnabled, "SetCpuOverclockEnabled"}, }; RegisterHandlers(functions); } @@ -47,6 +47,18 @@ private: rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode)); } + void SetCpuOverclockEnabled(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto cpu_overclock_enabled = rp.Pop<bool>(); + + LOG_WARNING(Service_APM, "(STUBBED) called, cpu_overclock_enabled={}", + cpu_overclock_enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + Controller& controller; }; diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp index 2e46e7161c..260fd0e0e5 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"} { {27, nullptr, "SetVolumeMappingTableForDev"}, {28, nullptr, "GetAudioOutputChannelCountForPlayReport"}, {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, - {30, nullptr, "Unknown30"}, - {31, nullptr, "Unknown31"}, - {32, nullptr, "Unknown32"}, - {33, nullptr, "Unknown33"}, - {34, nullptr, "Unknown34"}, - {10000, nullptr, "Unknown10000"}, - {10001, nullptr, "Unknown10001"}, - {10002, nullptr, "Unknown10002"}, + {30, nullptr, "SetSpeakerAutoMuteEnabled"}, + {31, nullptr, "IsSpeakerAutoMuteEnabled"}, + {32, nullptr, "GetActiveOutputTarget"}, + {33, nullptr, "GetTargetDeviceInfo"}, + {34, nullptr, "AcquireTargetNotification"}, + {10000, nullptr, "NotifyAudioOutputTargetForPlayReport"}, + {10001, nullptr, "NotifyAudioOutputChannelCountForPlayReport"}, + {10002, nullptr, "NotifyUnsupportedUsbOutputDeviceAttachedForPlayReport"}, }; // clang-format on diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index d337fd317b..cc268d8779 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp @@ -201,6 +201,22 @@ public: {62, nullptr, "Unknown62"}, {63, nullptr, "Unknown63"}, {64, nullptr, "Unknown64"}, + {65, nullptr, "Unknown65"}, + {66, nullptr, "Unknown66"}, + {67, nullptr, "Unknown67"}, + {68, nullptr, "Unknown68"}, + {69, nullptr, "Unknown69"}, + {70, nullptr, "Unknown70"}, + {71, nullptr, "Unknown71"}, + {72, nullptr, "Unknown72"}, + {73, nullptr, "Unknown73"}, + {74, nullptr, "Unknown74"}, + {75, nullptr, "Unknown75"}, + {76, nullptr, "Unknown76"}, + {100, nullptr, "Unknown100"}, + {101, nullptr, "Unknown101"}, + {110, nullptr, "Unknown102"}, + {111, nullptr, "Unknown103"}, }; // clang-format on @@ -249,6 +265,20 @@ public: {7, nullptr, "AcquireRadioEvent"}, {8, nullptr, "AcquireGamepadPairingEvent"}, {9, nullptr, "IsGamepadPairingStarted"}, + {10, nullptr, "StartAudioDeviceDiscovery"}, + {11, nullptr, "StopAudioDeviceDiscovery"}, + {12, nullptr, "IsDiscoveryingAudioDevice"}, + {13, nullptr, "GetDiscoveredAudioDevice"}, + {14, nullptr, "AcquireAudioDeviceConnectionEvent"}, + {15, nullptr, "ConnectAudioDevice"}, + {16, nullptr, "IsConnectingAudioDevice"}, + {17, nullptr, "GetConnectedAudioDevices"}, + {18, nullptr, "DisconnectAudioDevice"}, + {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"}, + {20, nullptr, "GetPairedAudioDevices"}, + {21, nullptr, "RemoveAudioDevicePairing"}, + {22, nullptr, "RequestAudioDeviceConnectionRejection"}, + {23, nullptr, "CancelAudioDeviceConnectionRejection"} }; // clang-format on diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 3501bc1a46..b087e7bba7 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_) {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, {204, nullptr, "OpenDataFileSystemByProgramIndex"}, {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"}, + {206, nullptr, "OpenDataStorageByPath"}, {400, nullptr, "OpenDeviceOperator"}, {500, nullptr, "OpenSdCardDetectionEventNotifier"}, {501, nullptr, "OpenGameCardDetectionEventNotifier"}, @@ -796,6 +797,8 @@ FSP_SRV::FSP_SRV(Core::System& system_) {1014, nullptr, "OutputMultiProgramTagAccessLog"}, {1016, nullptr, "FlushAccessLogOnSdCard"}, {1017, nullptr, "OutputApplicationInfoAccessLog"}, + {1018, nullptr, "SetDebugOption"}, + {1019, nullptr, "UnsetDebugOption"}, {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 3c36f4085e..9f9cea1e07 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -27,13 +27,13 @@ public: {10101, &IFriendService::GetFriendList, "GetFriendList"}, {10102, nullptr, "UpdateFriendInfo"}, {10110, nullptr, "GetFriendProfileImage"}, - {10120, nullptr, "Unknown10120"}, - {10121, nullptr, "Unknown10121"}, + {10120, nullptr, "IsFriendListCacheAvailable"}, + {10121, nullptr, "EnsureFriendListAvailable"}, {10200, nullptr, "SendFriendRequestForApplication"}, {10211, nullptr, "AddFacedFriendRequestForApplication"}, {10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"}, - {10420, nullptr, "Unknown10420"}, - {10421, nullptr, "Unknown10421"}, + {10420, nullptr, "IsBlockedUserListCacheAvailable"}, + {10421, nullptr, "EnsureBlockedUserListAvailable"}, {10500, nullptr, "GetProfileList"}, {10600, nullptr, "DeclareOpenOnlinePlaySession"}, {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"}, @@ -103,8 +103,8 @@ public: {30900, nullptr, "SendFriendInvitation"}, {30910, nullptr, "ReadFriendInvitation"}, {30911, nullptr, "ReadAllFriendInvitations"}, - {40100, nullptr, "Unknown40100"}, - {40400, nullptr, "Unknown40400"}, + {40100, nullptr, "DeleteFriendListCache"}, + {40400, nullptr, "DeleteBlockedUserListCache"}, {49900, nullptr, "DeleteNetworkServiceAccountCache"}, }; // clang-format on diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 84da38b3b1..a2bf7defb7 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) { const auto parameters{rp.PopRaw<Parameters>()}; - applet_resource->GetController<Controller_NPad>(HidController::NPad) + GetAppletResource() + ->GetController<Controller_NPad>(HidController::NPad) .SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp); LOG_WARNING(Service_HID, diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index 196f274e17..4fc23a9587 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp @@ -211,6 +211,11 @@ public: {127, nullptr, "Unknown127"}, {128, nullptr, "Unknown128"}, {129, nullptr, "Unknown129"}, + {130, nullptr, "Unknown130"}, + {131, nullptr, "Unknown131"}, + {132, nullptr, "Unknown132"}, + {133, nullptr, "Unknown133"}, + {134, nullptr, "Unknown134"}, }; // clang-format on @@ -287,6 +292,7 @@ public: {502, nullptr, "RequestDownloadTicketForPrepurchasedContents"}, {503, nullptr, "RequestSyncTicket"}, {504, nullptr, "RequestDownloadTicketForPrepurchasedContents2"}, + {505, nullptr, "RequestDownloadTicketForPrepurchasedContentsForAccount"}, }; // clang-format on diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 382ddcae54..5eaad04746 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_ {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, {606, nullptr, "GetContentMetaStorage"}, {607, nullptr, "ListAvailableAddOnContent"}, + {609, nullptr, "ListAvailabilityAssuredAddOnContent"}, {700, nullptr, "PushDownloadTaskList"}, {701, nullptr, "ClearTaskStatusList"}, {702, nullptr, "RequestDownloadTaskList"}, @@ -289,6 +290,11 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_ {2514, nullptr, "ClearTaskOfAsyncTaskManager"}, {2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"}, {2516, nullptr, "EnsureApplicationCertificate"}, + {2517, nullptr, "CreateApplicationInstance"}, + {2518, nullptr, "UpdateQualificationForDebug"}, + {2519, nullptr, "IsQualificationTransitionSupported"}, + {2520, nullptr, "IsQualificationTransitionSupportedByProcessId"}, + {2521, nullptr, "GetRightsUserChangedEvent"}, {2800, nullptr, "GetApplicationIdOfPreomia"}, {3000, nullptr, "RegisterDeviceLockKey"}, {3001, nullptr, "UnregisterDeviceLockKey"}, diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index 286578b17b..38e6eae04d 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"} { {202, nullptr, "SetFieldTestingFlag"}, {203, nullptr, "GetPanelCrcMode"}, {204, nullptr, "SetPanelCrcMode"}, + {205, nullptr, "GetNxControllerSettingsEx"}, + {206, nullptr, "SetNxControllerSettingsEx"}, }; // clang-format on diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp index 502dfbb4ac..0747c33cde 100644 --- a/src/core/hle/service/usb/usb.cpp +++ b/src/core/hle/service/usb/usb.cpp @@ -17,34 +17,9 @@ public: explicit IDsInterface(Core::System& system_) : ServiceFramework{system_, "IDsInterface"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "GetDsEndpoint"}, - {1, nullptr, "GetSetupEvent"}, - {2, nullptr, "Unknown2"}, - {3, nullptr, "EnableInterface"}, - {4, nullptr, "DisableInterface"}, - {5, nullptr, "CtrlInPostBufferAsync"}, - {6, nullptr, "CtrlOutPostBufferAsync"}, - {7, nullptr, "GetCtrlInCompletionEvent"}, - {8, nullptr, "GetCtrlInReportData"}, - {9, nullptr, "GetCtrlOutCompletionEvent"}, - {10, nullptr, "GetCtrlOutReportData"}, - {11, nullptr, "StallCtrl"}, - {12, nullptr, "AppendConfigurationData"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class USB_DS final : public ServiceFramework<USB_DS> { -public: - explicit USB_DS(Core::System& system_) : ServiceFramework{system_, "usb:ds"} { - // clang-format off - static const FunctionInfo functions[] = { {0, nullptr, "BindDevice"}, {1, nullptr, "BindClientProcess"}, - {2, nullptr, "GetDsInterface"}, + {2, nullptr, "AddInterface"}, {3, nullptr, "GetStateChangeEvent"}, {4, nullptr, "GetState"}, {5, nullptr, "ClearDeviceData"}, @@ -62,6 +37,19 @@ public: } }; +class USB_DS final : public ServiceFramework<USB_DS> { +public: + explicit USB_DS(Core::System& system_) : ServiceFramework{system_, "usb:ds"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "OpenDsService"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + class IClientEpSession final : public ServiceFramework<IClientEpSession> { public: explicit IClientEpSession(Core::System& system_) @@ -120,7 +108,7 @@ public: {5, nullptr, "DestroyInterfaceAvailableEvent"}, {6, nullptr, "GetInterfaceStateChangeEvent"}, {7, nullptr, "AcquireUsbIf"}, - {8, nullptr, "Unknown8"}, + {8, nullptr, "ResetDevice"}, }; // clang-format on diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp index 44957e01db..f10b8c8537 100644 --- a/src/core/hle/service/wlan/wlan.cpp +++ b/src/core/hle/service/wlan/wlan.cpp @@ -53,6 +53,7 @@ public: {35, nullptr, "Unknown35"}, {36, nullptr, "Unknown36"}, {37, nullptr, "Unknown37"}, + {38, nullptr, "Unknown38"}, }; // clang-format on @@ -117,7 +118,6 @@ public: {49, nullptr, "Unknown49"}, {50, nullptr, "Unknown50"}, {51, nullptr, "Unknown51"}, - {52, nullptr, "Unknown52"}, }; // clang-format on diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index aa69216c8d..d8ae7f0c12 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; constexpr int mouse_axis_y = 1; constexpr int wheel_axis_x = 2; constexpr int wheel_axis_y = 3; +constexpr int motion_wheel_y = 4; constexpr int touch_axis_x = 10; constexpr int touch_axis_y = 11; constexpr PadIdentifier identifier = { @@ -30,8 +31,9 @@ Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) PreSetAxis(identifier, mouse_axis_y); PreSetAxis(identifier, wheel_axis_x); PreSetAxis(identifier, wheel_axis_y); + PreSetAxis(identifier, motion_wheel_y); PreSetAxis(identifier, touch_axis_x); - PreSetAxis(identifier, touch_axis_x); + PreSetAxis(identifier, touch_axis_y); update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); }); } @@ -48,6 +50,8 @@ void Mouse::UpdateThread(std::stop_token stop_token) { SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity); } + SetAxis(identifier, motion_wheel_y, 0.0f); + if (mouse_panning_timout++ > 20) { StopPanning(); } @@ -136,6 +140,7 @@ void Mouse::MouseWheelChange(int x, int y) { wheel_position.y += y; SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x)); SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y)); + SetAxis(identifier, motion_wheel_y, static_cast<f32>(y) / 100.0f); } void Mouse::ReleaseAllButtons() { @@ -171,13 +176,39 @@ AnalogMapping Mouse::GetAnalogMappingForDevice( return mapping; } +Common::Input::ButtonNames Mouse::GetUIButtonName(const Common::ParamPackage& params) const { + const auto button = static_cast<MouseButton>(params.Get("button", 0)); + switch (button) { + case MouseButton::Left: + return Common::Input::ButtonNames::ButtonLeft; + case MouseButton::Right: + return Common::Input::ButtonNames::ButtonRight; + case MouseButton::Wheel: + return Common::Input::ButtonNames::ButtonMouseWheel; + case MouseButton::Backward: + return Common::Input::ButtonNames::ButtonBackward; + case MouseButton::Forward: + return Common::Input::ButtonNames::ButtonForward; + case MouseButton::Task: + return Common::Input::ButtonNames::ButtonTask; + case MouseButton::Extra: + return Common::Input::ButtonNames::ButtonExtra; + case MouseButton::Undefined: + default: + return Common::Input::ButtonNames::Undefined; + } +} + Common::Input::ButtonNames Mouse::GetUIName(const Common::ParamPackage& params) const { if (params.Has("button")) { - return Common::Input::ButtonNames::Value; + return GetUIButtonName(params); } if (params.Has("axis")) { return Common::Input::ButtonNames::Value; } + if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) { + return Common::Input::ButtonNames::Engine; + } return Common::Input::ButtonNames::Invalid; } diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 0404461781..c5833b8ede 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -69,6 +69,8 @@ private: void UpdateThread(std::stop_token stop_token); void StopPanning(); + Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; + Common::Vec2<int> mouse_origin; Common::Vec2<int> last_mouse_position; 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 41701e24d7..ed62817722 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -198,9 +198,9 @@ public: if (sdl_controller) { switch (SDL_GameControllerGetType(sdl_controller.get())) { case SDL_CONTROLLER_TYPE_XBOX360: - return "XBox 360 Controller"; + return "Xbox 360 Controller"; case SDL_CONTROLLER_TYPE_XBOXONE: - return "XBox One Controller"; + return "Xbox One Controller"; case SDL_CONTROLLER_TYPE_PS3: return "DualShock 3 Controller"; case SDL_CONTROLLER_TYPE_PS4: diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index c8a12c7d53..9aaeb91be8 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -192,6 +192,25 @@ std::size_t UDPClient::GetClientNumber(std::string_view host, u16 port) const { return MAX_UDP_CLIENTS; } +BatteryLevel UDPClient::GetBatteryLevel(Response::Battery battery) const { + switch (battery) { + case Response::Battery::Dying: + return BatteryLevel::Empty; + case Response::Battery::Low: + return BatteryLevel::Critical; + case Response::Battery::Medium: + return BatteryLevel::Low; + case Response::Battery::High: + return BatteryLevel::Medium; + case Response::Battery::Full: + case Response::Battery::Charged: + return BatteryLevel::Full; + case Response::Battery::Charging: + default: + return BatteryLevel::Charging; + } +} + void UDPClient::OnVersion([[maybe_unused]] Response::Version data) { LOG_TRACE(Input, "Version packet received: {}", data.version); } @@ -299,6 +318,8 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) { const int button = static_cast<int>(buttons[i]); SetButton(identifier, button, button_status); } + + SetBattery(identifier, GetBatteryLevel(data.info.battery)); } void UDPClient::StartCommunication(std::size_t client, const std::string& host, u16 port) { diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h index 1adc947c45..61a1fff376 100644 --- a/src/input_common/drivers/udp_client.h +++ b/src/input_common/drivers/udp_client.h @@ -15,6 +15,7 @@ namespace InputCommon::CemuhookUDP { class Socket; namespace Response { +enum class Battery : u8; struct PadData; struct PortInfo; struct TouchPad; @@ -137,6 +138,9 @@ private: // Translates configuration to client number std::size_t GetClientNumber(std::string_view host, u16 port) const; + // Translates UDP battery level to input engine battery level + BatteryLevel GetBatteryLevel(Response::Battery battery) const; + void OnVersion(Response::Version); void OnPortInfo(Response::PortInfo); void OnPadData(Response::PadData, std::size_t client); diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index b57330e51d..0508b408d3 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -173,7 +173,7 @@ void InputEngine::ResetButtonState() { SetButton(controller.first, button.first, false); } for (const auto& button : controller.second.hat_buttons) { - SetHatButton(controller.first, button.first, false); + SetHatButton(controller.first, button.first, 0); } } } diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp index 6e0024b2da..475257f422 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) { } new_input.Set("port", static_cast<int>(data.pad.port)); new_input.Set("pad", static_cast<int>(data.pad.pad)); + + // If engine is mouse map the mouse position as 3 axis motion + if (data.engine == "mouse") { + new_input.Set("axis_x", 1); + new_input.Set("invert_x", "-"); + new_input.Set("axis_y", 0); + new_input.Set("axis_z", 4); + new_input.Set("range", 1.0f); + new_input.Set("deadzone", 0.0f); + input_queue.Push(new_input); + return; + } + switch (data.type) { case EngineInputType::Button: 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 bb7f1a0fd3..e816a93ecb 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) { std::string definition{fmt::format("layout(location={}", index)}; const u32 remainder{4 - element}; const TransformFeedbackVarying* xfb_varying{}; - if (!runtime_info.xfb_varyings.empty()) { - xfb_varying = &runtime_info.xfb_varyings[base_index + element]; - xfb_varying = xfb_varying && xfb_varying->components > 0 ? xfb_varying : nullptr; + const size_t xfb_varying_index{base_index + element}; + if (xfb_varying_index < runtime_info.xfb_varyings.size()) { + xfb_varying = &runtime_info.xfb_varyings[xfb_varying_index]; + xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; } const u32 num_components{xfb_varying ? xfb_varying->components : remainder}; 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 d3ba66569b..cd90c084aa 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 while (element < 4) { const u32 remainder{4 - element}; const TransformFeedbackVarying* xfb_varying{}; - if (!ctx.runtime_info.xfb_varyings.empty()) { - xfb_varying = &ctx.runtime_info.xfb_varyings[base_attr_index + element]; - xfb_varying = xfb_varying && xfb_varying->components > 0 ? xfb_varying : nullptr; + const size_t xfb_varying_index{base_attr_index + element}; + if (xfb_varying_index < ctx.runtime_info.xfb_varyings.size()) { + xfb_varying = &ctx.runtime_info.xfb_varyings[xfb_varying_index]; + xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; } const u32 num_components{xfb_varying ? xfb_varying->components : remainder}; diff --git a/src/video_core/command_classes/codecs/codec.h b/src/video_core/command_classes/codecs/codec.h index 13ed883821..de56721550 100644 --- a/src/video_core/command_classes/codecs/codec.h +++ b/src/video_core/command_classes/codecs/codec.h @@ -66,7 +66,7 @@ private: bool initialized{}; NvdecCommon::VideoCodec current_codec{NvdecCommon::VideoCodec::None}; - AVCodec* av_codec{nullptr}; + const AVCodec* av_codec{nullptr}; AVCodecContext* av_codec_ctx{nullptr}; AVBufferRef* av_gpu_decoder{nullptr}; diff --git a/src/video_core/host_shaders/astc_decoder.comp b/src/video_core/host_shaders/astc_decoder.comp index f34c5f5d98..3a10578cb9 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) { // Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)] // is the same as [(num_bits - 1):0] and repeats all the way down. uint Replicate(uint val, uint num_bits, uint to_bit) { - if (num_bits == 0 || to_bit == 0) { - return 0; - } const uint v = val & uint((1 << num_bits) - 1); uint res = v; uint reslen = num_bits; @@ -187,42 +184,57 @@ uint ReplicateBitTo9(uint value) { return REPLICATE_1_BIT_TO_9_TABLE[value]; } -uint FastReplicateTo8(uint value, uint num_bits) { - switch (num_bits) { - case 1: - return REPLICATE_1_BIT_TO_8_TABLE[value]; - case 2: - return REPLICATE_2_BIT_TO_8_TABLE[value]; - case 3: - return REPLICATE_3_BIT_TO_8_TABLE[value]; - case 4: - return REPLICATE_4_BIT_TO_8_TABLE[value]; - case 5: - return REPLICATE_5_BIT_TO_8_TABLE[value]; - case 6: - return REPLICATE_6_BIT_TO_8_TABLE[value]; - case 7: - return REPLICATE_7_BIT_TO_8_TABLE[value]; - case 8: +uint FastReplicate(uint value, uint num_bits, uint to_bit) { + if (num_bits == 0) { + return 0; + } + if (num_bits == to_bit) { return value; } - return Replicate(value, num_bits, 8); + if (to_bit == 6) { + switch (num_bits) { + case 1: + return REPLICATE_1_BIT_TO_6_TABLE[value]; + case 2: + return REPLICATE_2_BIT_TO_6_TABLE[value]; + case 3: + return REPLICATE_3_BIT_TO_6_TABLE[value]; + case 4: + return REPLICATE_4_BIT_TO_6_TABLE[value]; + case 5: + return REPLICATE_5_BIT_TO_6_TABLE[value]; + default: + break; + } + } else { /* if (to_bit == 8) */ + switch (num_bits) { + case 1: + return REPLICATE_1_BIT_TO_8_TABLE[value]; + case 2: + return REPLICATE_2_BIT_TO_8_TABLE[value]; + case 3: + return REPLICATE_3_BIT_TO_8_TABLE[value]; + case 4: + return REPLICATE_4_BIT_TO_8_TABLE[value]; + case 5: + return REPLICATE_5_BIT_TO_8_TABLE[value]; + case 6: + return REPLICATE_6_BIT_TO_8_TABLE[value]; + case 7: + return REPLICATE_7_BIT_TO_8_TABLE[value]; + default: + break; + } + } + return Replicate(value, num_bits, to_bit); +} + +uint FastReplicateTo8(uint value, uint num_bits) { + return FastReplicate(value, num_bits, 8); } uint FastReplicateTo6(uint value, uint num_bits) { - switch (num_bits) { - case 1: - return REPLICATE_1_BIT_TO_6_TABLE[value]; - case 2: - return REPLICATE_2_BIT_TO_6_TABLE[value]; - case 3: - return REPLICATE_3_BIT_TO_6_TABLE[value]; - case 4: - return REPLICATE_4_BIT_TO_6_TABLE[value]; - case 5: - return REPLICATE_5_BIT_TO_6_TABLE[value]; - } - return Replicate(value, num_bits, 6); + return FastReplicate(value, num_bits, 6); } uint Div3Floor(uint v) { diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 3d78efddce..153702c0b8 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) { } if (has_ext_shader_atomic_int64) { VkPhysicalDeviceShaderAtomicInt64Features atomic_int64; - atomic_int64.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; + atomic_int64.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES; atomic_int64.pNext = nullptr; features.pNext = &atomic_int64; physical.GetFeatures2KHR(features); diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 34329970e0..7e8f928401 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -742,7 +742,9 @@ void Config::ReadUIValues() { qt_config->beginGroup(QStringLiteral("UI")); UISettings::values.theme = - ReadSetting(QStringLiteral("theme"), QString::fromUtf8(UISettings::themes[0].second)) + ReadSetting( + QStringLiteral("theme"), + QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second)) .toString(); ReadBasicSetting(UISettings::values.enable_discord_presence); ReadBasicSetting(UISettings::values.select_user_on_boot); @@ -1270,7 +1272,7 @@ void Config::SaveUIValues() { qt_config->beginGroup(QStringLiteral("UI")); WriteSetting(QStringLiteral("theme"), UISettings::values.theme, - QString::fromUtf8(UISettings::themes[0].second)); + QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second)); WriteBasicSetting(UISettings::values.enable_discord_presence); WriteBasicSetting(UISettings::values.select_user_on_boot); diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 22f27d80d0..60b20a62f6 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -48,6 +48,14 @@ public: static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods; static const std::array<UISettings::Shortcut, 20> default_hotkeys; + static constexpr UISettings::Theme default_theme{ +#ifdef _WIN32 + UISettings::Theme::DarkColorful +#else + UISettings::Theme::DefaultColorful +#endif + }; + private: void Initialize(const std::string& config_name); diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index b9342466eb..d2132b408d 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) { return QObject::tr("Share"); case Common::Input::ButtonNames::Options: return QObject::tr("Options"); + case Common::Input::ButtonNames::ButtonMouseWheel: + return QObject::tr("Wheel", "Indicates the mouse wheel"); + case Common::Input::ButtonNames::ButtonBackward: + return QObject::tr("Backward"); + case Common::Input::ButtonNames::ButtonForward: + return QObject::tr("Forward"); + case Common::Input::ButtonNames::ButtonTask: + return QObject::tr("Task"); + case Common::Input::ButtonNames::ButtonExtra: + return QObject::tr("Extra"); default: return QObject::tr("[undefined]"); } diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 1f41c46c4a..2d1a2d9cbe 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( std::size_t row = 0; auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) { for (std::size_t i = 0; i < threads.size(); ++i) { - if (threads[i]->GetThreadTypeForDebugging() == Kernel::ThreadType::User) { + if (threads[i]->GetThreadType() == Kernel::ThreadType::User) { item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i], system)); item_list.back()->row = row; } @@ -153,7 +153,7 @@ QString WaitTreeCallstack::GetText() const { std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const { std::vector<std::unique_ptr<WaitTreeItem>> list; - if (thread.GetThreadTypeForDebugging() != Kernel::ThreadType::User) { + if (thread.GetThreadType() != Kernel::ThreadType::User) { return list; } diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 402c4556d6..f7298ddadc 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -29,6 +29,15 @@ struct Shortcut { ContextualShortcut shortcut; }; +enum class Theme { + Default, + DefaultColorful, + Dark, + DarkColorful, + MidnightBlue, + MidnightBlueColorful, +}; + using Themes = std::array<std::pair<const char*, const char*>, 6>; extern const Themes themes; |