diff options
Diffstat (limited to '')
39 files changed, 540 insertions, 320 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index eba2177d1..89b3fb418 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -116,7 +116,7 @@ struct System::Impl { if (web_browser == nullptr) web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); - auto main_process = Kernel::Process::Create(kernel, "main"); + auto main_process = Kernel::Process::Create(system, "main"); kernel.MakeCurrentProcess(main_process.get()); telemetry_session = std::make_unique<Core::TelemetrySession>(); diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp index 54aa21a3a..1eefed6d0 100644 --- a/src/core/core_cpu.cpp +++ b/src/core/core_cpu.cpp @@ -11,6 +11,7 @@ #endif #include "core/arm/exclusive_monitor.h" #include "core/arm/unicorn/arm_unicorn.h" +#include "core/core.h" #include "core/core_cpu.h" #include "core/core_timing.h" #include "core/hle/kernel/scheduler.h" @@ -49,9 +50,9 @@ bool CpuBarrier::Rendezvous() { return false; } -Cpu::Cpu(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor, - CpuBarrier& cpu_barrier, std::size_t core_index) - : cpu_barrier{cpu_barrier}, core_timing{core_timing}, core_index{core_index} { +Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, + std::size_t core_index) + : cpu_barrier{cpu_barrier}, core_timing{system.CoreTiming()}, core_index{core_index} { if (Settings::values.use_cpu_jit) { #ifdef ARCHITECTURE_x86_64 arm_interface = std::make_unique<ARM_Dynarmic>(core_timing, exclusive_monitor, core_index); @@ -63,7 +64,7 @@ Cpu::Cpu(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor, arm_interface = std::make_unique<ARM_Unicorn>(core_timing); } - scheduler = std::make_unique<Kernel::Scheduler>(*arm_interface); + scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface); } Cpu::~Cpu() = default; diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h index e2204c6b0..7589beb8c 100644 --- a/src/core/core_cpu.h +++ b/src/core/core_cpu.h @@ -15,6 +15,10 @@ namespace Kernel { class Scheduler; } +namespace Core { +class System; +} + namespace Core::Timing { class CoreTiming; } @@ -45,8 +49,8 @@ private: class Cpu { public: - Cpu(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor, - CpuBarrier& cpu_barrier, std::size_t core_index); + Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, + std::size_t core_index); ~Cpu(); void RunLoop(bool tight_loop = true); diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp index 2ddb3610d..93bc5619c 100644 --- a/src/core/cpu_core_manager.cpp +++ b/src/core/cpu_core_manager.cpp @@ -27,8 +27,7 @@ void CpuCoreManager::Initialize(System& system) { exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size()); for (std::size_t index = 0; index < cores.size(); ++index) { - cores[index] = - std::make_unique<Cpu>(system.CoreTiming(), *exclusive_monitor, *barrier, index); + cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index); } // Create threads for CPU cores 1-3, and build thread_to_cpu map diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 90f276ee8..a1e4be070 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -19,9 +19,12 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/result.h" namespace IPC { +constexpr ResultCode ERR_REMOTE_PROCESS_DEAD{ErrorModule::HIPC, 301}; + class RequestHelperBase { protected: Kernel::HLERequestContext* context = nullptr; @@ -350,7 +353,7 @@ public: template <class T> std::shared_ptr<T> PopIpcInterface() { ASSERT(context->Session()->IsDomain()); - ASSERT(context->GetDomainMessageHeader()->input_object_count > 0); + ASSERT(context->GetDomainMessageHeader().input_object_count > 0); return context->GetDomainRequestHandler<T>(Pop<u32>() - 1); } }; @@ -362,6 +365,11 @@ inline u32 RequestParser::Pop() { return cmdbuf[index++]; } +template <> +inline s32 RequestParser::Pop() { + return static_cast<s32>(Pop<u32>()); +} + template <typename T> void RequestParser::PopRaw(T& value) { std::memcpy(&value, cmdbuf + index, sizeof(T)); @@ -393,6 +401,16 @@ inline u64 RequestParser::Pop() { } template <> +inline s8 RequestParser::Pop() { + return static_cast<s8>(Pop<u8>()); +} + +template <> +inline s16 RequestParser::Pop() { + return static_cast<s16>(Pop<u16>()); +} + +template <> inline s64 RequestParser::Pop() { return static_cast<s64>(Pop<u64>()); } diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 9780a7849..352190da8 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -42,7 +42,21 @@ void WakeThreads(const std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_ AddressArbiter::AddressArbiter(Core::System& system) : system{system} {} AddressArbiter::~AddressArbiter() = default; -ResultCode AddressArbiter::SignalToAddress(VAddr address, s32 num_to_wake) { +ResultCode AddressArbiter::SignalToAddress(VAddr address, SignalType type, s32 value, + s32 num_to_wake) { + switch (type) { + case SignalType::Signal: + return SignalToAddressOnly(address, num_to_wake); + case SignalType::IncrementAndSignalIfEqual: + return IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); + case SignalType::ModifyByWaitingCountAndSignalIfEqual: + return ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, num_to_wake); + default: + return ERR_INVALID_ENUM_VALUE; + } +} + +ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address); WakeThreads(waiting_threads, num_to_wake); return RESULT_SUCCESS; @@ -60,7 +74,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 } Memory::Write32(address, static_cast<u32>(value + 1)); - return SignalToAddress(address, num_to_wake); + return SignalToAddressOnly(address, num_to_wake); } ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, @@ -92,6 +106,20 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a return RESULT_SUCCESS; } +ResultCode AddressArbiter::WaitForAddress(VAddr address, ArbitrationType type, s32 value, + s64 timeout_ns) { + switch (type) { + case ArbitrationType::WaitIfLessThan: + return WaitForAddressIfLessThan(address, value, timeout_ns, false); + case ArbitrationType::DecrementAndWaitIfLessThan: + return WaitForAddressIfLessThan(address, value, timeout_ns, true); + case ArbitrationType::WaitIfEqual: + return WaitForAddressIfEqual(address, value, timeout_ns); + default: + return ERR_INVALID_ENUM_VALUE; + } +} + ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) { // Ensure that we can read the address. @@ -113,7 +141,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 return RESULT_TIMEOUT; } - return WaitForAddress(address, timeout); + return WaitForAddressImpl(address, timeout); } ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { @@ -130,10 +158,10 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t return RESULT_TIMEOUT; } - return WaitForAddress(address, timeout); + return WaitForAddressImpl(address, timeout); } -ResultCode AddressArbiter::WaitForAddress(VAddr address, s64 timeout) { +ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) { SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread(); current_thread->SetArbiterWaitAddress(address); current_thread->SetStatus(ThreadStatus::WaitArb); diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index e0c36f2e3..ed0d0e69f 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -4,8 +4,10 @@ #pragma once +#include <vector> + #include "common/common_types.h" -#include "core/hle/kernel/address_arbiter.h" +#include "core/hle/kernel/object.h" union ResultCode; @@ -40,8 +42,15 @@ public: AddressArbiter(AddressArbiter&&) = default; AddressArbiter& operator=(AddressArbiter&&) = delete; + /// Signals an address being waited on with a particular signaling type. + ResultCode SignalToAddress(VAddr address, SignalType type, s32 value, s32 num_to_wake); + + /// Waits on an address with a particular arbitration type. + ResultCode WaitForAddress(VAddr address, ArbitrationType type, s32 value, s64 timeout_ns); + +private: /// Signals an address being waited on. - ResultCode SignalToAddress(VAddr address, s32 num_to_wake); + ResultCode SignalToAddressOnly(VAddr address, s32 num_to_wake); /// Signals an address being waited on and increments its value if equal to the value argument. ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); @@ -59,9 +68,8 @@ public: /// Waits on an address if the value passed is equal to the argument value. ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); -private: // Waits on the given address with a timeout in nanoseconds - ResultCode WaitForAddress(VAddr address, s64 timeout); + ResultCode WaitForAddressImpl(VAddr address, s64 timeout); // Gets the threads waiting on an address. std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const; diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index d4c91d529..aa432658e 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -33,10 +33,11 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { // Create a new session pair, let the created sessions inherit the parent port's HLE handler. auto sessions = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this); - if (server_port->hle_handler) - server_port->hle_handler->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); - else - server_port->pending_sessions.push_back(std::get<SharedPtr<ServerSession>>(sessions)); + if (server_port->HasHLEHandler()) { + server_port->GetHLEHandler()->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); + } else { + server_port->AppendPendingSession(std::get<SharedPtr<ServerSession>>(sessions)); + } // Wake the threads waiting on the ServerPort server_port->WakeupAllWaitingThreads(); diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 704e82824..c17baa50a 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -17,21 +17,11 @@ ClientSession::~ClientSession() { // This destructor will be called automatically when the last ClientSession handle is closed by // the emulated application. - // Local references to ServerSession and SessionRequestHandler are necessary to guarantee they + // A local reference to the ServerSession is necessary to guarantee it // will be kept alive until after ClientDisconnected() returns. SharedPtr<ServerSession> server = parent->server; if (server) { - std::shared_ptr<SessionRequestHandler> hle_handler = server->hle_handler; - if (hle_handler) - hle_handler->ClientDisconnected(server); - - // TODO(Subv): Force a wake up of all the ServerSession's waiting threads and set - // their WaitSynchronization result to 0xC920181A. - - // Clean up the list of client threads with pending requests, they are unneeded now that the - // client endpoint is closed. - server->pending_requesting_threads.clear(); - server->currently_handling = nullptr; + server->ClientDisconnected(); } parent->client = nullptr; diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 4c18de69c..b1f39aad7 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -36,14 +36,15 @@ public: ResultCode SendSyncRequest(SharedPtr<Thread> thread); - std::string name; ///< Name of client port (optional) +private: + explicit ClientSession(KernelCore& kernel); + ~ClientSession() override; /// The parent session, which links to the server endpoint. std::shared_ptr<Session> parent; -private: - explicit ClientSession(KernelCore& kernel); - ~ClientSession() override; + /// Name of the client session (optional) + std::string name; }; } // namespace Kernel diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 5dd855db8..fe710eb6e 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -86,7 +86,7 @@ HLERequestContext::~HLERequestContext() = default; void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming) { IPC::RequestParser rp(src_cmdbuf); - command_header = std::make_shared<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>()); + command_header = rp.PopRaw<IPC::CommandHeader>(); if (command_header->type == IPC::CommandType::Close) { // Close does not populate the rest of the IPC header @@ -95,8 +95,7 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_ // If handle descriptor is present, add size of it if (command_header->enable_handle_descriptor) { - handle_descriptor_header = - std::make_shared<IPC::HandleDescriptorHeader>(rp.PopRaw<IPC::HandleDescriptorHeader>()); + handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>(); if (handle_descriptor_header->send_current_pid) { rp.Skip(2, false); } @@ -140,16 +139,15 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_ // If this is an incoming message, only CommandType "Request" has a domain header // All outgoing domain messages have the domain header, if only incoming has it if (incoming || domain_message_header) { - domain_message_header = - std::make_shared<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>()); + domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>(); } else { - if (Session()->IsDomain()) + if (Session()->IsDomain()) { LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); + } } } - data_payload_header = - std::make_shared<IPC::DataPayloadHeader>(rp.PopRaw<IPC::DataPayloadHeader>()); + data_payload_header = rp.PopRaw<IPC::DataPayloadHeader>(); data_payload_offset = rp.GetCurrentOffset(); @@ -264,11 +262,11 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { // Write the domain objects to the command buffer, these go after the raw untranslated data. // TODO(Subv): This completely ignores C buffers. std::size_t domain_offset = size - domain_message_header->num_objects; - auto& request_handlers = server_session->domain_request_handlers; - for (auto& object : domain_objects) { - request_handlers.emplace_back(object); - dst_cmdbuf[domain_offset++] = static_cast<u32_le>(request_handlers.size()); + for (const auto& object : domain_objects) { + server_session->AppendDomainRequestHandler(object); + dst_cmdbuf[domain_offset++] = + static_cast<u32_le>(server_session->NumDomainRequestHandlers()); } } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 0107acea4..2bdd9f02c 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -6,6 +6,7 @@ #include <array> #include <memory> +#include <optional> #include <string> #include <type_traits> #include <vector> @@ -168,12 +169,12 @@ public: return buffer_c_desciptors; } - const IPC::DomainMessageHeader* GetDomainMessageHeader() const { - return domain_message_header.get(); + const IPC::DomainMessageHeader& GetDomainMessageHeader() const { + return domain_message_header.value(); } bool HasDomainMessageHeader() const { - return domain_message_header != nullptr; + return domain_message_header.has_value(); } /// Helper function to read a buffer using the appropriate buffer descriptor @@ -272,10 +273,10 @@ private: boost::container::small_vector<SharedPtr<Object>, 8> copy_objects; boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; - std::shared_ptr<IPC::CommandHeader> command_header; - std::shared_ptr<IPC::HandleDescriptorHeader> handle_descriptor_header; - std::shared_ptr<IPC::DataPayloadHeader> data_payload_header; - std::shared_ptr<IPC::DomainMessageHeader> domain_message_header; + std::optional<IPC::CommandHeader> command_header; + std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; + std::optional<IPC::DataPayloadHeader> data_payload_header; + std::optional<IPC::DomainMessageHeader> domain_message_header; std::vector<IPC::BufferDescriptorX> buffer_x_desciptors; std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 04ea9349e..4d224d01d 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -87,7 +87,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_ } struct KernelCore::Impl { - explicit Impl(Core::System& system) : address_arbiter{system}, system{system} {} + explicit Impl(Core::System& system) : system{system} {} void Initialize(KernelCore& kernel) { Shutdown(); @@ -138,8 +138,6 @@ struct KernelCore::Impl { std::vector<SharedPtr<Process>> process_list; Process* current_process = nullptr; - Kernel::AddressArbiter address_arbiter; - SharedPtr<ResourceLimit> system_resource_limit; Core::Timing::EventType* thread_wakeup_event_type = nullptr; @@ -192,14 +190,6 @@ const Process* KernelCore::CurrentProcess() const { return impl->current_process; } -AddressArbiter& KernelCore::AddressArbiter() { - return impl->address_arbiter; -} - -const AddressArbiter& KernelCore::AddressArbiter() const { - return impl->address_arbiter; -} - void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) { impl->named_ports.emplace(std::move(name), std::move(port)); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4d292aca9..ff17ff865 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -75,12 +75,6 @@ public: /// Retrieves a const pointer to the current process. const Process* CurrentProcess() const; - /// Provides a reference to the kernel's address arbiter. - Kernel::AddressArbiter& AddressArbiter(); - - /// Provides a const reference to the kernel's address arbiter. - const Kernel::AddressArbiter& AddressArbiter() const; - /// Adds a port to the named port table void AddNamedPort(std::string name, SharedPtr<ClientPort> port); diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 8009150e0..49fced7b1 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -53,9 +53,10 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, VAddr entry_poi CodeSet::CodeSet() = default; CodeSet::~CodeSet() = default; -SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { - SharedPtr<Process> process(new Process(kernel)); +SharedPtr<Process> Process::Create(Core::System& system, std::string&& name) { + auto& kernel = system.Kernel(); + SharedPtr<Process> process(new Process(system)); process->name = std::move(name); process->resource_limit = kernel.GetSystemResourceLimit(); process->status = ProcessStatus::Created; @@ -132,7 +133,7 @@ void Process::PrepareForTermination() { if (thread->GetOwnerProcess() != this) continue; - if (thread == GetCurrentThread()) + if (thread == system.CurrentScheduler().GetCurrentThread()) continue; // TODO(Subv): When are the other running/ready threads terminated? @@ -144,7 +145,6 @@ void Process::PrepareForTermination() { } }; - const auto& system = Core::System::GetInstance(); stop_threads(system.Scheduler(0).GetThreadList()); stop_threads(system.Scheduler(1).GetThreadList()); stop_threads(system.Scheduler(2).GetThreadList()); @@ -227,14 +227,12 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); // Clear instruction cache in CPU JIT - Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); - Core::System::GetInstance().ArmInterface(1).ClearInstructionCache(); - Core::System::GetInstance().ArmInterface(2).ClearInstructionCache(); - Core::System::GetInstance().ArmInterface(3).ClearInstructionCache(); + system.InvalidateCpuInstructionCaches(); } -Kernel::Process::Process(KernelCore& kernel) : WaitObject{kernel} {} -Kernel::Process::~Process() {} +Process::Process(Core::System& system) + : WaitObject{system.Kernel()}, address_arbiter{system}, system{system} {} +Process::~Process() = default; void Process::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "Object unavailable!"); diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index dcc57ae9f..47ffd4ad3 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -12,12 +12,17 @@ #include <vector> #include <boost/container/static_vector.hpp> #include "common/common_types.h" +#include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/process_capability.h" #include "core/hle/kernel/vm_manager.h" #include "core/hle/kernel/wait_object.h" #include "core/hle/result.h" +namespace Core { +class System; +} + namespace FileSys { class ProgramMetadata; } @@ -116,7 +121,7 @@ public: static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; - static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name); + static SharedPtr<Process> Create(Core::System& system, std::string&& name); std::string GetTypeName() const override { return "Process"; @@ -150,6 +155,16 @@ public: return handle_table; } + /// Gets a reference to the process' address arbiter. + AddressArbiter& GetAddressArbiter() { + return address_arbiter; + } + + /// Gets a const reference to the process' address arbiter. + const AddressArbiter& GetAddressArbiter() const { + return address_arbiter; + } + /// Gets the current status of the process ProcessStatus GetStatus() const { return status; @@ -251,7 +266,7 @@ public: void FreeTLSSlot(VAddr tls_address); private: - explicit Process(KernelCore& kernel); + explicit Process(Core::System& system); ~Process() override; /// Checks if the specified thread should wait until this process is available. @@ -309,9 +324,16 @@ private: /// Per-process handle table for storing created object handles in. HandleTable handle_table; + /// Per-process address arbiter. + AddressArbiter address_arbiter; + /// Random values for svcGetInfo RandomEntropy std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy; + /// System context + Core::System& system; + + /// Name of this process std::string name; }; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 44f30d070..5fccfd9f4 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -19,7 +19,8 @@ namespace Kernel { std::mutex Scheduler::scheduler_mutex; -Scheduler::Scheduler(Core::ARM_Interface& cpu_core) : cpu_core(cpu_core) {} +Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core) + : cpu_core{cpu_core}, system{system} {} Scheduler::~Scheduler() { for (auto& thread : thread_list) { @@ -61,7 +62,7 @@ Thread* Scheduler::PopNextReadyThread() { void Scheduler::SwitchContext(Thread* new_thread) { Thread* const previous_thread = GetCurrentThread(); - Process* const previous_process = Core::CurrentProcess(); + Process* const previous_process = system.Kernel().CurrentProcess(); UpdateLastContextSwitchTime(previous_thread, previous_process); @@ -94,8 +95,8 @@ void Scheduler::SwitchContext(Thread* new_thread) { auto* const thread_owner_process = current_thread->GetOwnerProcess(); if (previous_process != thread_owner_process) { - Core::System::GetInstance().Kernel().MakeCurrentProcess(thread_owner_process); - SetCurrentPageTable(&Core::CurrentProcess()->VMManager().page_table); + system.Kernel().MakeCurrentProcess(thread_owner_process); + SetCurrentPageTable(&thread_owner_process->VMManager().page_table); } cpu_core.LoadContext(new_thread->GetContext()); @@ -111,7 +112,7 @@ void Scheduler::SwitchContext(Thread* new_thread) { void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { const u64 prev_switch_ticks = last_context_switch_time; - const u64 most_recent_switch_ticks = Core::System::GetInstance().CoreTiming().GetTicks(); + const u64 most_recent_switch_ticks = system.CoreTiming().GetTicks(); const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; if (thread != nullptr) { @@ -223,8 +224,7 @@ void Scheduler::YieldWithLoadBalancing(Thread* thread) { // Take the first non-nullptr one for (unsigned cur_core = 0; cur_core < Core::NUM_CPU_CORES; ++cur_core) { const auto res = - Core::System::GetInstance().CpuCore(cur_core).Scheduler().GetNextSuggestedThread( - core, priority); + system.CpuCore(cur_core).Scheduler().GetNextSuggestedThread(core, priority); // If scheduler provides a suggested thread if (res != nullptr) { diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 97ced4dfc..1c5bf57d9 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -13,7 +13,8 @@ namespace Core { class ARM_Interface; -} +class System; +} // namespace Core namespace Kernel { @@ -21,7 +22,7 @@ class Process; class Scheduler final { public: - explicit Scheduler(Core::ARM_Interface& cpu_core); + explicit Scheduler(Core::System& system, Core::ARM_Interface& cpu_core); ~Scheduler(); /// Returns whether there are any threads that are ready to run. @@ -162,6 +163,7 @@ private: Core::ARM_Interface& cpu_core; u64 last_context_switch_time = 0; + Core::System& system; static std::mutex scheduler_mutex; }; diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index d6ceeb2da..0e1515c89 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -26,6 +26,10 @@ ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() { return MakeResult(std::move(session)); } +void ServerPort::AppendPendingSession(SharedPtr<ServerSession> pending_session) { + pending_sessions.push_back(std::move(pending_session)); +} + bool ServerPort::ShouldWait(Thread* thread) const { // If there are no pending sessions, we wait until a new one is added. return pending_sessions.empty(); diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index e52f8245f..9bc667cf2 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -22,6 +22,8 @@ class SessionRequestHandler; class ServerPort final : public WaitObject { public: + using HLEHandler = std::shared_ptr<SessionRequestHandler>; + /** * Creates a pair of ServerPort and an associated ClientPort. * @@ -51,22 +53,27 @@ public: */ ResultVal<SharedPtr<ServerSession>> Accept(); + /// Whether or not this server port has an HLE handler available. + bool HasHLEHandler() const { + return hle_handler != nullptr; + } + + /// Gets the HLE handler for this port. + HLEHandler GetHLEHandler() const { + return hle_handler; + } + /** * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port * will inherit a reference to this handler. */ - void SetHleHandler(std::shared_ptr<SessionRequestHandler> hle_handler_) { + void SetHleHandler(HLEHandler hle_handler_) { hle_handler = std::move(hle_handler_); } - std::string name; ///< Name of port (optional) - - /// ServerSessions waiting to be accepted by the port - std::vector<SharedPtr<ServerSession>> pending_sessions; - - /// This session's HLE request handler template (optional) - /// ServerSessions created from this port inherit a reference to this handler. - std::shared_ptr<SessionRequestHandler> hle_handler; + /// Appends a ServerSession to the collection of ServerSessions + /// waiting to be accepted by this port. + void AppendPendingSession(SharedPtr<ServerSession> pending_session); bool ShouldWait(Thread* thread) const override; void Acquire(Thread* thread) override; @@ -74,6 +81,16 @@ public: private: explicit ServerPort(KernelCore& kernel); ~ServerPort() override; + + /// ServerSessions waiting to be accepted by the port + std::vector<SharedPtr<ServerSession>> pending_sessions; + + /// This session's HLE request handler template (optional) + /// ServerSessions created from this port inherit a reference to this handler. + HLEHandler hle_handler; + + /// Name of the port (optional) + std::string name; }; } // namespace Kernel diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 027434f92..4d8a337a7 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -63,42 +63,71 @@ void ServerSession::Acquire(Thread* thread) { pending_requesting_threads.pop_back(); } +void ServerSession::ClientDisconnected() { + // We keep a shared pointer to the hle handler to keep it alive throughout + // the call to ClientDisconnected, as ClientDisconnected invalidates the + // hle_handler member itself during the course of the function executing. + std::shared_ptr<SessionRequestHandler> handler = hle_handler; + if (handler) { + // Note that after this returns, this server session's hle_handler is + // invalidated (set to null). + handler->ClientDisconnected(this); + } + + // TODO(Subv): Force a wake up of all the ServerSession's waiting threads and set + // their WaitSynchronization result to 0xC920181A. + + // Clean up the list of client threads with pending requests, they are unneeded now that the + // client endpoint is closed. + pending_requesting_threads.clear(); + currently_handling = nullptr; +} + +void ServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) { + domain_request_handlers.push_back(std::move(handler)); +} + +std::size_t ServerSession::NumDomainRequestHandlers() const { + return domain_request_handlers.size(); +} + ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { - auto* const domain_message_header = context.GetDomainMessageHeader(); - if (domain_message_header) { - // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs - context.SetDomainRequestHandlers(domain_request_handlers); - - // If there is a DomainMessageHeader, then this is CommandType "Request" - const u32 object_id{context.GetDomainMessageHeader()->object_id}; - switch (domain_message_header->command) { - case IPC::DomainMessageHeader::CommandType::SendMessage: - if (object_id > domain_request_handlers.size()) { - LOG_CRITICAL(IPC, - "object_id {} is too big! This probably means a recent service call " - "to {} needed to return a new interface!", - object_id, name); - UNREACHABLE(); - return RESULT_SUCCESS; // Ignore error if asserts are off - } - return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); - - case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { - LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); - - domain_request_handlers[object_id - 1] = nullptr; - - IPC::ResponseBuilder rb{context, 2}; - rb.Push(RESULT_SUCCESS); - return RESULT_SUCCESS; - } + if (!context.HasDomainMessageHeader()) { + return RESULT_SUCCESS; + } + + // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs + context.SetDomainRequestHandlers(domain_request_handlers); + + // If there is a DomainMessageHeader, then this is CommandType "Request" + const auto& domain_message_header = context.GetDomainMessageHeader(); + const u32 object_id{domain_message_header.object_id}; + switch (domain_message_header.command) { + case IPC::DomainMessageHeader::CommandType::SendMessage: + if (object_id > domain_request_handlers.size()) { + LOG_CRITICAL(IPC, + "object_id {} is too big! This probably means a recent service call " + "to {} needed to return a new interface!", + object_id, name); + UNREACHABLE(); + return RESULT_SUCCESS; // Ignore error if asserts are off } + return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); - LOG_CRITICAL(IPC, "Unknown domain command={}", - static_cast<int>(domain_message_header->command.Value())); - ASSERT(false); + case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { + LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); + + domain_request_handlers[object_id - 1] = nullptr; + + IPC::ResponseBuilder rb{context, 2}; + rb.Push(RESULT_SUCCESS); + return RESULT_SUCCESS; + } } + LOG_CRITICAL(IPC, "Unknown domain command={}", + static_cast<int>(domain_message_header.command.Value())); + ASSERT(false); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index e0e9d64c8..aea4ccfeb 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -46,6 +46,14 @@ public: return HANDLE_TYPE; } + Session* GetParent() { + return parent.get(); + } + + const Session* GetParent() const { + return parent.get(); + } + using SessionPair = std::tuple<SharedPtr<ServerSession>, SharedPtr<ClientSession>>; /** @@ -78,23 +86,16 @@ public: void Acquire(Thread* thread) override; - std::string name; ///< The name of this session (optional) - std::shared_ptr<Session> parent; ///< The parent session, which links to the client endpoint. - std::shared_ptr<SessionRequestHandler> - hle_handler; ///< This session's HLE request handler (applicable when not a domain) + /// Called when a client disconnection occurs. + void ClientDisconnected(); - /// This is the list of domain request handlers (after conversion to a domain) - std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; - - /// List of threads that are pending a response after a sync request. This list is processed in - /// a LIFO manner, thus, the last request will be dispatched first. - /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test. - std::vector<SharedPtr<Thread>> pending_requesting_threads; + /// Adds a new domain request handler to the collection of request handlers within + /// this ServerSession instance. + void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler); - /// Thread whose request is currently being handled. A request is considered "handled" when a - /// response is sent via svcReplyAndReceive. - /// TODO(Subv): Find a better name for this. - SharedPtr<Thread> currently_handling; + /// Retrieves the total number of domain request handlers that have been + /// appended to this ServerSession instance. + std::size_t NumDomainRequestHandlers() const; /// Returns true if the session has been converted to a domain, otherwise False bool IsDomain() const { @@ -129,8 +130,30 @@ private: /// object handle. ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); + /// The parent session, which links to the client endpoint. + std::shared_ptr<Session> parent; + + /// This session's HLE request handler (applicable when not a domain) + std::shared_ptr<SessionRequestHandler> hle_handler; + + /// This is the list of domain request handlers (after conversion to a domain) + std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; + + /// List of threads that are pending a response after a sync request. This list is processed in + /// a LIFO manner, thus, the last request will be dispatched first. + /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test. + std::vector<SharedPtr<Thread>> pending_requesting_threads; + + /// Thread whose request is currently being handled. A request is considered "handled" when a + /// response is sent via svcReplyAndReceive. + /// TODO(Subv): Find a better name for this. + SharedPtr<Thread> currently_handling; + /// When set to True, converts the session to a domain at the end of the command bool convert_to_domain{}; + + /// The name of this session (optional) + std::string name; }; } // namespace Kernel diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 22d0c1dd5..62861da36 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -6,7 +6,6 @@ #include "common/assert.h" #include "common/logging/log.h" -#include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/shared_memory.h" @@ -34,8 +33,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_ shared_memory->backing_block_offset = 0; // Refresh the address mappings for the current process. - if (Core::CurrentProcess() != nullptr) { - Core::CurrentProcess()->VMManager().RefreshMemoryBlockMappings( + if (kernel.CurrentProcess() != nullptr) { + kernel.CurrentProcess()->VMManager().RefreshMemoryBlockMappings( shared_memory->backing_block.get()); } } else { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 7f5c0cc86..77d0e3d96 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1479,21 +1479,10 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout return ERR_INVALID_ADDRESS; } - auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter(); - switch (static_cast<AddressArbiter::ArbitrationType>(type)) { - case AddressArbiter::ArbitrationType::WaitIfLessThan: - return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, false); - case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan: - return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, true); - case AddressArbiter::ArbitrationType::WaitIfEqual: - return address_arbiter.WaitForAddressIfEqual(address, value, timeout); - default: - LOG_ERROR(Kernel_SVC, - "Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan " - "or WaitIfEqual but got {}", - type); - return ERR_INVALID_ENUM_VALUE; - } + const auto arbitration_type = static_cast<AddressArbiter::ArbitrationType>(type); + auto& address_arbiter = + Core::System::GetInstance().Kernel().CurrentProcess()->GetAddressArbiter(); + return address_arbiter.WaitForAddress(address, arbitration_type, value, timeout); } // Signals to an address (via Address Arbiter) @@ -1511,22 +1500,10 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to return ERR_INVALID_ADDRESS; } - auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter(); - switch (static_cast<AddressArbiter::SignalType>(type)) { - case AddressArbiter::SignalType::Signal: - return address_arbiter.SignalToAddress(address, num_to_wake); - case AddressArbiter::SignalType::IncrementAndSignalIfEqual: - return address_arbiter.IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); - case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual: - return address_arbiter.ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, - num_to_wake); - default: - LOG_ERROR(Kernel_SVC, - "Invalid signal type, expected Signal, IncrementAndSignalIfEqual " - "or ModifyByWaitingCountAndSignalIfEqual but got {}", - type); - return ERR_INVALID_ENUM_VALUE; - } + const auto signal_type = static_cast<AddressArbiter::SignalType>(type); + auto& address_arbiter = + Core::System::GetInstance().Kernel().CurrentProcess()->GetAddressArbiter(); + return address_arbiter.SignalToAddress(address, signal_type, value, num_to_wake); } /// This returns the total CPU ticks elapsed since the CPU was powered-on diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 1ed144481..ab84f5ddc 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -13,14 +13,6 @@ // All the constants in this file come from http://switchbrew.org/index.php?title=Error_codes /** - * Detailed description of the error. Code 0 always means success. - */ -enum class ErrorDescription : u32 { - Success = 0, - RemoteProcessDead = 301, -}; - -/** * Identifies the module which caused the error. Error codes can be propagated through a call * chain, meaning that this doesn't always correspond to the module where the API call made is * contained. @@ -120,7 +112,7 @@ enum class ErrorModule : u32 { ShopN = 811, }; -/// Encapsulates a CTR-OS error code, allowing it to be separated into its constituent fields. +/// Encapsulates a Horizon OS error code, allowing it to be separated into its constituent fields. union ResultCode { u32 raw; @@ -133,17 +125,9 @@ union ResultCode { constexpr explicit ResultCode(u32 raw) : raw(raw) {} - constexpr ResultCode(ErrorModule module, ErrorDescription description) - : ResultCode(module, static_cast<u32>(description)) {} - constexpr ResultCode(ErrorModule module_, u32 description_) : raw(module.FormatValue(module_) | description.FormatValue(description_)) {} - constexpr ResultCode& operator=(const ResultCode& o) { - raw = o.raw; - return *this; - } - constexpr bool IsSuccess() const { return raw == 0; } diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index bbe813490..21f5e64c7 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -107,7 +107,9 @@ private: void StopAudioOut(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "called"); - audio_core.StopStream(stream); + if (stream->IsPlaying()) { + audio_core.StopStream(stream); + } IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 11eba4a12..377e12cfa 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -9,43 +9,32 @@ #include <opus.h> -#include "common/common_funcs.h" +#include "common/assert.h" #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/service/audio/hwopus.h" namespace Service::Audio { - +namespace { struct OpusDeleter { void operator()(void* ptr) const { operator delete(ptr); } }; -class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { -public: - IHardwareOpusDecoderManager(std::unique_ptr<OpusDecoder, OpusDeleter> decoder, u32 sample_rate, - u32 channel_count) - : ServiceFramework("IHardwareOpusDecoderManager"), decoder(std::move(decoder)), - sample_rate(sample_rate), channel_count(channel_count) { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IHardwareOpusDecoderManager::DecodeInterleavedOld, "DecodeInterleavedOld"}, - {1, nullptr, "SetContext"}, - {2, nullptr, "DecodeInterleavedForMultiStreamOld"}, - {3, nullptr, "SetContextForMultiStream"}, - {4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"}, - {5, nullptr, "DecodeInterleavedForMultiStreamWithPerfOld"}, - {6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"}, - {7, nullptr, "DecodeInterleavedForMultiStream"}, - }; - // clang-format on +using OpusDecoderPtr = std::unique_ptr<OpusDecoder, OpusDeleter>; - RegisterHandlers(functions); - } +struct OpusPacketHeader { + // Packet size in bytes. + u32_be size; + // Indicates the final range of the codec's entropy coder. + u32_be final_range; +}; +static_assert(sizeof(OpusPacketHeader) == 0x8, "OpusHeader is an invalid size"); -private: +class OpusDecoderStateBase { +public: /// Describes extra behavior that may be asked of the decoding context. enum class ExtraBehavior { /// No extra behavior. @@ -55,30 +44,36 @@ private: ResetContext, }; - void DecodeInterleavedOld(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Audio, "called"); - - DecodeInterleavedHelper(ctx, nullptr, ExtraBehavior::None); - } - - void DecodeInterleavedWithPerfOld(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Audio, "called"); + enum class PerfTime { + Disabled, + Enabled, + }; - u64 performance = 0; - DecodeInterleavedHelper(ctx, &performance, ExtraBehavior::None); - } + virtual ~OpusDecoderStateBase() = default; - void DecodeInterleaved(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Audio, "called"); - - IPC::RequestParser rp{ctx}; - const auto extra_behavior = - rp.Pop<bool>() ? ExtraBehavior::ResetContext : ExtraBehavior::None; + // Decodes interleaved Opus packets. Optionally allows reporting time taken to + // perform the decoding, as well as any relevant extra behavior. + virtual void DecodeInterleaved(Kernel::HLERequestContext& ctx, PerfTime perf_time, + ExtraBehavior extra_behavior) = 0; +}; - u64 performance = 0; - DecodeInterleavedHelper(ctx, &performance, extra_behavior); +// Represents the decoder state for a non-multistream decoder. +class OpusDecoderState final : public OpusDecoderStateBase { +public: + explicit OpusDecoderState(OpusDecoderPtr decoder, u32 sample_rate, u32 channel_count) + : decoder{std::move(decoder)}, sample_rate{sample_rate}, channel_count{channel_count} {} + + void DecodeInterleaved(Kernel::HLERequestContext& ctx, PerfTime perf_time, + ExtraBehavior extra_behavior) override { + if (perf_time == PerfTime::Disabled) { + DecodeInterleavedHelper(ctx, nullptr, extra_behavior); + } else { + u64 performance = 0; + DecodeInterleavedHelper(ctx, &performance, extra_behavior); + } } +private: void DecodeInterleavedHelper(Kernel::HLERequestContext& ctx, u64* performance, ExtraBehavior extra_behavior) { u32 consumed = 0; @@ -89,8 +84,7 @@ private: ResetDecoderContext(); } - if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples, - performance)) { + if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), samples, performance)) { LOG_ERROR(Audio, "Failed to decode opus data"); IPC::ResponseBuilder rb{ctx, 2}; // TODO(ogniK): Use correct error code @@ -109,27 +103,27 @@ private: ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16)); } - bool Decoder_DecodeInterleaved(u32& consumed, u32& sample_count, const std::vector<u8>& input, - std::vector<opus_int16>& output, u64* out_performance_time) { + bool DecodeOpusData(u32& consumed, u32& sample_count, const std::vector<u8>& input, + std::vector<opus_int16>& output, u64* out_performance_time) const { const auto start_time = std::chrono::high_resolution_clock::now(); const std::size_t raw_output_sz = output.size() * sizeof(opus_int16); - if (sizeof(OpusHeader) > input.size()) { + if (sizeof(OpusPacketHeader) > input.size()) { LOG_ERROR(Audio, "Input is smaller than the header size, header_sz={}, input_sz={}", - sizeof(OpusHeader), input.size()); + sizeof(OpusPacketHeader), input.size()); return false; } - OpusHeader hdr{}; - std::memcpy(&hdr, input.data(), sizeof(OpusHeader)); - if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) { + OpusPacketHeader hdr{}; + std::memcpy(&hdr, input.data(), sizeof(OpusPacketHeader)); + if (sizeof(OpusPacketHeader) + static_cast<u32>(hdr.size) > input.size()) { LOG_ERROR(Audio, "Input does not fit in the opus header size. data_sz={}, input_sz={}", - sizeof(OpusHeader) + static_cast<u32>(hdr.sz), input.size()); + sizeof(OpusPacketHeader) + static_cast<u32>(hdr.size), input.size()); return false; } - const auto frame = input.data() + sizeof(OpusHeader); + const auto frame = input.data() + sizeof(OpusPacketHeader); const auto decoded_sample_count = opus_packet_get_nb_samples( - frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)), + frame, static_cast<opus_int32>(input.size() - sizeof(OpusPacketHeader)), static_cast<opus_int32>(sample_rate)); if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) { LOG_ERROR( @@ -141,18 +135,18 @@ private: const int frame_size = (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)); const auto out_sample_count = - opus_decode(decoder.get(), frame, hdr.sz, output.data(), frame_size, 0); + opus_decode(decoder.get(), frame, hdr.size, output.data(), frame_size, 0); if (out_sample_count < 0) { LOG_ERROR(Audio, "Incorrect sample count received from opus_decode, " "output_sample_count={}, frame_size={}, data_sz_from_hdr={}", - out_sample_count, frame_size, static_cast<u32>(hdr.sz)); + out_sample_count, frame_size, static_cast<u32>(hdr.size)); return false; } const auto end_time = std::chrono::high_resolution_clock::now() - start_time; sample_count = out_sample_count; - consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz); + consumed = static_cast<u32>(sizeof(OpusPacketHeader) + hdr.size); if (out_performance_time != nullptr) { *out_performance_time = std::chrono::duration_cast<std::chrono::milliseconds>(end_time).count(); @@ -167,21 +161,66 @@ private: opus_decoder_ctl(decoder.get(), OPUS_RESET_STATE); } - struct OpusHeader { - u32_be sz; // Needs to be BE for some odd reason - INSERT_PADDING_WORDS(1); - }; - static_assert(sizeof(OpusHeader) == 0x8, "OpusHeader is an invalid size"); - - std::unique_ptr<OpusDecoder, OpusDeleter> decoder; + OpusDecoderPtr decoder; u32 sample_rate; u32 channel_count; }; -static std::size_t WorkerBufferSize(u32 channel_count) { +class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { +public: + explicit IHardwareOpusDecoderManager(std::unique_ptr<OpusDecoderStateBase> decoder_state) + : ServiceFramework("IHardwareOpusDecoderManager"), decoder_state{std::move(decoder_state)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IHardwareOpusDecoderManager::DecodeInterleavedOld, "DecodeInterleavedOld"}, + {1, nullptr, "SetContext"}, + {2, nullptr, "DecodeInterleavedForMultiStreamOld"}, + {3, nullptr, "SetContextForMultiStream"}, + {4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"}, + {5, nullptr, "DecodeInterleavedForMultiStreamWithPerfOld"}, + {6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"}, + {7, nullptr, "DecodeInterleavedForMultiStream"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void DecodeInterleavedOld(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Audio, "called"); + + decoder_state->DecodeInterleaved(ctx, OpusDecoderStateBase::PerfTime::Disabled, + OpusDecoderStateBase::ExtraBehavior::None); + } + + void DecodeInterleavedWithPerfOld(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Audio, "called"); + + decoder_state->DecodeInterleaved(ctx, OpusDecoderStateBase::PerfTime::Enabled, + OpusDecoderStateBase::ExtraBehavior::None); + } + + void DecodeInterleaved(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Audio, "called"); + + IPC::RequestParser rp{ctx}; + const auto extra_behavior = rp.Pop<bool>() + ? OpusDecoderStateBase::ExtraBehavior::ResetContext + : OpusDecoderStateBase::ExtraBehavior::None; + + decoder_state->DecodeInterleaved(ctx, OpusDecoderStateBase::PerfTime::Enabled, + extra_behavior); + } + + std::unique_ptr<OpusDecoderStateBase> decoder_state; +}; + +std::size_t WorkerBufferSize(u32 channel_count) { ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); return opus_decoder_get_size(static_cast<int>(channel_count)); } +} // Anonymous namespace void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; @@ -220,8 +259,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { const std::size_t worker_sz = WorkerBufferSize(channel_count); ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large"); - std::unique_ptr<OpusDecoder, OpusDeleter> decoder{ - static_cast<OpusDecoder*>(operator new(worker_sz))}; + OpusDecoderPtr decoder{static_cast<OpusDecoder*>(operator new(worker_sz))}; if (const int err = opus_decoder_init(decoder.get(), sample_rate, channel_count)) { LOG_ERROR(Audio, "Failed to init opus decoder with error={}", err); IPC::ResponseBuilder rb{ctx, 2}; @@ -232,8 +270,8 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IHardwareOpusDecoderManager>(std::move(decoder), sample_rate, - channel_count); + rb.PushIpcInterface<IHardwareOpusDecoderManager>( + std::make_unique<OpusDecoderState>(std::move(decoder), sample_rate, channel_count)); } HwOpus::HwOpus() : ServiceFramework("hwopus") { diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 117f87a45..00806b0ed 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -11,7 +11,6 @@ #include "core/hle/ipc.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/server_port.h" @@ -76,7 +75,8 @@ namespace Service { * Creates a function string for logging, complete with the name (or header code, depending * on what's passed in) the port name, and all the cmd_buff arguments. */ -[[maybe_unused]] static std::string MakeFunctionString(const char* name, const char* port_name, +[[maybe_unused]] static std::string MakeFunctionString(std::string_view name, + std::string_view port_name, const u32* cmd_buff) { // Number of params == bits 0-5 + bits 6-11 int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); @@ -158,9 +158,7 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) { return ReportUnimplementedFunction(ctx, info); } - LOG_TRACE( - Service, "{}", - MakeFunctionString(info->name, GetServiceName().c_str(), ctx.CommandBuffer()).c_str()); + LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer())); handler_invoker(this, info->handler_callback, ctx); } @@ -169,7 +167,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co case IPC::CommandType::Close: { IPC::ResponseBuilder rb{context, 2}; rb.Push(RESULT_SUCCESS); - return ResultCode(ErrorModule::HIPC, ErrorDescription::RemoteProcessDead); + return IPC::ERR_REMOTE_PROCESS_DEAD; } case IPC::CommandType::ControlWithContext: case IPC::CommandType::Control: { diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index 74da4d5e6..e9ee73710 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -30,7 +30,7 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(RESULT_SUCCESS); - Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client}; + Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->GetParent()->client}; rb.PushMoveObjects(session); LOG_DEBUG(Service, "session={}", session->GetObjectId()); diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index bef25433e..b9d6381b4 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -67,7 +67,7 @@ public: if (port == nullptr) { return nullptr; } - return std::static_pointer_cast<T>(port->hle_handler); + return std::static_pointer_cast<T>(port->GetHLEHandler()); } void InvokeControlRequest(Kernel::HLERequestContext& context); diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index a975767bb..566cd6006 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -24,6 +24,7 @@ #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvflinger/buffer_queue.h" #include "core/hle/service/nvflinger/nvflinger.h" +#include "core/hle/service/service.h" #include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi_m.h" #include "core/hle/service/vi/vi_s.h" @@ -33,6 +34,7 @@ namespace Service::VI { constexpr ResultCode ERR_OPERATION_FAILED{ErrorModule::VI, 1}; +constexpr ResultCode ERR_PERMISSION_DENIED{ErrorModule::VI, 5}; constexpr ResultCode ERR_UNSUPPORTED{ErrorModule::VI, 6}; constexpr ResultCode ERR_NOT_FOUND{ErrorModule::VI, 7}; @@ -1203,26 +1205,40 @@ IApplicationDisplayService::IApplicationDisplayService( RegisterHandlers(functions); } -Module::Interface::Interface(std::shared_ptr<Module> module, const char* name, - std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) - : ServiceFramework(name), module(std::move(module)), nv_flinger(std::move(nv_flinger)) {} +static bool IsValidServiceAccess(Permission permission, Policy policy) { + if (permission == Permission::User) { + return policy == Policy::User; + } + + if (permission == Permission::System || permission == Permission::Manager) { + return policy == Policy::User || policy == Policy::Compositor; + } -Module::Interface::~Interface() = default; + return false; +} -void Module::Interface::GetDisplayService(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); +void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, + std::shared_ptr<NVFlinger::NVFlinger> nv_flinger, + Permission permission) { + IPC::RequestParser rp{ctx}; + const auto policy = rp.PopEnum<Policy>(); + + if (!IsValidServiceAccess(permission, policy)) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERR_PERMISSION_DENIED); + return; + } IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IApplicationDisplayService>(nv_flinger); + rb.PushIpcInterface<IApplicationDisplayService>(std::move(nv_flinger)); } void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) { - auto module = std::make_shared<Module>(); - std::make_shared<VI_M>(module, nv_flinger)->InstallAsService(service_manager); - std::make_shared<VI_S>(module, nv_flinger)->InstallAsService(service_manager); - std::make_shared<VI_U>(module, nv_flinger)->InstallAsService(service_manager); + std::make_shared<VI_M>(nv_flinger)->InstallAsService(service_manager); + std::make_shared<VI_S>(nv_flinger)->InstallAsService(service_manager); + std::make_shared<VI_U>(nv_flinger)->InstallAsService(service_manager); } } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index e3963502a..6b66f8b81 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h @@ -4,12 +4,21 @@ #pragma once -#include "core/hle/service/service.h" +#include <memory> +#include "common/common_types.h" + +namespace Kernel { +class HLERequestContext; +} namespace Service::NVFlinger { class NVFlinger; } +namespace Service::SM { +class ServiceManager; +} + namespace Service::VI { enum class DisplayResolution : u32 { @@ -19,22 +28,25 @@ enum class DisplayResolution : u32 { UndockedHeight = 720, }; -class Module final { -public: - class Interface : public ServiceFramework<Interface> { - public: - explicit Interface(std::shared_ptr<Module> module, const char* name, - std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); - ~Interface() override; - - void GetDisplayService(Kernel::HLERequestContext& ctx); +/// Permission level for a particular VI service instance +enum class Permission { + User, + System, + Manager, +}; - protected: - std::shared_ptr<Module> module; - std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; - }; +/// A policy type that may be requested via GetDisplayService and +/// GetDisplayServiceWithProxyNameExchange +enum class Policy { + User, + Compositor, }; +namespace detail { +void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, + std::shared_ptr<NVFlinger::NVFlinger> nv_flinger, Permission permission); +} // namespace detail + /// Registers all VI services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp index 207c06b16..06070087f 100644 --- a/src/core/hle/service/vi/vi_m.cpp +++ b/src/core/hle/service/vi/vi_m.cpp @@ -2,12 +2,14 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" +#include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi_m.h" namespace Service::VI { -VI_M::VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) - : Module::Interface(std::move(module), "vi:m", std::move(nv_flinger)) { +VI_M::VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) + : ServiceFramework{"vi:m"}, nv_flinger{std::move(nv_flinger)} { static const FunctionInfo functions[] = { {2, &VI_M::GetDisplayService, "GetDisplayService"}, {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, @@ -17,4 +19,10 @@ VI_M::VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> VI_M::~VI_M() = default; +void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_VI, "called"); + + detail::GetDisplayServiceImpl(ctx, nv_flinger, Permission::Manager); +} + } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h index 487d58d50..290e06689 100644 --- a/src/core/hle/service/vi/vi_m.h +++ b/src/core/hle/service/vi/vi_m.h @@ -4,14 +4,27 @@ #pragma once -#include "core/hle/service/vi/vi.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::NVFlinger { +class NVFlinger; +} namespace Service::VI { -class VI_M final : public Module::Interface { +class VI_M final : public ServiceFramework<VI_M> { public: - explicit VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); + explicit VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); ~VI_M() override; + +private: + void GetDisplayService(Kernel::HLERequestContext& ctx); + + std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp index 920e6a1f6..57c596cc4 100644 --- a/src/core/hle/service/vi/vi_s.cpp +++ b/src/core/hle/service/vi/vi_s.cpp @@ -2,12 +2,14 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" +#include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi_s.h" namespace Service::VI { -VI_S::VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) - : Module::Interface(std::move(module), "vi:s", std::move(nv_flinger)) { +VI_S::VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) + : ServiceFramework{"vi:s"}, nv_flinger{std::move(nv_flinger)} { static const FunctionInfo functions[] = { {1, &VI_S::GetDisplayService, "GetDisplayService"}, {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, @@ -17,4 +19,10 @@ VI_S::VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> VI_S::~VI_S() = default; +void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_VI, "called"); + + detail::GetDisplayServiceImpl(ctx, nv_flinger, Permission::System); +} + } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h index bbc31148f..47804dc0b 100644 --- a/src/core/hle/service/vi/vi_s.h +++ b/src/core/hle/service/vi/vi_s.h @@ -4,14 +4,27 @@ #pragma once -#include "core/hle/service/vi/vi.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::NVFlinger { +class NVFlinger; +} namespace Service::VI { -class VI_S final : public Module::Interface { +class VI_S final : public ServiceFramework<VI_S> { public: - explicit VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); + explicit VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); ~VI_S() override; + +private: + void GetDisplayService(Kernel::HLERequestContext& ctx); + + std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp index d81e410d6..9d5ceb608 100644 --- a/src/core/hle/service/vi/vi_u.cpp +++ b/src/core/hle/service/vi/vi_u.cpp @@ -2,12 +2,14 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" +#include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi_u.h" namespace Service::VI { -VI_U::VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) - : Module::Interface(std::move(module), "vi:u", std::move(nv_flinger)) { +VI_U::VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) + : ServiceFramework{"vi:u"}, nv_flinger{std::move(nv_flinger)} { static const FunctionInfo functions[] = { {0, &VI_U::GetDisplayService, "GetDisplayService"}, }; @@ -16,4 +18,10 @@ VI_U::VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> VI_U::~VI_U() = default; +void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_VI, "called"); + + detail::GetDisplayServiceImpl(ctx, nv_flinger, Permission::User); +} + } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h index b92f28c92..19bdb73b0 100644 --- a/src/core/hle/service/vi/vi_u.h +++ b/src/core/hle/service/vi/vi_u.h @@ -4,14 +4,27 @@ #pragma once -#include "core/hle/service/vi/vi.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::NVFlinger { +class NVFlinger; +} namespace Service::VI { -class VI_U final : public Module::Interface { +class VI_U final : public ServiceFramework<VI_U> { public: - explicit VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); + explicit VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); ~VI_U() override; + +private: + void GetDisplayService(Kernel::HLERequestContext& ctx); + + std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; }; } // namespace Service::VI diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 2e232e1e7..6dd3139cc 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -91,7 +91,10 @@ void LogSettings() { LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor); LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit); LogSetting("Renderer_FrameLimit", Settings::values.frame_limit); + LogSetting("Renderer_UseDiskShaderCache", Settings::values.use_disk_shader_cache); LogSetting("Renderer_UseAccurateGpuEmulation", Settings::values.use_accurate_gpu_emulation); + LogSetting("Renderer_UseAsynchronousGpuEmulation", + Settings::values.use_asynchronous_gpu_emulation); LogSetting("Audio_OutputEngine", Settings::values.sink_id); LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching); LogSetting("Audio_OutputDevice", Settings::values.audio_device_id); |