diff options
Diffstat (limited to 'src')
38 files changed, 1100 insertions, 874 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 { | |||
| 116 | if (web_browser == nullptr) | 116 | if (web_browser == nullptr) |
| 117 | web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); | 117 | web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); |
| 118 | 118 | ||
| 119 | auto main_process = Kernel::Process::Create(kernel, "main"); | 119 | auto main_process = Kernel::Process::Create(system, "main"); |
| 120 | kernel.MakeCurrentProcess(main_process.get()); | 120 | kernel.MakeCurrentProcess(main_process.get()); |
| 121 | 121 | ||
| 122 | telemetry_session = std::make_unique<Core::TelemetrySession>(); | 122 | telemetry_session = std::make_unique<Core::TelemetrySession>(); |
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 079283830..a1e4be070 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h | |||
| @@ -19,9 +19,12 @@ | |||
| 19 | #include "core/hle/kernel/hle_ipc.h" | 19 | #include "core/hle/kernel/hle_ipc.h" |
| 20 | #include "core/hle/kernel/object.h" | 20 | #include "core/hle/kernel/object.h" |
| 21 | #include "core/hle/kernel/server_session.h" | 21 | #include "core/hle/kernel/server_session.h" |
| 22 | #include "core/hle/result.h" | ||
| 22 | 23 | ||
| 23 | namespace IPC { | 24 | namespace IPC { |
| 24 | 25 | ||
| 26 | constexpr ResultCode ERR_REMOTE_PROCESS_DEAD{ErrorModule::HIPC, 301}; | ||
| 27 | |||
| 25 | class RequestHelperBase { | 28 | class RequestHelperBase { |
| 26 | protected: | 29 | protected: |
| 27 | Kernel::HLERequestContext* context = nullptr; | 30 | Kernel::HLERequestContext* context = nullptr; |
| @@ -362,6 +365,11 @@ inline u32 RequestParser::Pop() { | |||
| 362 | return cmdbuf[index++]; | 365 | return cmdbuf[index++]; |
| 363 | } | 366 | } |
| 364 | 367 | ||
| 368 | template <> | ||
| 369 | inline s32 RequestParser::Pop() { | ||
| 370 | return static_cast<s32>(Pop<u32>()); | ||
| 371 | } | ||
| 372 | |||
| 365 | template <typename T> | 373 | template <typename T> |
| 366 | void RequestParser::PopRaw(T& value) { | 374 | void RequestParser::PopRaw(T& value) { |
| 367 | std::memcpy(&value, cmdbuf + index, sizeof(T)); | 375 | std::memcpy(&value, cmdbuf + index, sizeof(T)); |
| @@ -393,6 +401,16 @@ inline u64 RequestParser::Pop() { | |||
| 393 | } | 401 | } |
| 394 | 402 | ||
| 395 | template <> | 403 | template <> |
| 404 | inline s8 RequestParser::Pop() { | ||
| 405 | return static_cast<s8>(Pop<u8>()); | ||
| 406 | } | ||
| 407 | |||
| 408 | template <> | ||
| 409 | inline s16 RequestParser::Pop() { | ||
| 410 | return static_cast<s16>(Pop<u16>()); | ||
| 411 | } | ||
| 412 | |||
| 413 | template <> | ||
| 396 | inline s64 RequestParser::Pop() { | 414 | inline s64 RequestParser::Pop() { |
| 397 | return static_cast<s64>(Pop<u64>()); | 415 | return static_cast<s64>(Pop<u64>()); |
| 398 | } | 416 | } |
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_ | |||
| 42 | AddressArbiter::AddressArbiter(Core::System& system) : system{system} {} | 42 | AddressArbiter::AddressArbiter(Core::System& system) : system{system} {} |
| 43 | AddressArbiter::~AddressArbiter() = default; | 43 | AddressArbiter::~AddressArbiter() = default; |
| 44 | 44 | ||
| 45 | ResultCode AddressArbiter::SignalToAddress(VAddr address, s32 num_to_wake) { | 45 | ResultCode AddressArbiter::SignalToAddress(VAddr address, SignalType type, s32 value, |
| 46 | s32 num_to_wake) { | ||
| 47 | switch (type) { | ||
| 48 | case SignalType::Signal: | ||
| 49 | return SignalToAddressOnly(address, num_to_wake); | ||
| 50 | case SignalType::IncrementAndSignalIfEqual: | ||
| 51 | return IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); | ||
| 52 | case SignalType::ModifyByWaitingCountAndSignalIfEqual: | ||
| 53 | return ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, num_to_wake); | ||
| 54 | default: | ||
| 55 | return ERR_INVALID_ENUM_VALUE; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { | ||
| 46 | const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address); | 60 | const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address); |
| 47 | WakeThreads(waiting_threads, num_to_wake); | 61 | WakeThreads(waiting_threads, num_to_wake); |
| 48 | return RESULT_SUCCESS; | 62 | return RESULT_SUCCESS; |
| @@ -60,7 +74,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 | |||
| 60 | } | 74 | } |
| 61 | 75 | ||
| 62 | Memory::Write32(address, static_cast<u32>(value + 1)); | 76 | Memory::Write32(address, static_cast<u32>(value + 1)); |
| 63 | return SignalToAddress(address, num_to_wake); | 77 | return SignalToAddressOnly(address, num_to_wake); |
| 64 | } | 78 | } |
| 65 | 79 | ||
| 66 | ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, | 80 | ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, |
| @@ -92,6 +106,20 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a | |||
| 92 | return RESULT_SUCCESS; | 106 | return RESULT_SUCCESS; |
| 93 | } | 107 | } |
| 94 | 108 | ||
| 109 | ResultCode AddressArbiter::WaitForAddress(VAddr address, ArbitrationType type, s32 value, | ||
| 110 | s64 timeout_ns) { | ||
| 111 | switch (type) { | ||
| 112 | case ArbitrationType::WaitIfLessThan: | ||
| 113 | return WaitForAddressIfLessThan(address, value, timeout_ns, false); | ||
| 114 | case ArbitrationType::DecrementAndWaitIfLessThan: | ||
| 115 | return WaitForAddressIfLessThan(address, value, timeout_ns, true); | ||
| 116 | case ArbitrationType::WaitIfEqual: | ||
| 117 | return WaitForAddressIfEqual(address, value, timeout_ns); | ||
| 118 | default: | ||
| 119 | return ERR_INVALID_ENUM_VALUE; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 95 | ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, | 123 | ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, |
| 96 | bool should_decrement) { | 124 | bool should_decrement) { |
| 97 | // Ensure that we can read the address. | 125 | // Ensure that we can read the address. |
| @@ -113,7 +141,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 | |||
| 113 | return RESULT_TIMEOUT; | 141 | return RESULT_TIMEOUT; |
| 114 | } | 142 | } |
| 115 | 143 | ||
| 116 | return WaitForAddress(address, timeout); | 144 | return WaitForAddressImpl(address, timeout); |
| 117 | } | 145 | } |
| 118 | 146 | ||
| 119 | ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { | 147 | ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { |
| @@ -130,10 +158,10 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t | |||
| 130 | return RESULT_TIMEOUT; | 158 | return RESULT_TIMEOUT; |
| 131 | } | 159 | } |
| 132 | 160 | ||
| 133 | return WaitForAddress(address, timeout); | 161 | return WaitForAddressImpl(address, timeout); |
| 134 | } | 162 | } |
| 135 | 163 | ||
| 136 | ResultCode AddressArbiter::WaitForAddress(VAddr address, s64 timeout) { | 164 | ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) { |
| 137 | SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread(); | 165 | SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread(); |
| 138 | current_thread->SetArbiterWaitAddress(address); | 166 | current_thread->SetArbiterWaitAddress(address); |
| 139 | current_thread->SetStatus(ThreadStatus::WaitArb); | 167 | 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 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <vector> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | #include "core/hle/kernel/address_arbiter.h" | 10 | #include "core/hle/kernel/object.h" |
| 9 | 11 | ||
| 10 | union ResultCode; | 12 | union ResultCode; |
| 11 | 13 | ||
| @@ -40,8 +42,15 @@ public: | |||
| 40 | AddressArbiter(AddressArbiter&&) = default; | 42 | AddressArbiter(AddressArbiter&&) = default; |
| 41 | AddressArbiter& operator=(AddressArbiter&&) = delete; | 43 | AddressArbiter& operator=(AddressArbiter&&) = delete; |
| 42 | 44 | ||
| 45 | /// Signals an address being waited on with a particular signaling type. | ||
| 46 | ResultCode SignalToAddress(VAddr address, SignalType type, s32 value, s32 num_to_wake); | ||
| 47 | |||
| 48 | /// Waits on an address with a particular arbitration type. | ||
| 49 | ResultCode WaitForAddress(VAddr address, ArbitrationType type, s32 value, s64 timeout_ns); | ||
| 50 | |||
| 51 | private: | ||
| 43 | /// Signals an address being waited on. | 52 | /// Signals an address being waited on. |
| 44 | ResultCode SignalToAddress(VAddr address, s32 num_to_wake); | 53 | ResultCode SignalToAddressOnly(VAddr address, s32 num_to_wake); |
| 45 | 54 | ||
| 46 | /// Signals an address being waited on and increments its value if equal to the value argument. | 55 | /// Signals an address being waited on and increments its value if equal to the value argument. |
| 47 | ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); | 56 | ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); |
| @@ -59,9 +68,8 @@ public: | |||
| 59 | /// Waits on an address if the value passed is equal to the argument value. | 68 | /// Waits on an address if the value passed is equal to the argument value. |
| 60 | ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); | 69 | ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); |
| 61 | 70 | ||
| 62 | private: | ||
| 63 | // Waits on the given address with a timeout in nanoseconds | 71 | // Waits on the given address with a timeout in nanoseconds |
| 64 | ResultCode WaitForAddress(VAddr address, s64 timeout); | 72 | ResultCode WaitForAddressImpl(VAddr address, s64 timeout); |
| 65 | 73 | ||
| 66 | // Gets the threads waiting on an address. | 74 | // Gets the threads waiting on an address. |
| 67 | std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const; | 75 | 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() { | |||
| 33 | // Create a new session pair, let the created sessions inherit the parent port's HLE handler. | 33 | // Create a new session pair, let the created sessions inherit the parent port's HLE handler. |
| 34 | auto sessions = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this); | 34 | auto sessions = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this); |
| 35 | 35 | ||
| 36 | if (server_port->hle_handler) | 36 | if (server_port->HasHLEHandler()) { |
| 37 | server_port->hle_handler->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); | 37 | server_port->GetHLEHandler()->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); |
| 38 | else | 38 | } else { |
| 39 | server_port->pending_sessions.push_back(std::get<SharedPtr<ServerSession>>(sessions)); | 39 | server_port->AppendPendingSession(std::get<SharedPtr<ServerSession>>(sessions)); |
| 40 | } | ||
| 40 | 41 | ||
| 41 | // Wake the threads waiting on the ServerPort | 42 | // Wake the threads waiting on the ServerPort |
| 42 | server_port->WakeupAllWaitingThreads(); | 43 | server_port->WakeupAllWaitingThreads(); |
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_ | |||
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | struct KernelCore::Impl { | 89 | struct KernelCore::Impl { |
| 90 | explicit Impl(Core::System& system) : address_arbiter{system}, system{system} {} | 90 | explicit Impl(Core::System& system) : system{system} {} |
| 91 | 91 | ||
| 92 | void Initialize(KernelCore& kernel) { | 92 | void Initialize(KernelCore& kernel) { |
| 93 | Shutdown(); | 93 | Shutdown(); |
| @@ -138,8 +138,6 @@ struct KernelCore::Impl { | |||
| 138 | std::vector<SharedPtr<Process>> process_list; | 138 | std::vector<SharedPtr<Process>> process_list; |
| 139 | Process* current_process = nullptr; | 139 | Process* current_process = nullptr; |
| 140 | 140 | ||
| 141 | Kernel::AddressArbiter address_arbiter; | ||
| 142 | |||
| 143 | SharedPtr<ResourceLimit> system_resource_limit; | 141 | SharedPtr<ResourceLimit> system_resource_limit; |
| 144 | 142 | ||
| 145 | Core::Timing::EventType* thread_wakeup_event_type = nullptr; | 143 | Core::Timing::EventType* thread_wakeup_event_type = nullptr; |
| @@ -192,14 +190,6 @@ const Process* KernelCore::CurrentProcess() const { | |||
| 192 | return impl->current_process; | 190 | return impl->current_process; |
| 193 | } | 191 | } |
| 194 | 192 | ||
| 195 | AddressArbiter& KernelCore::AddressArbiter() { | ||
| 196 | return impl->address_arbiter; | ||
| 197 | } | ||
| 198 | |||
| 199 | const AddressArbiter& KernelCore::AddressArbiter() const { | ||
| 200 | return impl->address_arbiter; | ||
| 201 | } | ||
| 202 | |||
| 203 | void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) { | 193 | void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) { |
| 204 | impl->named_ports.emplace(std::move(name), std::move(port)); | 194 | impl->named_ports.emplace(std::move(name), std::move(port)); |
| 205 | } | 195 | } |
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: | |||
| 75 | /// Retrieves a const pointer to the current process. | 75 | /// Retrieves a const pointer to the current process. |
| 76 | const Process* CurrentProcess() const; | 76 | const Process* CurrentProcess() const; |
| 77 | 77 | ||
| 78 | /// Provides a reference to the kernel's address arbiter. | ||
| 79 | Kernel::AddressArbiter& AddressArbiter(); | ||
| 80 | |||
| 81 | /// Provides a const reference to the kernel's address arbiter. | ||
| 82 | const Kernel::AddressArbiter& AddressArbiter() const; | ||
| 83 | |||
| 84 | /// Adds a port to the named port table | 78 | /// Adds a port to the named port table |
| 85 | void AddNamedPort(std::string name, SharedPtr<ClientPort> port); | 79 | void AddNamedPort(std::string name, SharedPtr<ClientPort> port); |
| 86 | 80 | ||
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 | |||
| 53 | CodeSet::CodeSet() = default; | 53 | CodeSet::CodeSet() = default; |
| 54 | CodeSet::~CodeSet() = default; | 54 | CodeSet::~CodeSet() = default; |
| 55 | 55 | ||
| 56 | SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { | 56 | SharedPtr<Process> Process::Create(Core::System& system, std::string&& name) { |
| 57 | SharedPtr<Process> process(new Process(kernel)); | 57 | auto& kernel = system.Kernel(); |
| 58 | 58 | ||
| 59 | SharedPtr<Process> process(new Process(system)); | ||
| 59 | process->name = std::move(name); | 60 | process->name = std::move(name); |
| 60 | process->resource_limit = kernel.GetSystemResourceLimit(); | 61 | process->resource_limit = kernel.GetSystemResourceLimit(); |
| 61 | process->status = ProcessStatus::Created; | 62 | process->status = ProcessStatus::Created; |
| @@ -132,7 +133,7 @@ void Process::PrepareForTermination() { | |||
| 132 | if (thread->GetOwnerProcess() != this) | 133 | if (thread->GetOwnerProcess() != this) |
| 133 | continue; | 134 | continue; |
| 134 | 135 | ||
| 135 | if (thread == GetCurrentThread()) | 136 | if (thread == system.CurrentScheduler().GetCurrentThread()) |
| 136 | continue; | 137 | continue; |
| 137 | 138 | ||
| 138 | // TODO(Subv): When are the other running/ready threads terminated? | 139 | // TODO(Subv): When are the other running/ready threads terminated? |
| @@ -144,7 +145,6 @@ void Process::PrepareForTermination() { | |||
| 144 | } | 145 | } |
| 145 | }; | 146 | }; |
| 146 | 147 | ||
| 147 | const auto& system = Core::System::GetInstance(); | ||
| 148 | stop_threads(system.Scheduler(0).GetThreadList()); | 148 | stop_threads(system.Scheduler(0).GetThreadList()); |
| 149 | stop_threads(system.Scheduler(1).GetThreadList()); | 149 | stop_threads(system.Scheduler(1).GetThreadList()); |
| 150 | stop_threads(system.Scheduler(2).GetThreadList()); | 150 | stop_threads(system.Scheduler(2).GetThreadList()); |
| @@ -227,14 +227,12 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { | |||
| 227 | MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); | 227 | MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); |
| 228 | 228 | ||
| 229 | // Clear instruction cache in CPU JIT | 229 | // Clear instruction cache in CPU JIT |
| 230 | Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); | 230 | system.InvalidateCpuInstructionCaches(); |
| 231 | Core::System::GetInstance().ArmInterface(1).ClearInstructionCache(); | ||
| 232 | Core::System::GetInstance().ArmInterface(2).ClearInstructionCache(); | ||
| 233 | Core::System::GetInstance().ArmInterface(3).ClearInstructionCache(); | ||
| 234 | } | 231 | } |
| 235 | 232 | ||
| 236 | Kernel::Process::Process(KernelCore& kernel) : WaitObject{kernel} {} | 233 | Process::Process(Core::System& system) |
| 237 | Kernel::Process::~Process() {} | 234 | : WaitObject{system.Kernel()}, address_arbiter{system}, system{system} {} |
| 235 | Process::~Process() = default; | ||
| 238 | 236 | ||
| 239 | void Process::Acquire(Thread* thread) { | 237 | void Process::Acquire(Thread* thread) { |
| 240 | ASSERT_MSG(!ShouldWait(thread), "Object unavailable!"); | 238 | 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 @@ | |||
| 12 | #include <vector> | 12 | #include <vector> |
| 13 | #include <boost/container/static_vector.hpp> | 13 | #include <boost/container/static_vector.hpp> |
| 14 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 15 | #include "core/hle/kernel/address_arbiter.h" | ||
| 15 | #include "core/hle/kernel/handle_table.h" | 16 | #include "core/hle/kernel/handle_table.h" |
| 16 | #include "core/hle/kernel/process_capability.h" | 17 | #include "core/hle/kernel/process_capability.h" |
| 17 | #include "core/hle/kernel/vm_manager.h" | 18 | #include "core/hle/kernel/vm_manager.h" |
| 18 | #include "core/hle/kernel/wait_object.h" | 19 | #include "core/hle/kernel/wait_object.h" |
| 19 | #include "core/hle/result.h" | 20 | #include "core/hle/result.h" |
| 20 | 21 | ||
| 22 | namespace Core { | ||
| 23 | class System; | ||
| 24 | } | ||
| 25 | |||
| 21 | namespace FileSys { | 26 | namespace FileSys { |
| 22 | class ProgramMetadata; | 27 | class ProgramMetadata; |
| 23 | } | 28 | } |
| @@ -116,7 +121,7 @@ public: | |||
| 116 | 121 | ||
| 117 | static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; | 122 | static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; |
| 118 | 123 | ||
| 119 | static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name); | 124 | static SharedPtr<Process> Create(Core::System& system, std::string&& name); |
| 120 | 125 | ||
| 121 | std::string GetTypeName() const override { | 126 | std::string GetTypeName() const override { |
| 122 | return "Process"; | 127 | return "Process"; |
| @@ -150,6 +155,16 @@ public: | |||
| 150 | return handle_table; | 155 | return handle_table; |
| 151 | } | 156 | } |
| 152 | 157 | ||
| 158 | /// Gets a reference to the process' address arbiter. | ||
| 159 | AddressArbiter& GetAddressArbiter() { | ||
| 160 | return address_arbiter; | ||
| 161 | } | ||
| 162 | |||
| 163 | /// Gets a const reference to the process' address arbiter. | ||
| 164 | const AddressArbiter& GetAddressArbiter() const { | ||
| 165 | return address_arbiter; | ||
| 166 | } | ||
| 167 | |||
| 153 | /// Gets the current status of the process | 168 | /// Gets the current status of the process |
| 154 | ProcessStatus GetStatus() const { | 169 | ProcessStatus GetStatus() const { |
| 155 | return status; | 170 | return status; |
| @@ -251,7 +266,7 @@ public: | |||
| 251 | void FreeTLSSlot(VAddr tls_address); | 266 | void FreeTLSSlot(VAddr tls_address); |
| 252 | 267 | ||
| 253 | private: | 268 | private: |
| 254 | explicit Process(KernelCore& kernel); | 269 | explicit Process(Core::System& system); |
| 255 | ~Process() override; | 270 | ~Process() override; |
| 256 | 271 | ||
| 257 | /// Checks if the specified thread should wait until this process is available. | 272 | /// Checks if the specified thread should wait until this process is available. |
| @@ -309,9 +324,16 @@ private: | |||
| 309 | /// Per-process handle table for storing created object handles in. | 324 | /// Per-process handle table for storing created object handles in. |
| 310 | HandleTable handle_table; | 325 | HandleTable handle_table; |
| 311 | 326 | ||
| 327 | /// Per-process address arbiter. | ||
| 328 | AddressArbiter address_arbiter; | ||
| 329 | |||
| 312 | /// Random values for svcGetInfo RandomEntropy | 330 | /// Random values for svcGetInfo RandomEntropy |
| 313 | std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy; | 331 | std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy; |
| 314 | 332 | ||
| 333 | /// System context | ||
| 334 | Core::System& system; | ||
| 335 | |||
| 336 | /// Name of this process | ||
| 315 | std::string name; | 337 | std::string name; |
| 316 | }; | 338 | }; |
| 317 | 339 | ||
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() { | |||
| 26 | return MakeResult(std::move(session)); | 26 | return MakeResult(std::move(session)); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | void ServerPort::AppendPendingSession(SharedPtr<ServerSession> pending_session) { | ||
| 30 | pending_sessions.push_back(std::move(pending_session)); | ||
| 31 | } | ||
| 32 | |||
| 29 | bool ServerPort::ShouldWait(Thread* thread) const { | 33 | bool ServerPort::ShouldWait(Thread* thread) const { |
| 30 | // If there are no pending sessions, we wait until a new one is added. | 34 | // If there are no pending sessions, we wait until a new one is added. |
| 31 | return pending_sessions.empty(); | 35 | 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; | |||
| 22 | 22 | ||
| 23 | class ServerPort final : public WaitObject { | 23 | class ServerPort final : public WaitObject { |
| 24 | public: | 24 | public: |
| 25 | using HLEHandler = std::shared_ptr<SessionRequestHandler>; | ||
| 26 | |||
| 25 | /** | 27 | /** |
| 26 | * Creates a pair of ServerPort and an associated ClientPort. | 28 | * Creates a pair of ServerPort and an associated ClientPort. |
| 27 | * | 29 | * |
| @@ -51,22 +53,27 @@ public: | |||
| 51 | */ | 53 | */ |
| 52 | ResultVal<SharedPtr<ServerSession>> Accept(); | 54 | ResultVal<SharedPtr<ServerSession>> Accept(); |
| 53 | 55 | ||
| 56 | /// Whether or not this server port has an HLE handler available. | ||
| 57 | bool HasHLEHandler() const { | ||
| 58 | return hle_handler != nullptr; | ||
| 59 | } | ||
| 60 | |||
| 61 | /// Gets the HLE handler for this port. | ||
| 62 | HLEHandler GetHLEHandler() const { | ||
| 63 | return hle_handler; | ||
| 64 | } | ||
| 65 | |||
| 54 | /** | 66 | /** |
| 55 | * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port | 67 | * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port |
| 56 | * will inherit a reference to this handler. | 68 | * will inherit a reference to this handler. |
| 57 | */ | 69 | */ |
| 58 | void SetHleHandler(std::shared_ptr<SessionRequestHandler> hle_handler_) { | 70 | void SetHleHandler(HLEHandler hle_handler_) { |
| 59 | hle_handler = std::move(hle_handler_); | 71 | hle_handler = std::move(hle_handler_); |
| 60 | } | 72 | } |
| 61 | 73 | ||
| 62 | std::string name; ///< Name of port (optional) | 74 | /// Appends a ServerSession to the collection of ServerSessions |
| 63 | 75 | /// waiting to be accepted by this port. | |
| 64 | /// ServerSessions waiting to be accepted by the port | 76 | void AppendPendingSession(SharedPtr<ServerSession> pending_session); |
| 65 | std::vector<SharedPtr<ServerSession>> pending_sessions; | ||
| 66 | |||
| 67 | /// This session's HLE request handler template (optional) | ||
| 68 | /// ServerSessions created from this port inherit a reference to this handler. | ||
| 69 | std::shared_ptr<SessionRequestHandler> hle_handler; | ||
| 70 | 77 | ||
| 71 | bool ShouldWait(Thread* thread) const override; | 78 | bool ShouldWait(Thread* thread) const override; |
| 72 | void Acquire(Thread* thread) override; | 79 | void Acquire(Thread* thread) override; |
| @@ -74,6 +81,16 @@ public: | |||
| 74 | private: | 81 | private: |
| 75 | explicit ServerPort(KernelCore& kernel); | 82 | explicit ServerPort(KernelCore& kernel); |
| 76 | ~ServerPort() override; | 83 | ~ServerPort() override; |
| 84 | |||
| 85 | /// ServerSessions waiting to be accepted by the port | ||
| 86 | std::vector<SharedPtr<ServerSession>> pending_sessions; | ||
| 87 | |||
| 88 | /// This session's HLE request handler template (optional) | ||
| 89 | /// ServerSessions created from this port inherit a reference to this handler. | ||
| 90 | HLEHandler hle_handler; | ||
| 91 | |||
| 92 | /// Name of the port (optional) | ||
| 93 | std::string name; | ||
| 77 | }; | 94 | }; |
| 78 | 95 | ||
| 79 | } // namespace Kernel | 96 | } // namespace Kernel |
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 | |||
| 1479 | return ERR_INVALID_ADDRESS; | 1479 | return ERR_INVALID_ADDRESS; |
| 1480 | } | 1480 | } |
| 1481 | 1481 | ||
| 1482 | auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter(); | 1482 | const auto arbitration_type = static_cast<AddressArbiter::ArbitrationType>(type); |
| 1483 | switch (static_cast<AddressArbiter::ArbitrationType>(type)) { | 1483 | auto& address_arbiter = |
| 1484 | case AddressArbiter::ArbitrationType::WaitIfLessThan: | 1484 | Core::System::GetInstance().Kernel().CurrentProcess()->GetAddressArbiter(); |
| 1485 | return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, false); | 1485 | return address_arbiter.WaitForAddress(address, arbitration_type, value, timeout); |
| 1486 | case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan: | ||
| 1487 | return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, true); | ||
| 1488 | case AddressArbiter::ArbitrationType::WaitIfEqual: | ||
| 1489 | return address_arbiter.WaitForAddressIfEqual(address, value, timeout); | ||
| 1490 | default: | ||
| 1491 | LOG_ERROR(Kernel_SVC, | ||
| 1492 | "Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan " | ||
| 1493 | "or WaitIfEqual but got {}", | ||
| 1494 | type); | ||
| 1495 | return ERR_INVALID_ENUM_VALUE; | ||
| 1496 | } | ||
| 1497 | } | 1486 | } |
| 1498 | 1487 | ||
| 1499 | // Signals to an address (via Address Arbiter) | 1488 | // Signals to an address (via Address Arbiter) |
| @@ -1511,22 +1500,10 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to | |||
| 1511 | return ERR_INVALID_ADDRESS; | 1500 | return ERR_INVALID_ADDRESS; |
| 1512 | } | 1501 | } |
| 1513 | 1502 | ||
| 1514 | auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter(); | 1503 | const auto signal_type = static_cast<AddressArbiter::SignalType>(type); |
| 1515 | switch (static_cast<AddressArbiter::SignalType>(type)) { | 1504 | auto& address_arbiter = |
| 1516 | case AddressArbiter::SignalType::Signal: | 1505 | Core::System::GetInstance().Kernel().CurrentProcess()->GetAddressArbiter(); |
| 1517 | return address_arbiter.SignalToAddress(address, num_to_wake); | 1506 | return address_arbiter.SignalToAddress(address, signal_type, value, num_to_wake); |
| 1518 | case AddressArbiter::SignalType::IncrementAndSignalIfEqual: | ||
| 1519 | return address_arbiter.IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); | ||
| 1520 | case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual: | ||
| 1521 | return address_arbiter.ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, | ||
| 1522 | num_to_wake); | ||
| 1523 | default: | ||
| 1524 | LOG_ERROR(Kernel_SVC, | ||
| 1525 | "Invalid signal type, expected Signal, IncrementAndSignalIfEqual " | ||
| 1526 | "or ModifyByWaitingCountAndSignalIfEqual but got {}", | ||
| 1527 | type); | ||
| 1528 | return ERR_INVALID_ENUM_VALUE; | ||
| 1529 | } | ||
| 1530 | } | 1507 | } |
| 1531 | 1508 | ||
| 1532 | /// This returns the total CPU ticks elapsed since the CPU was powered-on | 1509 | /// 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 @@ | |||
| 13 | // All the constants in this file come from http://switchbrew.org/index.php?title=Error_codes | 13 | // All the constants in this file come from http://switchbrew.org/index.php?title=Error_codes |
| 14 | 14 | ||
| 15 | /** | 15 | /** |
| 16 | * Detailed description of the error. Code 0 always means success. | ||
| 17 | */ | ||
| 18 | enum class ErrorDescription : u32 { | ||
| 19 | Success = 0, | ||
| 20 | RemoteProcessDead = 301, | ||
| 21 | }; | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Identifies the module which caused the error. Error codes can be propagated through a call | 16 | * Identifies the module which caused the error. Error codes can be propagated through a call |
| 25 | * chain, meaning that this doesn't always correspond to the module where the API call made is | 17 | * chain, meaning that this doesn't always correspond to the module where the API call made is |
| 26 | * contained. | 18 | * contained. |
| @@ -120,7 +112,7 @@ enum class ErrorModule : u32 { | |||
| 120 | ShopN = 811, | 112 | ShopN = 811, |
| 121 | }; | 113 | }; |
| 122 | 114 | ||
| 123 | /// Encapsulates a CTR-OS error code, allowing it to be separated into its constituent fields. | 115 | /// Encapsulates a Horizon OS error code, allowing it to be separated into its constituent fields. |
| 124 | union ResultCode { | 116 | union ResultCode { |
| 125 | u32 raw; | 117 | u32 raw; |
| 126 | 118 | ||
| @@ -133,17 +125,9 @@ union ResultCode { | |||
| 133 | 125 | ||
| 134 | constexpr explicit ResultCode(u32 raw) : raw(raw) {} | 126 | constexpr explicit ResultCode(u32 raw) : raw(raw) {} |
| 135 | 127 | ||
| 136 | constexpr ResultCode(ErrorModule module, ErrorDescription description) | ||
| 137 | : ResultCode(module, static_cast<u32>(description)) {} | ||
| 138 | |||
| 139 | constexpr ResultCode(ErrorModule module_, u32 description_) | 128 | constexpr ResultCode(ErrorModule module_, u32 description_) |
| 140 | : raw(module.FormatValue(module_) | description.FormatValue(description_)) {} | 129 | : raw(module.FormatValue(module_) | description.FormatValue(description_)) {} |
| 141 | 130 | ||
| 142 | constexpr ResultCode& operator=(const ResultCode& o) { | ||
| 143 | raw = o.raw; | ||
| 144 | return *this; | ||
| 145 | } | ||
| 146 | |||
| 147 | constexpr bool IsSuccess() const { | 131 | constexpr bool IsSuccess() const { |
| 148 | return raw == 0; | 132 | return raw == 0; |
| 149 | } | 133 | } |
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 @@ | |||
| 11 | #include "core/hle/ipc.h" | 11 | #include "core/hle/ipc.h" |
| 12 | #include "core/hle/ipc_helpers.h" | 12 | #include "core/hle/ipc_helpers.h" |
| 13 | #include "core/hle/kernel/client_port.h" | 13 | #include "core/hle/kernel/client_port.h" |
| 14 | #include "core/hle/kernel/handle_table.h" | ||
| 15 | #include "core/hle/kernel/kernel.h" | 14 | #include "core/hle/kernel/kernel.h" |
| 16 | #include "core/hle/kernel/process.h" | 15 | #include "core/hle/kernel/process.h" |
| 17 | #include "core/hle/kernel/server_port.h" | 16 | #include "core/hle/kernel/server_port.h" |
| @@ -76,7 +75,8 @@ namespace Service { | |||
| 76 | * Creates a function string for logging, complete with the name (or header code, depending | 75 | * Creates a function string for logging, complete with the name (or header code, depending |
| 77 | * on what's passed in) the port name, and all the cmd_buff arguments. | 76 | * on what's passed in) the port name, and all the cmd_buff arguments. |
| 78 | */ | 77 | */ |
| 79 | [[maybe_unused]] static std::string MakeFunctionString(const char* name, const char* port_name, | 78 | [[maybe_unused]] static std::string MakeFunctionString(std::string_view name, |
| 79 | std::string_view port_name, | ||
| 80 | const u32* cmd_buff) { | 80 | const u32* cmd_buff) { |
| 81 | // Number of params == bits 0-5 + bits 6-11 | 81 | // Number of params == bits 0-5 + bits 6-11 |
| 82 | int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); | 82 | int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); |
| @@ -158,9 +158,7 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) { | |||
| 158 | return ReportUnimplementedFunction(ctx, info); | 158 | return ReportUnimplementedFunction(ctx, info); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | LOG_TRACE( | 161 | LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer())); |
| 162 | Service, "{}", | ||
| 163 | MakeFunctionString(info->name, GetServiceName().c_str(), ctx.CommandBuffer()).c_str()); | ||
| 164 | handler_invoker(this, info->handler_callback, ctx); | 162 | handler_invoker(this, info->handler_callback, ctx); |
| 165 | } | 163 | } |
| 166 | 164 | ||
| @@ -169,7 +167,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co | |||
| 169 | case IPC::CommandType::Close: { | 167 | case IPC::CommandType::Close: { |
| 170 | IPC::ResponseBuilder rb{context, 2}; | 168 | IPC::ResponseBuilder rb{context, 2}; |
| 171 | rb.Push(RESULT_SUCCESS); | 169 | rb.Push(RESULT_SUCCESS); |
| 172 | return ResultCode(ErrorModule::HIPC, ErrorDescription::RemoteProcessDead); | 170 | return IPC::ERR_REMOTE_PROCESS_DEAD; |
| 173 | } | 171 | } |
| 174 | case IPC::CommandType::ControlWithContext: | 172 | case IPC::CommandType::ControlWithContext: |
| 175 | case IPC::CommandType::Control: { | 173 | case IPC::CommandType::Control: { |
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: | |||
| 67 | if (port == nullptr) { | 67 | if (port == nullptr) { |
| 68 | return nullptr; | 68 | return nullptr; |
| 69 | } | 69 | } |
| 70 | return std::static_pointer_cast<T>(port->hle_handler); | 70 | return std::static_pointer_cast<T>(port->GetHLEHandler()); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | void InvokeControlRequest(Kernel::HLERequestContext& context); | 73 | 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 @@ | |||
| 24 | #include "core/hle/service/nvdrv/nvdrv.h" | 24 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 25 | #include "core/hle/service/nvflinger/buffer_queue.h" | 25 | #include "core/hle/service/nvflinger/buffer_queue.h" |
| 26 | #include "core/hle/service/nvflinger/nvflinger.h" | 26 | #include "core/hle/service/nvflinger/nvflinger.h" |
| 27 | #include "core/hle/service/service.h" | ||
| 27 | #include "core/hle/service/vi/vi.h" | 28 | #include "core/hle/service/vi/vi.h" |
| 28 | #include "core/hle/service/vi/vi_m.h" | 29 | #include "core/hle/service/vi/vi_m.h" |
| 29 | #include "core/hle/service/vi/vi_s.h" | 30 | #include "core/hle/service/vi/vi_s.h" |
| @@ -33,6 +34,7 @@ | |||
| 33 | namespace Service::VI { | 34 | namespace Service::VI { |
| 34 | 35 | ||
| 35 | constexpr ResultCode ERR_OPERATION_FAILED{ErrorModule::VI, 1}; | 36 | constexpr ResultCode ERR_OPERATION_FAILED{ErrorModule::VI, 1}; |
| 37 | constexpr ResultCode ERR_PERMISSION_DENIED{ErrorModule::VI, 5}; | ||
| 36 | constexpr ResultCode ERR_UNSUPPORTED{ErrorModule::VI, 6}; | 38 | constexpr ResultCode ERR_UNSUPPORTED{ErrorModule::VI, 6}; |
| 37 | constexpr ResultCode ERR_NOT_FOUND{ErrorModule::VI, 7}; | 39 | constexpr ResultCode ERR_NOT_FOUND{ErrorModule::VI, 7}; |
| 38 | 40 | ||
| @@ -1203,26 +1205,40 @@ IApplicationDisplayService::IApplicationDisplayService( | |||
| 1203 | RegisterHandlers(functions); | 1205 | RegisterHandlers(functions); |
| 1204 | } | 1206 | } |
| 1205 | 1207 | ||
| 1206 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name, | 1208 | static bool IsValidServiceAccess(Permission permission, Policy policy) { |
| 1207 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 1209 | if (permission == Permission::User) { |
| 1208 | : ServiceFramework(name), module(std::move(module)), nv_flinger(std::move(nv_flinger)) {} | 1210 | return policy == Policy::User; |
| 1211 | } | ||
| 1212 | |||
| 1213 | if (permission == Permission::System || permission == Permission::Manager) { | ||
| 1214 | return policy == Policy::User || policy == Policy::Compositor; | ||
| 1215 | } | ||
| 1209 | 1216 | ||
| 1210 | Module::Interface::~Interface() = default; | 1217 | return false; |
| 1218 | } | ||
| 1211 | 1219 | ||
| 1212 | void Module::Interface::GetDisplayService(Kernel::HLERequestContext& ctx) { | 1220 | void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, |
| 1213 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 1221 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger, |
| 1222 | Permission permission) { | ||
| 1223 | IPC::RequestParser rp{ctx}; | ||
| 1224 | const auto policy = rp.PopEnum<Policy>(); | ||
| 1225 | |||
| 1226 | if (!IsValidServiceAccess(permission, policy)) { | ||
| 1227 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1228 | rb.Push(ERR_PERMISSION_DENIED); | ||
| 1229 | return; | ||
| 1230 | } | ||
| 1214 | 1231 | ||
| 1215 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1232 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1216 | rb.Push(RESULT_SUCCESS); | 1233 | rb.Push(RESULT_SUCCESS); |
| 1217 | rb.PushIpcInterface<IApplicationDisplayService>(nv_flinger); | 1234 | rb.PushIpcInterface<IApplicationDisplayService>(std::move(nv_flinger)); |
| 1218 | } | 1235 | } |
| 1219 | 1236 | ||
| 1220 | void InstallInterfaces(SM::ServiceManager& service_manager, | 1237 | void InstallInterfaces(SM::ServiceManager& service_manager, |
| 1221 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) { | 1238 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) { |
| 1222 | auto module = std::make_shared<Module>(); | 1239 | std::make_shared<VI_M>(nv_flinger)->InstallAsService(service_manager); |
| 1223 | std::make_shared<VI_M>(module, nv_flinger)->InstallAsService(service_manager); | 1240 | std::make_shared<VI_S>(nv_flinger)->InstallAsService(service_manager); |
| 1224 | std::make_shared<VI_S>(module, nv_flinger)->InstallAsService(service_manager); | 1241 | std::make_shared<VI_U>(nv_flinger)->InstallAsService(service_manager); |
| 1225 | std::make_shared<VI_U>(module, nv_flinger)->InstallAsService(service_manager); | ||
| 1226 | } | 1242 | } |
| 1227 | 1243 | ||
| 1228 | } // namespace Service::VI | 1244 | } // 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 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include <memory> |
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | class HLERequestContext; | ||
| 12 | } | ||
| 8 | 13 | ||
| 9 | namespace Service::NVFlinger { | 14 | namespace Service::NVFlinger { |
| 10 | class NVFlinger; | 15 | class NVFlinger; |
| 11 | } | 16 | } |
| 12 | 17 | ||
| 18 | namespace Service::SM { | ||
| 19 | class ServiceManager; | ||
| 20 | } | ||
| 21 | |||
| 13 | namespace Service::VI { | 22 | namespace Service::VI { |
| 14 | 23 | ||
| 15 | enum class DisplayResolution : u32 { | 24 | enum class DisplayResolution : u32 { |
| @@ -19,22 +28,25 @@ enum class DisplayResolution : u32 { | |||
| 19 | UndockedHeight = 720, | 28 | UndockedHeight = 720, |
| 20 | }; | 29 | }; |
| 21 | 30 | ||
| 22 | class Module final { | 31 | /// Permission level for a particular VI service instance |
| 23 | public: | 32 | enum class Permission { |
| 24 | class Interface : public ServiceFramework<Interface> { | 33 | User, |
| 25 | public: | 34 | System, |
| 26 | explicit Interface(std::shared_ptr<Module> module, const char* name, | 35 | Manager, |
| 27 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 36 | }; |
| 28 | ~Interface() override; | ||
| 29 | |||
| 30 | void GetDisplayService(Kernel::HLERequestContext& ctx); | ||
| 31 | 37 | ||
| 32 | protected: | 38 | /// A policy type that may be requested via GetDisplayService and |
| 33 | std::shared_ptr<Module> module; | 39 | /// GetDisplayServiceWithProxyNameExchange |
| 34 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 40 | enum class Policy { |
| 35 | }; | 41 | User, |
| 42 | Compositor, | ||
| 36 | }; | 43 | }; |
| 37 | 44 | ||
| 45 | namespace detail { | ||
| 46 | void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, | ||
| 47 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger, Permission permission); | ||
| 48 | } // namespace detail | ||
| 49 | |||
| 38 | /// Registers all VI services with the specified service manager. | 50 | /// Registers all VI services with the specified service manager. |
| 39 | void InstallInterfaces(SM::ServiceManager& service_manager, | 51 | void InstallInterfaces(SM::ServiceManager& service_manager, |
| 40 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 52 | 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 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/hle/service/vi/vi.h" | ||
| 5 | #include "core/hle/service/vi/vi_m.h" | 7 | #include "core/hle/service/vi/vi_m.h" |
| 6 | 8 | ||
| 7 | namespace Service::VI { | 9 | namespace Service::VI { |
| 8 | 10 | ||
| 9 | VI_M::VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 11 | VI_M::VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) |
| 10 | : Module::Interface(std::move(module), "vi:m", std::move(nv_flinger)) { | 12 | : ServiceFramework{"vi:m"}, nv_flinger{std::move(nv_flinger)} { |
| 11 | static const FunctionInfo functions[] = { | 13 | static const FunctionInfo functions[] = { |
| 12 | {2, &VI_M::GetDisplayService, "GetDisplayService"}, | 14 | {2, &VI_M::GetDisplayService, "GetDisplayService"}, |
| 13 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, | 15 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, |
| @@ -17,4 +19,10 @@ VI_M::VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> | |||
| 17 | 19 | ||
| 18 | VI_M::~VI_M() = default; | 20 | VI_M::~VI_M() = default; |
| 19 | 21 | ||
| 22 | void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) { | ||
| 23 | LOG_DEBUG(Service_VI, "called"); | ||
| 24 | |||
| 25 | detail::GetDisplayServiceImpl(ctx, nv_flinger, Permission::Manager); | ||
| 26 | } | ||
| 27 | |||
| 20 | } // namespace Service::VI | 28 | } // 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 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/service/vi/vi.h" | 7 | #include "core/hle/service/service.h" |
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | class HLERequestContext; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Service::NVFlinger { | ||
| 14 | class NVFlinger; | ||
| 15 | } | ||
| 8 | 16 | ||
| 9 | namespace Service::VI { | 17 | namespace Service::VI { |
| 10 | 18 | ||
| 11 | class VI_M final : public Module::Interface { | 19 | class VI_M final : public ServiceFramework<VI_M> { |
| 12 | public: | 20 | public: |
| 13 | explicit VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 21 | explicit VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); |
| 14 | ~VI_M() override; | 22 | ~VI_M() override; |
| 23 | |||
| 24 | private: | ||
| 25 | void GetDisplayService(Kernel::HLERequestContext& ctx); | ||
| 26 | |||
| 27 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | ||
| 15 | }; | 28 | }; |
| 16 | 29 | ||
| 17 | } // namespace Service::VI | 30 | } // 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 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/hle/service/vi/vi.h" | ||
| 5 | #include "core/hle/service/vi/vi_s.h" | 7 | #include "core/hle/service/vi/vi_s.h" |
| 6 | 8 | ||
| 7 | namespace Service::VI { | 9 | namespace Service::VI { |
| 8 | 10 | ||
| 9 | VI_S::VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 11 | VI_S::VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) |
| 10 | : Module::Interface(std::move(module), "vi:s", std::move(nv_flinger)) { | 12 | : ServiceFramework{"vi:s"}, nv_flinger{std::move(nv_flinger)} { |
| 11 | static const FunctionInfo functions[] = { | 13 | static const FunctionInfo functions[] = { |
| 12 | {1, &VI_S::GetDisplayService, "GetDisplayService"}, | 14 | {1, &VI_S::GetDisplayService, "GetDisplayService"}, |
| 13 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, | 15 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, |
| @@ -17,4 +19,10 @@ VI_S::VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> | |||
| 17 | 19 | ||
| 18 | VI_S::~VI_S() = default; | 20 | VI_S::~VI_S() = default; |
| 19 | 21 | ||
| 22 | void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) { | ||
| 23 | LOG_DEBUG(Service_VI, "called"); | ||
| 24 | |||
| 25 | detail::GetDisplayServiceImpl(ctx, nv_flinger, Permission::System); | ||
| 26 | } | ||
| 27 | |||
| 20 | } // namespace Service::VI | 28 | } // 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 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/service/vi/vi.h" | 7 | #include "core/hle/service/service.h" |
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | class HLERequestContext; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Service::NVFlinger { | ||
| 14 | class NVFlinger; | ||
| 15 | } | ||
| 8 | 16 | ||
| 9 | namespace Service::VI { | 17 | namespace Service::VI { |
| 10 | 18 | ||
| 11 | class VI_S final : public Module::Interface { | 19 | class VI_S final : public ServiceFramework<VI_S> { |
| 12 | public: | 20 | public: |
| 13 | explicit VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 21 | explicit VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); |
| 14 | ~VI_S() override; | 22 | ~VI_S() override; |
| 23 | |||
| 24 | private: | ||
| 25 | void GetDisplayService(Kernel::HLERequestContext& ctx); | ||
| 26 | |||
| 27 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | ||
| 15 | }; | 28 | }; |
| 16 | 29 | ||
| 17 | } // namespace Service::VI | 30 | } // 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 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/hle/service/vi/vi.h" | ||
| 5 | #include "core/hle/service/vi/vi_u.h" | 7 | #include "core/hle/service/vi/vi_u.h" |
| 6 | 8 | ||
| 7 | namespace Service::VI { | 9 | namespace Service::VI { |
| 8 | 10 | ||
| 9 | VI_U::VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 11 | VI_U::VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) |
| 10 | : Module::Interface(std::move(module), "vi:u", std::move(nv_flinger)) { | 12 | : ServiceFramework{"vi:u"}, nv_flinger{std::move(nv_flinger)} { |
| 11 | static const FunctionInfo functions[] = { | 13 | static const FunctionInfo functions[] = { |
| 12 | {0, &VI_U::GetDisplayService, "GetDisplayService"}, | 14 | {0, &VI_U::GetDisplayService, "GetDisplayService"}, |
| 13 | }; | 15 | }; |
| @@ -16,4 +18,10 @@ VI_U::VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> | |||
| 16 | 18 | ||
| 17 | VI_U::~VI_U() = default; | 19 | VI_U::~VI_U() = default; |
| 18 | 20 | ||
| 21 | void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) { | ||
| 22 | LOG_DEBUG(Service_VI, "called"); | ||
| 23 | |||
| 24 | detail::GetDisplayServiceImpl(ctx, nv_flinger, Permission::User); | ||
| 25 | } | ||
| 26 | |||
| 19 | } // namespace Service::VI | 27 | } // 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 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/service/vi/vi.h" | 7 | #include "core/hle/service/service.h" |
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | class HLERequestContext; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Service::NVFlinger { | ||
| 14 | class NVFlinger; | ||
| 15 | } | ||
| 8 | 16 | ||
| 9 | namespace Service::VI { | 17 | namespace Service::VI { |
| 10 | 18 | ||
| 11 | class VI_U final : public Module::Interface { | 19 | class VI_U final : public ServiceFramework<VI_U> { |
| 12 | public: | 20 | public: |
| 13 | explicit VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 21 | explicit VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); |
| 14 | ~VI_U() override; | 22 | ~VI_U() override; |
| 23 | |||
| 24 | private: | ||
| 25 | void GetDisplayService(Kernel::HLERequestContext& ctx); | ||
| 26 | |||
| 27 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | ||
| 15 | }; | 28 | }; |
| 16 | 29 | ||
| 17 | } // namespace Service::VI | 30 | } // namespace Service::VI |
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 1c7db28c0..5b4e032bd 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -7,15 +7,18 @@ add_library(input_common STATIC | |||
| 7 | main.h | 7 | main.h |
| 8 | motion_emu.cpp | 8 | motion_emu.cpp |
| 9 | motion_emu.h | 9 | motion_emu.h |
| 10 | 10 | sdl/sdl.cpp | |
| 11 | $<$<BOOL:${SDL2_FOUND}>:sdl/sdl.cpp sdl/sdl.h> | 11 | sdl/sdl.h |
| 12 | ) | 12 | ) |
| 13 | 13 | ||
| 14 | create_target_directory_groups(input_common) | ||
| 15 | |||
| 16 | target_link_libraries(input_common PUBLIC core PRIVATE common) | ||
| 17 | |||
| 18 | if(SDL2_FOUND) | 14 | if(SDL2_FOUND) |
| 15 | target_sources(input_common PRIVATE | ||
| 16 | sdl/sdl_impl.cpp | ||
| 17 | sdl/sdl_impl.h | ||
| 18 | ) | ||
| 19 | target_link_libraries(input_common PRIVATE SDL2) | 19 | target_link_libraries(input_common PRIVATE SDL2) |
| 20 | target_compile_definitions(input_common PRIVATE HAVE_SDL2) | 20 | target_compile_definitions(input_common PRIVATE HAVE_SDL2) |
| 21 | endif() | 21 | endif() |
| 22 | |||
| 23 | create_target_directory_groups(input_common) | ||
| 24 | target_link_libraries(input_common PUBLIC core PRIVATE common) | ||
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 37f572853..8e66c1b15 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp | |||
| @@ -17,10 +17,7 @@ namespace InputCommon { | |||
| 17 | 17 | ||
| 18 | static std::shared_ptr<Keyboard> keyboard; | 18 | static std::shared_ptr<Keyboard> keyboard; |
| 19 | static std::shared_ptr<MotionEmu> motion_emu; | 19 | static std::shared_ptr<MotionEmu> motion_emu; |
| 20 | 20 | static std::unique_ptr<SDL::State> sdl; | |
| 21 | #ifdef HAVE_SDL2 | ||
| 22 | static std::thread poll_thread; | ||
| 23 | #endif | ||
| 24 | 21 | ||
| 25 | void Init() { | 22 | void Init() { |
| 26 | keyboard = std::make_shared<Keyboard>(); | 23 | keyboard = std::make_shared<Keyboard>(); |
| @@ -30,15 +27,7 @@ void Init() { | |||
| 30 | motion_emu = std::make_shared<MotionEmu>(); | 27 | motion_emu = std::make_shared<MotionEmu>(); |
| 31 | Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu); | 28 | Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu); |
| 32 | 29 | ||
| 33 | #ifdef HAVE_SDL2 | 30 | sdl = SDL::Init(); |
| 34 | SDL::Init(); | ||
| 35 | #endif | ||
| 36 | } | ||
| 37 | |||
| 38 | void StartJoystickEventHandler() { | ||
| 39 | #ifdef HAVE_SDL2 | ||
| 40 | poll_thread = std::thread(SDL::PollLoop); | ||
| 41 | #endif | ||
| 42 | } | 31 | } |
| 43 | 32 | ||
| 44 | void Shutdown() { | 33 | void Shutdown() { |
| @@ -47,11 +36,7 @@ void Shutdown() { | |||
| 47 | Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button"); | 36 | Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button"); |
| 48 | Input::UnregisterFactory<Input::MotionDevice>("motion_emu"); | 37 | Input::UnregisterFactory<Input::MotionDevice>("motion_emu"); |
| 49 | motion_emu.reset(); | 38 | motion_emu.reset(); |
| 50 | 39 | sdl.reset(); | |
| 51 | #ifdef HAVE_SDL2 | ||
| 52 | SDL::Shutdown(); | ||
| 53 | poll_thread.join(); | ||
| 54 | #endif | ||
| 55 | } | 40 | } |
| 56 | 41 | ||
| 57 | Keyboard* GetKeyboard() { | 42 | Keyboard* GetKeyboard() { |
| @@ -88,7 +73,7 @@ namespace Polling { | |||
| 88 | 73 | ||
| 89 | std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) { | 74 | std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) { |
| 90 | #ifdef HAVE_SDL2 | 75 | #ifdef HAVE_SDL2 |
| 91 | return SDL::Polling::GetPollers(type); | 76 | return sdl->GetPollers(type); |
| 92 | #else | 77 | #else |
| 93 | return {}; | 78 | return {}; |
| 94 | #endif | 79 | #endif |
diff --git a/src/input_common/main.h b/src/input_common/main.h index 9eb13106e..77a0ce90b 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h | |||
| @@ -20,8 +20,6 @@ void Init(); | |||
| 20 | /// Deregisters all built-in input device factories and shuts them down. | 20 | /// Deregisters all built-in input device factories and shuts them down. |
| 21 | void Shutdown(); | 21 | void Shutdown(); |
| 22 | 22 | ||
| 23 | void StartJoystickEventHandler(); | ||
| 24 | |||
| 25 | class Keyboard; | 23 | class Keyboard; |
| 26 | 24 | ||
| 27 | /// Gets the keyboard button device factory. | 25 | /// Gets the keyboard button device factory. |
diff --git a/src/input_common/sdl/sdl.cpp b/src/input_common/sdl/sdl.cpp index faf3c1fa3..644db3448 100644 --- a/src/input_common/sdl/sdl.cpp +++ b/src/input_common/sdl/sdl.cpp | |||
| @@ -1,631 +1,19 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | 1 | // Copyright 2018 Citra Emulator Project |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 6 | #include <atomic> | ||
| 7 | #include <cmath> | ||
| 8 | #include <functional> | ||
| 9 | #include <iterator> | ||
| 10 | #include <mutex> | ||
| 11 | #include <string> | ||
| 12 | #include <thread> | ||
| 13 | #include <tuple> | ||
| 14 | #include <unordered_map> | ||
| 15 | #include <utility> | ||
| 16 | #include <vector> | ||
| 17 | #include <SDL.h> | ||
| 18 | #include "common/assert.h" | ||
| 19 | #include "common/logging/log.h" | ||
| 20 | #include "common/math_util.h" | ||
| 21 | #include "common/param_package.h" | ||
| 22 | #include "common/threadsafe_queue.h" | ||
| 23 | #include "input_common/main.h" | ||
| 24 | #include "input_common/sdl/sdl.h" | 5 | #include "input_common/sdl/sdl.h" |
| 6 | #ifdef HAVE_SDL2 | ||
| 7 | #include "input_common/sdl/sdl_impl.h" | ||
| 8 | #endif | ||
| 25 | 9 | ||
| 26 | namespace InputCommon { | 10 | namespace InputCommon::SDL { |
| 27 | 11 | ||
| 28 | namespace SDL { | 12 | std::unique_ptr<State> Init() { |
| 29 | 13 | #ifdef HAVE_SDL2 | |
| 30 | class SDLJoystick; | 14 | return std::make_unique<SDLState>(); |
| 31 | class SDLButtonFactory; | 15 | #else |
| 32 | class SDLAnalogFactory; | 16 | return std::make_unique<NullState>(); |
| 33 | 17 | #endif | |
| 34 | /// Map of GUID of a list of corresponding virtual Joysticks | ||
| 35 | static std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map; | ||
| 36 | static std::mutex joystick_map_mutex; | ||
| 37 | |||
| 38 | static std::shared_ptr<SDLButtonFactory> button_factory; | ||
| 39 | static std::shared_ptr<SDLAnalogFactory> analog_factory; | ||
| 40 | |||
| 41 | /// Used by the Pollers during config | ||
| 42 | static std::atomic<bool> polling; | ||
| 43 | static Common::SPSCQueue<SDL_Event> event_queue; | ||
| 44 | |||
| 45 | static std::atomic<bool> initialized = false; | ||
| 46 | |||
| 47 | static std::string GetGUID(SDL_Joystick* joystick) { | ||
| 48 | SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); | ||
| 49 | char guid_str[33]; | ||
| 50 | SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); | ||
| 51 | return guid_str; | ||
| 52 | } | ||
| 53 | |||
| 54 | class SDLJoystick { | ||
| 55 | public: | ||
| 56 | SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, | ||
| 57 | decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose) | ||
| 58 | : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, deleter} {} | ||
| 59 | |||
| 60 | void SetButton(int button, bool value) { | ||
| 61 | std::lock_guard<std::mutex> lock(mutex); | ||
| 62 | state.buttons[button] = value; | ||
| 63 | } | ||
| 64 | |||
| 65 | bool GetButton(int button) const { | ||
| 66 | std::lock_guard<std::mutex> lock(mutex); | ||
| 67 | return state.buttons.at(button); | ||
| 68 | } | ||
| 69 | |||
| 70 | void SetAxis(int axis, Sint16 value) { | ||
| 71 | std::lock_guard<std::mutex> lock(mutex); | ||
| 72 | state.axes[axis] = value; | ||
| 73 | } | ||
| 74 | |||
| 75 | float GetAxis(int axis) const { | ||
| 76 | std::lock_guard<std::mutex> lock(mutex); | ||
| 77 | return state.axes.at(axis) / 32767.0f; | ||
| 78 | } | ||
| 79 | |||
| 80 | std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const { | ||
| 81 | float x = GetAxis(axis_x); | ||
| 82 | float y = GetAxis(axis_y); | ||
| 83 | y = -y; // 3DS uses an y-axis inverse from SDL | ||
| 84 | |||
| 85 | // Make sure the coordinates are in the unit circle, | ||
| 86 | // otherwise normalize it. | ||
| 87 | float r = x * x + y * y; | ||
| 88 | if (r > 1.0f) { | ||
| 89 | r = std::sqrt(r); | ||
| 90 | x /= r; | ||
| 91 | y /= r; | ||
| 92 | } | ||
| 93 | |||
| 94 | return std::make_tuple(x, y); | ||
| 95 | } | ||
| 96 | |||
| 97 | void SetHat(int hat, Uint8 direction) { | ||
| 98 | std::lock_guard<std::mutex> lock(mutex); | ||
| 99 | state.hats[hat] = direction; | ||
| 100 | } | ||
| 101 | |||
| 102 | bool GetHatDirection(int hat, Uint8 direction) const { | ||
| 103 | std::lock_guard<std::mutex> lock(mutex); | ||
| 104 | return (state.hats.at(hat) & direction) != 0; | ||
| 105 | } | ||
| 106 | /** | ||
| 107 | * The guid of the joystick | ||
| 108 | */ | ||
| 109 | const std::string& GetGUID() const { | ||
| 110 | return guid; | ||
| 111 | } | ||
| 112 | |||
| 113 | /** | ||
| 114 | * The number of joystick from the same type that were connected before this joystick | ||
| 115 | */ | ||
| 116 | int GetPort() const { | ||
| 117 | return port; | ||
| 118 | } | ||
| 119 | |||
| 120 | SDL_Joystick* GetSDLJoystick() const { | ||
| 121 | return sdl_joystick.get(); | ||
| 122 | } | ||
| 123 | |||
| 124 | void SetSDLJoystick(SDL_Joystick* joystick, | ||
| 125 | decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose) { | ||
| 126 | sdl_joystick = | ||
| 127 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)>(joystick, deleter); | ||
| 128 | } | ||
| 129 | |||
| 130 | private: | ||
| 131 | struct State { | ||
| 132 | std::unordered_map<int, bool> buttons; | ||
| 133 | std::unordered_map<int, Sint16> axes; | ||
| 134 | std::unordered_map<int, Uint8> hats; | ||
| 135 | } state; | ||
| 136 | std::string guid; | ||
| 137 | int port; | ||
| 138 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; | ||
| 139 | mutable std::mutex mutex; | ||
| 140 | }; | ||
| 141 | |||
| 142 | /** | ||
| 143 | * Get the nth joystick with the corresponding GUID | ||
| 144 | */ | ||
| 145 | static std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port) { | ||
| 146 | std::lock_guard<std::mutex> lock(joystick_map_mutex); | ||
| 147 | const auto it = joystick_map.find(guid); | ||
| 148 | if (it != joystick_map.end()) { | ||
| 149 | while (it->second.size() <= port) { | ||
| 150 | auto joystick = std::make_shared<SDLJoystick>(guid, it->second.size(), nullptr, | ||
| 151 | [](SDL_Joystick*) {}); | ||
| 152 | it->second.emplace_back(std::move(joystick)); | ||
| 153 | } | ||
| 154 | return it->second[port]; | ||
| 155 | } | ||
| 156 | auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, [](SDL_Joystick*) {}); | ||
| 157 | return joystick_map[guid].emplace_back(std::move(joystick)); | ||
| 158 | } | ||
| 159 | |||
| 160 | /** | ||
| 161 | * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so tie | ||
| 162 | * it to a SDLJoystick with the same guid and that port | ||
| 163 | */ | ||
| 164 | static std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { | ||
| 165 | std::lock_guard<std::mutex> lock(joystick_map_mutex); | ||
| 166 | auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); | ||
| 167 | const std::string guid = GetGUID(sdl_joystick); | ||
| 168 | auto map_it = joystick_map.find(guid); | ||
| 169 | if (map_it != joystick_map.end()) { | ||
| 170 | auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(), | ||
| 171 | [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) { | ||
| 172 | return sdl_joystick == joystick->GetSDLJoystick(); | ||
| 173 | }); | ||
| 174 | if (vec_it != map_it->second.end()) { | ||
| 175 | // This is the common case: There is already an existing SDL_Joystick maped to a | ||
| 176 | // SDLJoystick. return the SDLJoystick | ||
| 177 | return *vec_it; | ||
| 178 | } | ||
| 179 | // Search for a SDLJoystick without a mapped SDL_Joystick... | ||
| 180 | auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(), | ||
| 181 | [](const std::shared_ptr<SDLJoystick>& joystick) { | ||
| 182 | return !joystick->GetSDLJoystick(); | ||
| 183 | }); | ||
| 184 | if (nullptr_it != map_it->second.end()) { | ||
| 185 | // ... and map it | ||
| 186 | (*nullptr_it)->SetSDLJoystick(sdl_joystick); | ||
| 187 | return *nullptr_it; | ||
| 188 | } | ||
| 189 | // There is no SDLJoystick without a mapped SDL_Joystick | ||
| 190 | // Create a new SDLJoystick | ||
| 191 | auto joystick = std::make_shared<SDLJoystick>(guid, map_it->second.size(), sdl_joystick); | ||
| 192 | return map_it->second.emplace_back(std::move(joystick)); | ||
| 193 | } | ||
| 194 | auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); | ||
| 195 | return joystick_map[guid].emplace_back(std::move(joystick)); | ||
| 196 | } | ||
| 197 | |||
| 198 | void InitJoystick(int joystick_index) { | ||
| 199 | std::lock_guard<std::mutex> lock(joystick_map_mutex); | ||
| 200 | SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); | ||
| 201 | if (!sdl_joystick) { | ||
| 202 | LOG_ERROR(Input, "failed to open joystick {}", joystick_index); | ||
| 203 | return; | ||
| 204 | } | ||
| 205 | std::string guid = GetGUID(sdl_joystick); | ||
| 206 | if (joystick_map.find(guid) == joystick_map.end()) { | ||
| 207 | auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); | ||
| 208 | joystick_map[guid].emplace_back(std::move(joystick)); | ||
| 209 | return; | ||
| 210 | } | ||
| 211 | auto& joystick_guid_list = joystick_map[guid]; | ||
| 212 | const auto it = std::find_if( | ||
| 213 | joystick_guid_list.begin(), joystick_guid_list.end(), | ||
| 214 | [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); }); | ||
| 215 | if (it != joystick_guid_list.end()) { | ||
| 216 | (*it)->SetSDLJoystick(sdl_joystick); | ||
| 217 | return; | ||
| 218 | } | ||
| 219 | auto joystick = std::make_shared<SDLJoystick>(guid, joystick_guid_list.size(), sdl_joystick); | ||
| 220 | joystick_guid_list.emplace_back(std::move(joystick)); | ||
| 221 | } | ||
| 222 | |||
| 223 | void CloseJoystick(SDL_Joystick* sdl_joystick) { | ||
| 224 | std::lock_guard<std::mutex> lock(joystick_map_mutex); | ||
| 225 | std::string guid = GetGUID(sdl_joystick); | ||
| 226 | // This call to guid is save since the joystick is guranteed to be in that map | ||
| 227 | auto& joystick_guid_list = joystick_map[guid]; | ||
| 228 | const auto joystick_it = | ||
| 229 | std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), | ||
| 230 | [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) { | ||
| 231 | return joystick->GetSDLJoystick() == sdl_joystick; | ||
| 232 | }); | ||
| 233 | (*joystick_it)->SetSDLJoystick(nullptr, [](SDL_Joystick*) {}); | ||
| 234 | } | ||
| 235 | |||
| 236 | void HandleGameControllerEvent(const SDL_Event& event) { | ||
| 237 | switch (event.type) { | ||
| 238 | case SDL_JOYBUTTONUP: { | ||
| 239 | auto joystick = GetSDLJoystickBySDLID(event.jbutton.which); | ||
| 240 | if (joystick) { | ||
| 241 | joystick->SetButton(event.jbutton.button, false); | ||
| 242 | } | ||
| 243 | break; | ||
| 244 | } | ||
| 245 | case SDL_JOYBUTTONDOWN: { | ||
| 246 | auto joystick = GetSDLJoystickBySDLID(event.jbutton.which); | ||
| 247 | if (joystick) { | ||
| 248 | joystick->SetButton(event.jbutton.button, true); | ||
| 249 | } | ||
| 250 | break; | ||
| 251 | } | ||
| 252 | case SDL_JOYHATMOTION: { | ||
| 253 | auto joystick = GetSDLJoystickBySDLID(event.jhat.which); | ||
| 254 | if (joystick) { | ||
| 255 | joystick->SetHat(event.jhat.hat, event.jhat.value); | ||
| 256 | } | ||
| 257 | break; | ||
| 258 | } | ||
| 259 | case SDL_JOYAXISMOTION: { | ||
| 260 | auto joystick = GetSDLJoystickBySDLID(event.jaxis.which); | ||
| 261 | if (joystick) { | ||
| 262 | joystick->SetAxis(event.jaxis.axis, event.jaxis.value); | ||
| 263 | } | ||
| 264 | break; | ||
| 265 | } | ||
| 266 | case SDL_JOYDEVICEREMOVED: | ||
| 267 | LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); | ||
| 268 | CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); | ||
| 269 | break; | ||
| 270 | case SDL_JOYDEVICEADDED: | ||
| 271 | LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which); | ||
| 272 | InitJoystick(event.jdevice.which); | ||
| 273 | break; | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | void CloseSDLJoysticks() { | ||
| 278 | std::lock_guard<std::mutex> lock(joystick_map_mutex); | ||
| 279 | joystick_map.clear(); | ||
| 280 | } | ||
| 281 | |||
| 282 | void PollLoop() { | ||
| 283 | if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { | ||
| 284 | LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); | ||
| 285 | return; | ||
| 286 | } | ||
| 287 | |||
| 288 | SDL_Event event; | ||
| 289 | while (initialized) { | ||
| 290 | // Wait for 10 ms or until an event happens | ||
| 291 | if (SDL_WaitEventTimeout(&event, 10)) { | ||
| 292 | // Don't handle the event if we are configuring | ||
| 293 | if (polling) { | ||
| 294 | event_queue.Push(event); | ||
| 295 | } else { | ||
| 296 | HandleGameControllerEvent(event); | ||
| 297 | } | ||
| 298 | } | ||
| 299 | } | ||
| 300 | CloseSDLJoysticks(); | ||
| 301 | SDL_QuitSubSystem(SDL_INIT_JOYSTICK); | ||
| 302 | } | ||
| 303 | |||
| 304 | class SDLButton final : public Input::ButtonDevice { | ||
| 305 | public: | ||
| 306 | explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_) | ||
| 307 | : joystick(std::move(joystick_)), button(button_) {} | ||
| 308 | |||
| 309 | bool GetStatus() const override { | ||
| 310 | return joystick->GetButton(button); | ||
| 311 | } | ||
| 312 | |||
| 313 | private: | ||
| 314 | std::shared_ptr<SDLJoystick> joystick; | ||
| 315 | int button; | ||
| 316 | }; | ||
| 317 | |||
| 318 | class SDLDirectionButton final : public Input::ButtonDevice { | ||
| 319 | public: | ||
| 320 | explicit SDLDirectionButton(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) | ||
| 321 | : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {} | ||
| 322 | |||
| 323 | bool GetStatus() const override { | ||
| 324 | return joystick->GetHatDirection(hat, direction); | ||
| 325 | } | ||
| 326 | |||
| 327 | private: | ||
| 328 | std::shared_ptr<SDLJoystick> joystick; | ||
| 329 | int hat; | ||
| 330 | Uint8 direction; | ||
| 331 | }; | ||
| 332 | |||
| 333 | class SDLAxisButton final : public Input::ButtonDevice { | ||
| 334 | public: | ||
| 335 | explicit SDLAxisButton(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_, | ||
| 336 | bool trigger_if_greater_) | ||
| 337 | : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_), | ||
| 338 | trigger_if_greater(trigger_if_greater_) {} | ||
| 339 | |||
| 340 | bool GetStatus() const override { | ||
| 341 | float axis_value = joystick->GetAxis(axis); | ||
| 342 | if (trigger_if_greater) | ||
| 343 | return axis_value > threshold; | ||
| 344 | return axis_value < threshold; | ||
| 345 | } | ||
| 346 | |||
| 347 | private: | ||
| 348 | std::shared_ptr<SDLJoystick> joystick; | ||
| 349 | int axis; | ||
| 350 | float threshold; | ||
| 351 | bool trigger_if_greater; | ||
| 352 | }; | ||
| 353 | |||
| 354 | class SDLAnalog final : public Input::AnalogDevice { | ||
| 355 | public: | ||
| 356 | SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_) | ||
| 357 | : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_) {} | ||
| 358 | |||
| 359 | std::tuple<float, float> GetStatus() const override { | ||
| 360 | return joystick->GetAnalog(axis_x, axis_y); | ||
| 361 | } | ||
| 362 | |||
| 363 | private: | ||
| 364 | std::shared_ptr<SDLJoystick> joystick; | ||
| 365 | int axis_x; | ||
| 366 | int axis_y; | ||
| 367 | }; | ||
| 368 | |||
| 369 | /// A button device factory that creates button devices from SDL joystick | ||
| 370 | class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> { | ||
| 371 | public: | ||
| 372 | /** | ||
| 373 | * Creates a button device from a joystick button | ||
| 374 | * @param params contains parameters for creating the device: | ||
| 375 | * - "guid": the guid of the joystick to bind | ||
| 376 | * - "port": the nth joystick of the same type to bind | ||
| 377 | * - "button"(optional): the index of the button to bind | ||
| 378 | * - "hat"(optional): the index of the hat to bind as direction buttons | ||
| 379 | * - "axis"(optional): the index of the axis to bind | ||
| 380 | * - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", | ||
| 381 | * "down", "left" or "right" | ||
| 382 | * - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is | ||
| 383 | * triggered if the axis value crosses | ||
| 384 | * - "direction"(only used for axis): "+" means the button is triggered when the axis | ||
| 385 | * value is greater than the threshold; "-" means the button is triggered when the axis | ||
| 386 | * value is smaller than the threshold | ||
| 387 | */ | ||
| 388 | std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override { | ||
| 389 | const std::string guid = params.Get("guid", "0"); | ||
| 390 | const int port = params.Get("port", 0); | ||
| 391 | |||
| 392 | auto joystick = GetSDLJoystickByGUID(guid, port); | ||
| 393 | |||
| 394 | if (params.Has("hat")) { | ||
| 395 | const int hat = params.Get("hat", 0); | ||
| 396 | const std::string direction_name = params.Get("direction", ""); | ||
| 397 | Uint8 direction; | ||
| 398 | if (direction_name == "up") { | ||
| 399 | direction = SDL_HAT_UP; | ||
| 400 | } else if (direction_name == "down") { | ||
| 401 | direction = SDL_HAT_DOWN; | ||
| 402 | } else if (direction_name == "left") { | ||
| 403 | direction = SDL_HAT_LEFT; | ||
| 404 | } else if (direction_name == "right") { | ||
| 405 | direction = SDL_HAT_RIGHT; | ||
| 406 | } else { | ||
| 407 | direction = 0; | ||
| 408 | } | ||
| 409 | // This is necessary so accessing GetHat with hat won't crash | ||
| 410 | joystick->SetHat(hat, SDL_HAT_CENTERED); | ||
| 411 | return std::make_unique<SDLDirectionButton>(joystick, hat, direction); | ||
| 412 | } | ||
| 413 | |||
| 414 | if (params.Has("axis")) { | ||
| 415 | const int axis = params.Get("axis", 0); | ||
| 416 | const float threshold = params.Get("threshold", 0.5f); | ||
| 417 | const std::string direction_name = params.Get("direction", ""); | ||
| 418 | bool trigger_if_greater; | ||
| 419 | if (direction_name == "+") { | ||
| 420 | trigger_if_greater = true; | ||
| 421 | } else if (direction_name == "-") { | ||
| 422 | trigger_if_greater = false; | ||
| 423 | } else { | ||
| 424 | trigger_if_greater = true; | ||
| 425 | LOG_ERROR(Input, "Unknown direction '{}'", direction_name); | ||
| 426 | } | ||
| 427 | // This is necessary so accessing GetAxis with axis won't crash | ||
| 428 | joystick->SetAxis(axis, 0); | ||
| 429 | return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater); | ||
| 430 | } | ||
| 431 | |||
| 432 | const int button = params.Get("button", 0); | ||
| 433 | // This is necessary so accessing GetButton with button won't crash | ||
| 434 | joystick->SetButton(button, false); | ||
| 435 | return std::make_unique<SDLButton>(joystick, button); | ||
| 436 | } | ||
| 437 | }; | ||
| 438 | |||
| 439 | /// An analog device factory that creates analog devices from SDL joystick | ||
| 440 | class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> { | ||
| 441 | public: | ||
| 442 | /** | ||
| 443 | * Creates analog device from joystick axes | ||
| 444 | * @param params contains parameters for creating the device: | ||
| 445 | * - "guid": the guid of the joystick to bind | ||
| 446 | * - "port": the nth joystick of the same type | ||
| 447 | * - "axis_x": the index of the axis to be bind as x-axis | ||
| 448 | * - "axis_y": the index of the axis to be bind as y-axis | ||
| 449 | */ | ||
| 450 | std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override { | ||
| 451 | const std::string guid = params.Get("guid", "0"); | ||
| 452 | const int port = params.Get("port", 0); | ||
| 453 | const int axis_x = params.Get("axis_x", 0); | ||
| 454 | const int axis_y = params.Get("axis_y", 1); | ||
| 455 | |||
| 456 | auto joystick = GetSDLJoystickByGUID(guid, port); | ||
| 457 | |||
| 458 | // This is necessary so accessing GetAxis with axis_x and axis_y won't crash | ||
| 459 | joystick->SetAxis(axis_x, 0); | ||
| 460 | joystick->SetAxis(axis_y, 0); | ||
| 461 | return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y); | ||
| 462 | } | ||
| 463 | }; | ||
| 464 | |||
| 465 | void Init() { | ||
| 466 | using namespace Input; | ||
| 467 | RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>()); | ||
| 468 | RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>()); | ||
| 469 | polling = false; | ||
| 470 | initialized = true; | ||
| 471 | } | ||
| 472 | |||
| 473 | void Shutdown() { | ||
| 474 | if (initialized) { | ||
| 475 | using namespace Input; | ||
| 476 | UnregisterFactory<ButtonDevice>("sdl"); | ||
| 477 | UnregisterFactory<AnalogDevice>("sdl"); | ||
| 478 | initialized = false; | ||
| 479 | } | ||
| 480 | } | ||
| 481 | |||
| 482 | Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) { | ||
| 483 | Common::ParamPackage params({{"engine", "sdl"}}); | ||
| 484 | switch (event.type) { | ||
| 485 | case SDL_JOYAXISMOTION: { | ||
| 486 | auto joystick = GetSDLJoystickBySDLID(event.jaxis.which); | ||
| 487 | params.Set("port", joystick->GetPort()); | ||
| 488 | params.Set("guid", joystick->GetGUID()); | ||
| 489 | params.Set("axis", event.jaxis.axis); | ||
| 490 | if (event.jaxis.value > 0) { | ||
| 491 | params.Set("direction", "+"); | ||
| 492 | params.Set("threshold", "0.5"); | ||
| 493 | } else { | ||
| 494 | params.Set("direction", "-"); | ||
| 495 | params.Set("threshold", "-0.5"); | ||
| 496 | } | ||
| 497 | break; | ||
| 498 | } | ||
| 499 | case SDL_JOYBUTTONUP: { | ||
| 500 | auto joystick = GetSDLJoystickBySDLID(event.jbutton.which); | ||
| 501 | params.Set("port", joystick->GetPort()); | ||
| 502 | params.Set("guid", joystick->GetGUID()); | ||
| 503 | params.Set("button", event.jbutton.button); | ||
| 504 | break; | ||
| 505 | } | ||
| 506 | case SDL_JOYHATMOTION: { | ||
| 507 | auto joystick = GetSDLJoystickBySDLID(event.jhat.which); | ||
| 508 | params.Set("port", joystick->GetPort()); | ||
| 509 | params.Set("guid", joystick->GetGUID()); | ||
| 510 | params.Set("hat", event.jhat.hat); | ||
| 511 | switch (event.jhat.value) { | ||
| 512 | case SDL_HAT_UP: | ||
| 513 | params.Set("direction", "up"); | ||
| 514 | break; | ||
| 515 | case SDL_HAT_DOWN: | ||
| 516 | params.Set("direction", "down"); | ||
| 517 | break; | ||
| 518 | case SDL_HAT_LEFT: | ||
| 519 | params.Set("direction", "left"); | ||
| 520 | break; | ||
| 521 | case SDL_HAT_RIGHT: | ||
| 522 | params.Set("direction", "right"); | ||
| 523 | break; | ||
| 524 | default: | ||
| 525 | return {}; | ||
| 526 | } | ||
| 527 | break; | ||
| 528 | } | ||
| 529 | } | ||
| 530 | return params; | ||
| 531 | } | ||
| 532 | |||
| 533 | namespace Polling { | ||
| 534 | |||
| 535 | class SDLPoller : public InputCommon::Polling::DevicePoller { | ||
| 536 | public: | ||
| 537 | void Start() override { | ||
| 538 | event_queue.Clear(); | ||
| 539 | polling = true; | ||
| 540 | } | ||
| 541 | |||
| 542 | void Stop() override { | ||
| 543 | polling = false; | ||
| 544 | } | ||
| 545 | }; | ||
| 546 | |||
| 547 | class SDLButtonPoller final : public SDLPoller { | ||
| 548 | public: | ||
| 549 | Common::ParamPackage GetNextInput() override { | ||
| 550 | SDL_Event event; | ||
| 551 | while (event_queue.Pop(event)) { | ||
| 552 | switch (event.type) { | ||
| 553 | case SDL_JOYAXISMOTION: | ||
| 554 | if (std::abs(event.jaxis.value / 32767.0) < 0.5) { | ||
| 555 | break; | ||
| 556 | } | ||
| 557 | case SDL_JOYBUTTONUP: | ||
| 558 | case SDL_JOYHATMOTION: | ||
| 559 | return SDLEventToButtonParamPackage(event); | ||
| 560 | } | ||
| 561 | } | ||
| 562 | return {}; | ||
| 563 | } | ||
| 564 | }; | ||
| 565 | |||
| 566 | class SDLAnalogPoller final : public SDLPoller { | ||
| 567 | public: | ||
| 568 | void Start() override { | ||
| 569 | SDLPoller::Start(); | ||
| 570 | |||
| 571 | // Reset stored axes | ||
| 572 | analog_xaxis = -1; | ||
| 573 | analog_yaxis = -1; | ||
| 574 | analog_axes_joystick = -1; | ||
| 575 | } | ||
| 576 | |||
| 577 | Common::ParamPackage GetNextInput() override { | ||
| 578 | SDL_Event event; | ||
| 579 | while (event_queue.Pop(event)) { | ||
| 580 | if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { | ||
| 581 | continue; | ||
| 582 | } | ||
| 583 | // An analog device needs two axes, so we need to store the axis for later and wait for | ||
| 584 | // a second SDL event. The axes also must be from the same joystick. | ||
| 585 | int axis = event.jaxis.axis; | ||
| 586 | if (analog_xaxis == -1) { | ||
| 587 | analog_xaxis = axis; | ||
| 588 | analog_axes_joystick = event.jaxis.which; | ||
| 589 | } else if (analog_yaxis == -1 && analog_xaxis != axis && | ||
| 590 | analog_axes_joystick == event.jaxis.which) { | ||
| 591 | analog_yaxis = axis; | ||
| 592 | } | ||
| 593 | } | ||
| 594 | Common::ParamPackage params; | ||
| 595 | if (analog_xaxis != -1 && analog_yaxis != -1) { | ||
| 596 | auto joystick = GetSDLJoystickBySDLID(event.jaxis.which); | ||
| 597 | params.Set("engine", "sdl"); | ||
| 598 | params.Set("port", joystick->GetPort()); | ||
| 599 | params.Set("guid", joystick->GetGUID()); | ||
| 600 | params.Set("axis_x", analog_xaxis); | ||
| 601 | params.Set("axis_y", analog_yaxis); | ||
| 602 | analog_xaxis = -1; | ||
| 603 | analog_yaxis = -1; | ||
| 604 | analog_axes_joystick = -1; | ||
| 605 | return params; | ||
| 606 | } | ||
| 607 | return params; | ||
| 608 | } | ||
| 609 | |||
| 610 | private: | ||
| 611 | int analog_xaxis = -1; | ||
| 612 | int analog_yaxis = -1; | ||
| 613 | SDL_JoystickID analog_axes_joystick = -1; | ||
| 614 | }; | ||
| 615 | |||
| 616 | std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers( | ||
| 617 | InputCommon::Polling::DeviceType type) { | ||
| 618 | std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> pollers; | ||
| 619 | switch (type) { | ||
| 620 | case InputCommon::Polling::DeviceType::Analog: | ||
| 621 | pollers.push_back(std::make_unique<SDLAnalogPoller>()); | ||
| 622 | break; | ||
| 623 | case InputCommon::Polling::DeviceType::Button: | ||
| 624 | pollers.push_back(std::make_unique<SDLButtonPoller>()); | ||
| 625 | break; | ||
| 626 | } | ||
| 627 | return pollers; | ||
| 628 | } | 18 | } |
| 629 | } // namespace Polling | 19 | } // namespace InputCommon::SDL |
| 630 | } // namespace SDL | ||
| 631 | } // namespace InputCommon | ||
diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h index 0206860d3..02a8d2e2c 100644 --- a/src/input_common/sdl/sdl.h +++ b/src/input_common/sdl/sdl.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | 1 | // Copyright 2018 Citra Emulator Project |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| @@ -7,45 +7,36 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | #include "core/frontend/input.h" | 9 | #include "core/frontend/input.h" |
| 10 | #include "input_common/main.h" | ||
| 10 | 11 | ||
| 11 | union SDL_Event; | 12 | union SDL_Event; |
| 13 | |||
| 12 | namespace Common { | 14 | namespace Common { |
| 13 | class ParamPackage; | 15 | class ParamPackage; |
| 14 | } | 16 | } // namespace Common |
| 15 | namespace InputCommon { | 17 | |
| 16 | namespace Polling { | 18 | namespace InputCommon::Polling { |
| 17 | class DevicePoller; | 19 | class DevicePoller; |
| 18 | enum class DeviceType; | 20 | enum class DeviceType; |
| 19 | } // namespace Polling | 21 | } // namespace InputCommon::Polling |
| 20 | } // namespace InputCommon | ||
| 21 | |||
| 22 | namespace InputCommon { | ||
| 23 | namespace SDL { | ||
| 24 | |||
| 25 | /// Initializes and registers SDL device factories | ||
| 26 | void Init(); | ||
| 27 | |||
| 28 | /// Unresisters SDL device factories and shut them down. | ||
| 29 | void Shutdown(); | ||
| 30 | |||
| 31 | /// Needs to be called before SDL_QuitSubSystem. | ||
| 32 | void CloseSDLJoysticks(); | ||
| 33 | 22 | ||
| 34 | /// Handle SDL_Events for joysticks from SDL_PollEvent | 23 | namespace InputCommon::SDL { |
| 35 | void HandleGameControllerEvent(const SDL_Event& event); | ||
| 36 | 24 | ||
| 37 | /// A Loop that calls HandleGameControllerEvent until Shutdown is called | 25 | class State { |
| 38 | void PollLoop(); | 26 | public: |
| 27 | /// Unresisters SDL device factories and shut them down. | ||
| 28 | virtual ~State() = default; | ||
| 39 | 29 | ||
| 40 | /// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice | 30 | virtual std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers( |
| 41 | Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event); | 31 | InputCommon::Polling::DeviceType type) = 0; |
| 32 | }; | ||
| 42 | 33 | ||
| 43 | namespace Polling { | 34 | class NullState : public State { |
| 35 | public: | ||
| 36 | std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers( | ||
| 37 | InputCommon::Polling::DeviceType type) override {} | ||
| 38 | }; | ||
| 44 | 39 | ||
| 45 | /// Get all DevicePoller that use the SDL backend for a specific device type | 40 | std::unique_ptr<State> Init(); |
| 46 | std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers( | ||
| 47 | InputCommon::Polling::DeviceType type); | ||
| 48 | 41 | ||
| 49 | } // namespace Polling | 42 | } // namespace InputCommon::SDL |
| 50 | } // namespace SDL | ||
| 51 | } // namespace InputCommon | ||
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp new file mode 100644 index 000000000..934339d3b --- /dev/null +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -0,0 +1,669 @@ | |||
| 1 | // Copyright 2018 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <atomic> | ||
| 7 | #include <cmath> | ||
| 8 | #include <functional> | ||
| 9 | #include <iterator> | ||
| 10 | #include <mutex> | ||
| 11 | #include <string> | ||
| 12 | #include <thread> | ||
| 13 | #include <tuple> | ||
| 14 | #include <unordered_map> | ||
| 15 | #include <utility> | ||
| 16 | #include <vector> | ||
| 17 | #include <SDL.h> | ||
| 18 | #include "common/assert.h" | ||
| 19 | #include "common/logging/log.h" | ||
| 20 | #include "common/math_util.h" | ||
| 21 | #include "common/param_package.h" | ||
| 22 | #include "common/threadsafe_queue.h" | ||
| 23 | #include "core/frontend/input.h" | ||
| 24 | #include "input_common/sdl/sdl_impl.h" | ||
| 25 | |||
| 26 | namespace InputCommon { | ||
| 27 | |||
| 28 | namespace SDL { | ||
| 29 | |||
| 30 | static std::string GetGUID(SDL_Joystick* joystick) { | ||
| 31 | SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); | ||
| 32 | char guid_str[33]; | ||
| 33 | SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); | ||
| 34 | return guid_str; | ||
| 35 | } | ||
| 36 | |||
| 37 | /// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice | ||
| 38 | static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event); | ||
| 39 | |||
| 40 | static int SDLEventWatcher(void* userdata, SDL_Event* event) { | ||
| 41 | SDLState* sdl_state = reinterpret_cast<SDLState*>(userdata); | ||
| 42 | // Don't handle the event if we are configuring | ||
| 43 | if (sdl_state->polling) { | ||
| 44 | sdl_state->event_queue.Push(*event); | ||
| 45 | } else { | ||
| 46 | sdl_state->HandleGameControllerEvent(*event); | ||
| 47 | } | ||
| 48 | return 0; | ||
| 49 | } | ||
| 50 | |||
| 51 | class SDLJoystick { | ||
| 52 | public: | ||
| 53 | SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, | ||
| 54 | decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose) | ||
| 55 | : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, deleter} {} | ||
| 56 | |||
| 57 | void SetButton(int button, bool value) { | ||
| 58 | std::lock_guard<std::mutex> lock(mutex); | ||
| 59 | state.buttons[button] = value; | ||
| 60 | } | ||
| 61 | |||
| 62 | bool GetButton(int button) const { | ||
| 63 | std::lock_guard<std::mutex> lock(mutex); | ||
| 64 | return state.buttons.at(button); | ||
| 65 | } | ||
| 66 | |||
| 67 | void SetAxis(int axis, Sint16 value) { | ||
| 68 | std::lock_guard<std::mutex> lock(mutex); | ||
| 69 | state.axes[axis] = value; | ||
| 70 | } | ||
| 71 | |||
| 72 | float GetAxis(int axis) const { | ||
| 73 | std::lock_guard<std::mutex> lock(mutex); | ||
| 74 | return state.axes.at(axis) / 32767.0f; | ||
| 75 | } | ||
| 76 | |||
| 77 | std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const { | ||
| 78 | float x = GetAxis(axis_x); | ||
| 79 | float y = GetAxis(axis_y); | ||
| 80 | y = -y; // 3DS uses an y-axis inverse from SDL | ||
| 81 | |||
| 82 | // Make sure the coordinates are in the unit circle, | ||
| 83 | // otherwise normalize it. | ||
| 84 | float r = x * x + y * y; | ||
| 85 | if (r > 1.0f) { | ||
| 86 | r = std::sqrt(r); | ||
| 87 | x /= r; | ||
| 88 | y /= r; | ||
| 89 | } | ||
| 90 | |||
| 91 | return std::make_tuple(x, y); | ||
| 92 | } | ||
| 93 | |||
| 94 | void SetHat(int hat, Uint8 direction) { | ||
| 95 | std::lock_guard<std::mutex> lock(mutex); | ||
| 96 | state.hats[hat] = direction; | ||
| 97 | } | ||
| 98 | |||
| 99 | bool GetHatDirection(int hat, Uint8 direction) const { | ||
| 100 | std::lock_guard<std::mutex> lock(mutex); | ||
| 101 | return (state.hats.at(hat) & direction) != 0; | ||
| 102 | } | ||
| 103 | /** | ||
| 104 | * The guid of the joystick | ||
| 105 | */ | ||
| 106 | const std::string& GetGUID() const { | ||
| 107 | return guid; | ||
| 108 | } | ||
| 109 | |||
| 110 | /** | ||
| 111 | * The number of joystick from the same type that were connected before this joystick | ||
| 112 | */ | ||
| 113 | int GetPort() const { | ||
| 114 | return port; | ||
| 115 | } | ||
| 116 | |||
| 117 | SDL_Joystick* GetSDLJoystick() const { | ||
| 118 | return sdl_joystick.get(); | ||
| 119 | } | ||
| 120 | |||
| 121 | void SetSDLJoystick(SDL_Joystick* joystick, | ||
| 122 | decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose) { | ||
| 123 | sdl_joystick = | ||
| 124 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)>(joystick, deleter); | ||
| 125 | } | ||
| 126 | |||
| 127 | private: | ||
| 128 | struct State { | ||
| 129 | std::unordered_map<int, bool> buttons; | ||
| 130 | std::unordered_map<int, Sint16> axes; | ||
| 131 | std::unordered_map<int, Uint8> hats; | ||
| 132 | } state; | ||
| 133 | std::string guid; | ||
| 134 | int port; | ||
| 135 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; | ||
| 136 | mutable std::mutex mutex; | ||
| 137 | }; | ||
| 138 | |||
| 139 | /** | ||
| 140 | * Get the nth joystick with the corresponding GUID | ||
| 141 | */ | ||
| 142 | std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { | ||
| 143 | std::lock_guard<std::mutex> lock(joystick_map_mutex); | ||
| 144 | const auto it = joystick_map.find(guid); | ||
| 145 | if (it != joystick_map.end()) { | ||
| 146 | while (it->second.size() <= port) { | ||
| 147 | auto joystick = std::make_shared<SDLJoystick>(guid, it->second.size(), nullptr, | ||
| 148 | [](SDL_Joystick*) {}); | ||
| 149 | it->second.emplace_back(std::move(joystick)); | ||
| 150 | } | ||
| 151 | return it->second[port]; | ||
| 152 | } | ||
| 153 | auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, [](SDL_Joystick*) {}); | ||
| 154 | return joystick_map[guid].emplace_back(std::move(joystick)); | ||
| 155 | } | ||
| 156 | |||
| 157 | /** | ||
| 158 | * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so tie | ||
| 159 | * it to a SDLJoystick with the same guid and that port | ||
| 160 | */ | ||
| 161 | std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { | ||
| 162 | auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); | ||
| 163 | const std::string guid = GetGUID(sdl_joystick); | ||
| 164 | std::lock_guard<std::mutex> lock(joystick_map_mutex); | ||
| 165 | auto map_it = joystick_map.find(guid); | ||
| 166 | if (map_it != joystick_map.end()) { | ||
| 167 | auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(), | ||
| 168 | [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) { | ||
| 169 | return sdl_joystick == joystick->GetSDLJoystick(); | ||
| 170 | }); | ||
| 171 | if (vec_it != map_it->second.end()) { | ||
| 172 | // This is the common case: There is already an existing SDL_Joystick maped to a | ||
| 173 | // SDLJoystick. return the SDLJoystick | ||
| 174 | return *vec_it; | ||
| 175 | } | ||
| 176 | // Search for a SDLJoystick without a mapped SDL_Joystick... | ||
| 177 | auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(), | ||
| 178 | [](const std::shared_ptr<SDLJoystick>& joystick) { | ||
| 179 | return !joystick->GetSDLJoystick(); | ||
| 180 | }); | ||
| 181 | if (nullptr_it != map_it->second.end()) { | ||
| 182 | // ... and map it | ||
| 183 | (*nullptr_it)->SetSDLJoystick(sdl_joystick); | ||
| 184 | return *nullptr_it; | ||
| 185 | } | ||
| 186 | // There is no SDLJoystick without a mapped SDL_Joystick | ||
| 187 | // Create a new SDLJoystick | ||
| 188 | auto joystick = std::make_shared<SDLJoystick>(guid, map_it->second.size(), sdl_joystick); | ||
| 189 | return map_it->second.emplace_back(std::move(joystick)); | ||
| 190 | } | ||
| 191 | auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); | ||
| 192 | return joystick_map[guid].emplace_back(std::move(joystick)); | ||
| 193 | } | ||
| 194 | |||
| 195 | void SDLState::InitJoystick(int joystick_index) { | ||
| 196 | SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); | ||
| 197 | if (!sdl_joystick) { | ||
| 198 | LOG_ERROR(Input, "failed to open joystick {}", joystick_index); | ||
| 199 | return; | ||
| 200 | } | ||
| 201 | std::string guid = GetGUID(sdl_joystick); | ||
| 202 | std::lock_guard<std::mutex> lock(joystick_map_mutex); | ||
| 203 | if (joystick_map.find(guid) == joystick_map.end()) { | ||
| 204 | auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); | ||
| 205 | joystick_map[guid].emplace_back(std::move(joystick)); | ||
| 206 | return; | ||
| 207 | } | ||
| 208 | auto& joystick_guid_list = joystick_map[guid]; | ||
| 209 | const auto it = std::find_if( | ||
| 210 | joystick_guid_list.begin(), joystick_guid_list.end(), | ||
| 211 | [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); }); | ||
| 212 | if (it != joystick_guid_list.end()) { | ||
| 213 | (*it)->SetSDLJoystick(sdl_joystick); | ||
| 214 | return; | ||
| 215 | } | ||
| 216 | auto joystick = std::make_shared<SDLJoystick>(guid, joystick_guid_list.size(), sdl_joystick); | ||
| 217 | joystick_guid_list.emplace_back(std::move(joystick)); | ||
| 218 | } | ||
| 219 | |||
| 220 | void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) { | ||
| 221 | std::string guid = GetGUID(sdl_joystick); | ||
| 222 | std::shared_ptr<SDLJoystick> joystick; | ||
| 223 | { | ||
| 224 | std::lock_guard<std::mutex> lock(joystick_map_mutex); | ||
| 225 | // This call to guid is safe since the joystick is guaranteed to be in the map | ||
| 226 | auto& joystick_guid_list = joystick_map[guid]; | ||
| 227 | const auto joystick_it = | ||
| 228 | std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), | ||
| 229 | [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) { | ||
| 230 | return joystick->GetSDLJoystick() == sdl_joystick; | ||
| 231 | }); | ||
| 232 | joystick = *joystick_it; | ||
| 233 | } | ||
| 234 | // Destruct SDL_Joystick outside the lock guard because SDL can internally call event calback | ||
| 235 | // which locks the mutex again | ||
| 236 | joystick->SetSDLJoystick(nullptr, [](SDL_Joystick*) {}); | ||
| 237 | } | ||
| 238 | |||
| 239 | void SDLState::HandleGameControllerEvent(const SDL_Event& event) { | ||
| 240 | switch (event.type) { | ||
| 241 | case SDL_JOYBUTTONUP: { | ||
| 242 | if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { | ||
| 243 | joystick->SetButton(event.jbutton.button, false); | ||
| 244 | } | ||
| 245 | break; | ||
| 246 | } | ||
| 247 | case SDL_JOYBUTTONDOWN: { | ||
| 248 | if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { | ||
| 249 | joystick->SetButton(event.jbutton.button, true); | ||
| 250 | } | ||
| 251 | break; | ||
| 252 | } | ||
| 253 | case SDL_JOYHATMOTION: { | ||
| 254 | if (auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) { | ||
| 255 | joystick->SetHat(event.jhat.hat, event.jhat.value); | ||
| 256 | } | ||
| 257 | break; | ||
| 258 | } | ||
| 259 | case SDL_JOYAXISMOTION: { | ||
| 260 | if (auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) { | ||
| 261 | joystick->SetAxis(event.jaxis.axis, event.jaxis.value); | ||
| 262 | } | ||
| 263 | break; | ||
| 264 | } | ||
| 265 | case SDL_JOYDEVICEREMOVED: | ||
| 266 | LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); | ||
| 267 | CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); | ||
| 268 | break; | ||
| 269 | case SDL_JOYDEVICEADDED: | ||
| 270 | LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which); | ||
| 271 | InitJoystick(event.jdevice.which); | ||
| 272 | break; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | void SDLState::CloseJoysticks() { | ||
| 277 | std::lock_guard<std::mutex> lock(joystick_map_mutex); | ||
| 278 | joystick_map.clear(); | ||
| 279 | } | ||
| 280 | |||
| 281 | class SDLButton final : public Input::ButtonDevice { | ||
| 282 | public: | ||
| 283 | explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_) | ||
| 284 | : joystick(std::move(joystick_)), button(button_) {} | ||
| 285 | |||
| 286 | bool GetStatus() const override { | ||
| 287 | return joystick->GetButton(button); | ||
| 288 | } | ||
| 289 | |||
| 290 | private: | ||
| 291 | std::shared_ptr<SDLJoystick> joystick; | ||
| 292 | int button; | ||
| 293 | }; | ||
| 294 | |||
| 295 | class SDLDirectionButton final : public Input::ButtonDevice { | ||
| 296 | public: | ||
| 297 | explicit SDLDirectionButton(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) | ||
| 298 | : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {} | ||
| 299 | |||
| 300 | bool GetStatus() const override { | ||
| 301 | return joystick->GetHatDirection(hat, direction); | ||
| 302 | } | ||
| 303 | |||
| 304 | private: | ||
| 305 | std::shared_ptr<SDLJoystick> joystick; | ||
| 306 | int hat; | ||
| 307 | Uint8 direction; | ||
| 308 | }; | ||
| 309 | |||
| 310 | class SDLAxisButton final : public Input::ButtonDevice { | ||
| 311 | public: | ||
| 312 | explicit SDLAxisButton(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_, | ||
| 313 | bool trigger_if_greater_) | ||
| 314 | : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_), | ||
| 315 | trigger_if_greater(trigger_if_greater_) {} | ||
| 316 | |||
| 317 | bool GetStatus() const override { | ||
| 318 | float axis_value = joystick->GetAxis(axis); | ||
| 319 | if (trigger_if_greater) | ||
| 320 | return axis_value > threshold; | ||
| 321 | return axis_value < threshold; | ||
| 322 | } | ||
| 323 | |||
| 324 | private: | ||
| 325 | std::shared_ptr<SDLJoystick> joystick; | ||
| 326 | int axis; | ||
| 327 | float threshold; | ||
| 328 | bool trigger_if_greater; | ||
| 329 | }; | ||
| 330 | |||
| 331 | class SDLAnalog final : public Input::AnalogDevice { | ||
| 332 | public: | ||
| 333 | SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_) | ||
| 334 | : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_) {} | ||
| 335 | |||
| 336 | std::tuple<float, float> GetStatus() const override { | ||
| 337 | const auto [x, y] = joystick->GetAnalog(axis_x, axis_y); | ||
| 338 | const float r = std::sqrt((x * x) + (y * y)); | ||
| 339 | if (r > deadzone) { | ||
| 340 | return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone), | ||
| 341 | y / r * (r - deadzone) / (1 - deadzone)); | ||
| 342 | } | ||
| 343 | return std::make_tuple<float, float>(0.0f, 0.0f); | ||
| 344 | } | ||
| 345 | |||
| 346 | private: | ||
| 347 | std::shared_ptr<SDLJoystick> joystick; | ||
| 348 | const int axis_x; | ||
| 349 | const int axis_y; | ||
| 350 | const float deadzone; | ||
| 351 | }; | ||
| 352 | |||
| 353 | /// A button device factory that creates button devices from SDL joystick | ||
| 354 | class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> { | ||
| 355 | public: | ||
| 356 | explicit SDLButtonFactory(SDLState& state_) : state(state_) {} | ||
| 357 | |||
| 358 | /** | ||
| 359 | * Creates a button device from a joystick button | ||
| 360 | * @param params contains parameters for creating the device: | ||
| 361 | * - "guid": the guid of the joystick to bind | ||
| 362 | * - "port": the nth joystick of the same type to bind | ||
| 363 | * - "button"(optional): the index of the button to bind | ||
| 364 | * - "hat"(optional): the index of the hat to bind as direction buttons | ||
| 365 | * - "axis"(optional): the index of the axis to bind | ||
| 366 | * - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", | ||
| 367 | * "down", "left" or "right" | ||
| 368 | * - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is | ||
| 369 | * triggered if the axis value crosses | ||
| 370 | * - "direction"(only used for axis): "+" means the button is triggered when the axis | ||
| 371 | * value is greater than the threshold; "-" means the button is triggered when the axis | ||
| 372 | * value is smaller than the threshold | ||
| 373 | */ | ||
| 374 | std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override { | ||
| 375 | const std::string guid = params.Get("guid", "0"); | ||
| 376 | const int port = params.Get("port", 0); | ||
| 377 | |||
| 378 | auto joystick = state.GetSDLJoystickByGUID(guid, port); | ||
| 379 | |||
| 380 | if (params.Has("hat")) { | ||
| 381 | const int hat = params.Get("hat", 0); | ||
| 382 | const std::string direction_name = params.Get("direction", ""); | ||
| 383 | Uint8 direction; | ||
| 384 | if (direction_name == "up") { | ||
| 385 | direction = SDL_HAT_UP; | ||
| 386 | } else if (direction_name == "down") { | ||
| 387 | direction = SDL_HAT_DOWN; | ||
| 388 | } else if (direction_name == "left") { | ||
| 389 | direction = SDL_HAT_LEFT; | ||
| 390 | } else if (direction_name == "right") { | ||
| 391 | direction = SDL_HAT_RIGHT; | ||
| 392 | } else { | ||
| 393 | direction = 0; | ||
| 394 | } | ||
| 395 | // This is necessary so accessing GetHat with hat won't crash | ||
| 396 | joystick->SetHat(hat, SDL_HAT_CENTERED); | ||
| 397 | return std::make_unique<SDLDirectionButton>(joystick, hat, direction); | ||
| 398 | } | ||
| 399 | |||
| 400 | if (params.Has("axis")) { | ||
| 401 | const int axis = params.Get("axis", 0); | ||
| 402 | const float threshold = params.Get("threshold", 0.5f); | ||
| 403 | const std::string direction_name = params.Get("direction", ""); | ||
| 404 | bool trigger_if_greater; | ||
| 405 | if (direction_name == "+") { | ||
| 406 | trigger_if_greater = true; | ||
| 407 | } else if (direction_name == "-") { | ||
| 408 | trigger_if_greater = false; | ||
| 409 | } else { | ||
| 410 | trigger_if_greater = true; | ||
| 411 | LOG_ERROR(Input, "Unknown direction {}", direction_name); | ||
| 412 | } | ||
| 413 | // This is necessary so accessing GetAxis with axis won't crash | ||
| 414 | joystick->SetAxis(axis, 0); | ||
| 415 | return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater); | ||
| 416 | } | ||
| 417 | |||
| 418 | const int button = params.Get("button", 0); | ||
| 419 | // This is necessary so accessing GetButton with button won't crash | ||
| 420 | joystick->SetButton(button, false); | ||
| 421 | return std::make_unique<SDLButton>(joystick, button); | ||
| 422 | } | ||
| 423 | |||
| 424 | private: | ||
| 425 | SDLState& state; | ||
| 426 | }; | ||
| 427 | |||
| 428 | /// An analog device factory that creates analog devices from SDL joystick | ||
| 429 | class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> { | ||
| 430 | public: | ||
| 431 | explicit SDLAnalogFactory(SDLState& state_) : state(state_) {} | ||
| 432 | /** | ||
| 433 | * Creates analog device from joystick axes | ||
| 434 | * @param params contains parameters for creating the device: | ||
| 435 | * - "guid": the guid of the joystick to bind | ||
| 436 | * - "port": the nth joystick of the same type | ||
| 437 | * - "axis_x": the index of the axis to be bind as x-axis | ||
| 438 | * - "axis_y": the index of the axis to be bind as y-axis | ||
| 439 | */ | ||
| 440 | std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override { | ||
| 441 | const std::string guid = params.Get("guid", "0"); | ||
| 442 | const int port = params.Get("port", 0); | ||
| 443 | const int axis_x = params.Get("axis_x", 0); | ||
| 444 | const int axis_y = params.Get("axis_y", 1); | ||
| 445 | float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); | ||
| 446 | |||
| 447 | auto joystick = state.GetSDLJoystickByGUID(guid, port); | ||
| 448 | |||
| 449 | // This is necessary so accessing GetAxis with axis_x and axis_y won't crash | ||
| 450 | joystick->SetAxis(axis_x, 0); | ||
| 451 | joystick->SetAxis(axis_y, 0); | ||
| 452 | return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone); | ||
| 453 | } | ||
| 454 | |||
| 455 | private: | ||
| 456 | SDLState& state; | ||
| 457 | }; | ||
| 458 | |||
| 459 | SDLState::SDLState() { | ||
| 460 | using namespace Input; | ||
| 461 | RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>(*this)); | ||
| 462 | RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>(*this)); | ||
| 463 | |||
| 464 | // If the frontend is going to manage the event loop, then we dont start one here | ||
| 465 | start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK); | ||
| 466 | if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { | ||
| 467 | LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); | ||
| 468 | return; | ||
| 469 | } | ||
| 470 | if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) { | ||
| 471 | LOG_ERROR(Input, "Failed to set Hint for background events", SDL_GetError()); | ||
| 472 | } | ||
| 473 | |||
| 474 | SDL_AddEventWatch(&SDLEventWatcher, this); | ||
| 475 | |||
| 476 | initialized = true; | ||
| 477 | if (start_thread) { | ||
| 478 | poll_thread = std::thread([&] { | ||
| 479 | using namespace std::chrono_literals; | ||
| 480 | SDL_Event event; | ||
| 481 | while (initialized) { | ||
| 482 | SDL_PumpEvents(); | ||
| 483 | std::this_thread::sleep_for(std::chrono::duration(10ms)); | ||
| 484 | } | ||
| 485 | }); | ||
| 486 | } | ||
| 487 | // Because the events for joystick connection happens before we have our event watcher added, we | ||
| 488 | // can just open all the joysticks right here | ||
| 489 | for (int i = 0; i < SDL_NumJoysticks(); ++i) { | ||
| 490 | InitJoystick(i); | ||
| 491 | } | ||
| 492 | } | ||
| 493 | |||
| 494 | SDLState::~SDLState() { | ||
| 495 | using namespace Input; | ||
| 496 | UnregisterFactory<ButtonDevice>("sdl"); | ||
| 497 | UnregisterFactory<AnalogDevice>("sdl"); | ||
| 498 | |||
| 499 | CloseJoysticks(); | ||
| 500 | SDL_DelEventWatch(&SDLEventWatcher, this); | ||
| 501 | |||
| 502 | initialized = false; | ||
| 503 | if (start_thread) { | ||
| 504 | poll_thread.join(); | ||
| 505 | SDL_QuitSubSystem(SDL_INIT_JOYSTICK); | ||
| 506 | } | ||
| 507 | } | ||
| 508 | |||
| 509 | Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { | ||
| 510 | Common::ParamPackage params({{"engine", "sdl"}}); | ||
| 511 | |||
| 512 | switch (event.type) { | ||
| 513 | case SDL_JOYAXISMOTION: { | ||
| 514 | auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); | ||
| 515 | params.Set("port", joystick->GetPort()); | ||
| 516 | params.Set("guid", joystick->GetGUID()); | ||
| 517 | params.Set("axis", event.jaxis.axis); | ||
| 518 | if (event.jaxis.value > 0) { | ||
| 519 | params.Set("direction", "+"); | ||
| 520 | params.Set("threshold", "0.5"); | ||
| 521 | } else { | ||
| 522 | params.Set("direction", "-"); | ||
| 523 | params.Set("threshold", "-0.5"); | ||
| 524 | } | ||
| 525 | break; | ||
| 526 | } | ||
| 527 | case SDL_JOYBUTTONUP: { | ||
| 528 | auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); | ||
| 529 | params.Set("port", joystick->GetPort()); | ||
| 530 | params.Set("guid", joystick->GetGUID()); | ||
| 531 | params.Set("button", event.jbutton.button); | ||
| 532 | break; | ||
| 533 | } | ||
| 534 | case SDL_JOYHATMOTION: { | ||
| 535 | auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); | ||
| 536 | params.Set("port", joystick->GetPort()); | ||
| 537 | params.Set("guid", joystick->GetGUID()); | ||
| 538 | params.Set("hat", event.jhat.hat); | ||
| 539 | switch (event.jhat.value) { | ||
| 540 | case SDL_HAT_UP: | ||
| 541 | params.Set("direction", "up"); | ||
| 542 | break; | ||
| 543 | case SDL_HAT_DOWN: | ||
| 544 | params.Set("direction", "down"); | ||
| 545 | break; | ||
| 546 | case SDL_HAT_LEFT: | ||
| 547 | params.Set("direction", "left"); | ||
| 548 | break; | ||
| 549 | case SDL_HAT_RIGHT: | ||
| 550 | params.Set("direction", "right"); | ||
| 551 | break; | ||
| 552 | default: | ||
| 553 | return {}; | ||
| 554 | } | ||
| 555 | break; | ||
| 556 | } | ||
| 557 | } | ||
| 558 | return params; | ||
| 559 | } | ||
| 560 | |||
| 561 | namespace Polling { | ||
| 562 | |||
| 563 | class SDLPoller : public InputCommon::Polling::DevicePoller { | ||
| 564 | public: | ||
| 565 | explicit SDLPoller(SDLState& state_) : state(state_) {} | ||
| 566 | |||
| 567 | void Start() override { | ||
| 568 | state.event_queue.Clear(); | ||
| 569 | state.polling = true; | ||
| 570 | } | ||
| 571 | |||
| 572 | void Stop() override { | ||
| 573 | state.polling = false; | ||
| 574 | } | ||
| 575 | |||
| 576 | protected: | ||
| 577 | SDLState& state; | ||
| 578 | }; | ||
| 579 | |||
| 580 | class SDLButtonPoller final : public SDLPoller { | ||
| 581 | public: | ||
| 582 | explicit SDLButtonPoller(SDLState& state_) : SDLPoller(state_) {} | ||
| 583 | |||
| 584 | Common::ParamPackage GetNextInput() override { | ||
| 585 | SDL_Event event; | ||
| 586 | while (state.event_queue.Pop(event)) { | ||
| 587 | switch (event.type) { | ||
| 588 | case SDL_JOYAXISMOTION: | ||
| 589 | if (std::abs(event.jaxis.value / 32767.0) < 0.5) { | ||
| 590 | break; | ||
| 591 | } | ||
| 592 | case SDL_JOYBUTTONUP: | ||
| 593 | case SDL_JOYHATMOTION: | ||
| 594 | return SDLEventToButtonParamPackage(state, event); | ||
| 595 | } | ||
| 596 | } | ||
| 597 | return {}; | ||
| 598 | } | ||
| 599 | }; | ||
| 600 | |||
| 601 | class SDLAnalogPoller final : public SDLPoller { | ||
| 602 | public: | ||
| 603 | explicit SDLAnalogPoller(SDLState& state_) : SDLPoller(state_) {} | ||
| 604 | |||
| 605 | void Start() override { | ||
| 606 | SDLPoller::Start(); | ||
| 607 | |||
| 608 | // Reset stored axes | ||
| 609 | analog_xaxis = -1; | ||
| 610 | analog_yaxis = -1; | ||
| 611 | analog_axes_joystick = -1; | ||
| 612 | } | ||
| 613 | |||
| 614 | Common::ParamPackage GetNextInput() override { | ||
| 615 | SDL_Event event; | ||
| 616 | while (state.event_queue.Pop(event)) { | ||
| 617 | if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { | ||
| 618 | continue; | ||
| 619 | } | ||
| 620 | // An analog device needs two axes, so we need to store the axis for later and wait for | ||
| 621 | // a second SDL event. The axes also must be from the same joystick. | ||
| 622 | int axis = event.jaxis.axis; | ||
| 623 | if (analog_xaxis == -1) { | ||
| 624 | analog_xaxis = axis; | ||
| 625 | analog_axes_joystick = event.jaxis.which; | ||
| 626 | } else if (analog_yaxis == -1 && analog_xaxis != axis && | ||
| 627 | analog_axes_joystick == event.jaxis.which) { | ||
| 628 | analog_yaxis = axis; | ||
| 629 | } | ||
| 630 | } | ||
| 631 | Common::ParamPackage params; | ||
| 632 | if (analog_xaxis != -1 && analog_yaxis != -1) { | ||
| 633 | auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); | ||
| 634 | params.Set("engine", "sdl"); | ||
| 635 | params.Set("port", joystick->GetPort()); | ||
| 636 | params.Set("guid", joystick->GetGUID()); | ||
| 637 | params.Set("axis_x", analog_xaxis); | ||
| 638 | params.Set("axis_y", analog_yaxis); | ||
| 639 | analog_xaxis = -1; | ||
| 640 | analog_yaxis = -1; | ||
| 641 | analog_axes_joystick = -1; | ||
| 642 | return params; | ||
| 643 | } | ||
| 644 | return params; | ||
| 645 | } | ||
| 646 | |||
| 647 | private: | ||
| 648 | int analog_xaxis = -1; | ||
| 649 | int analog_yaxis = -1; | ||
| 650 | SDL_JoystickID analog_axes_joystick = -1; | ||
| 651 | }; | ||
| 652 | } // namespace Polling | ||
| 653 | |||
| 654 | std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> SDLState::GetPollers( | ||
| 655 | InputCommon::Polling::DeviceType type) { | ||
| 656 | std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> pollers; | ||
| 657 | switch (type) { | ||
| 658 | case InputCommon::Polling::DeviceType::Analog: | ||
| 659 | pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this)); | ||
| 660 | break; | ||
| 661 | case InputCommon::Polling::DeviceType::Button: | ||
| 662 | pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this)); | ||
| 663 | break; | ||
| 664 | return pollers; | ||
| 665 | } | ||
| 666 | } | ||
| 667 | |||
| 668 | } // namespace SDL | ||
| 669 | } // namespace InputCommon | ||
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h new file mode 100644 index 000000000..fec82fbe6 --- /dev/null +++ b/src/input_common/sdl/sdl_impl.h | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | // Copyright 2018 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <atomic> | ||
| 8 | #include <memory> | ||
| 9 | #include <thread> | ||
| 10 | #include "common/threadsafe_queue.h" | ||
| 11 | #include "input_common/sdl/sdl.h" | ||
| 12 | |||
| 13 | union SDL_Event; | ||
| 14 | using SDL_Joystick = struct _SDL_Joystick; | ||
| 15 | using SDL_JoystickID = s32; | ||
| 16 | |||
| 17 | namespace InputCommon::SDL { | ||
| 18 | |||
| 19 | class SDLJoystick; | ||
| 20 | class SDLButtonFactory; | ||
| 21 | class SDLAnalogFactory; | ||
| 22 | |||
| 23 | class SDLState : public State { | ||
| 24 | public: | ||
| 25 | /// Initializes and registers SDL device factories | ||
| 26 | SDLState(); | ||
| 27 | |||
| 28 | /// Unresisters SDL device factories and shut them down. | ||
| 29 | ~SDLState() override; | ||
| 30 | |||
| 31 | /// Handle SDL_Events for joysticks from SDL_PollEvent | ||
| 32 | void HandleGameControllerEvent(const SDL_Event& event); | ||
| 33 | |||
| 34 | std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id); | ||
| 35 | std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port); | ||
| 36 | |||
| 37 | /// Get all DevicePoller that use the SDL backend for a specific device type | ||
| 38 | std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers( | ||
| 39 | InputCommon::Polling::DeviceType type) override; | ||
| 40 | |||
| 41 | /// Used by the Pollers during config | ||
| 42 | std::atomic<bool> polling = false; | ||
| 43 | Common::SPSCQueue<SDL_Event> event_queue; | ||
| 44 | |||
| 45 | private: | ||
| 46 | void InitJoystick(int joystick_index); | ||
| 47 | void CloseJoystick(SDL_Joystick* sdl_joystick); | ||
| 48 | |||
| 49 | /// Needs to be called before SDL_QuitSubSystem. | ||
| 50 | void CloseJoysticks(); | ||
| 51 | |||
| 52 | /// Map of GUID of a list of corresponding virtual Joysticks | ||
| 53 | std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map; | ||
| 54 | std::mutex joystick_map_mutex; | ||
| 55 | |||
| 56 | std::shared_ptr<SDLButtonFactory> button_factory; | ||
| 57 | std::shared_ptr<SDLAnalogFactory> analog_factory; | ||
| 58 | |||
| 59 | bool start_thread = false; | ||
| 60 | std::atomic<bool> initialized = false; | ||
| 61 | |||
| 62 | std::thread poll_thread; | ||
| 63 | }; | ||
| 64 | } // namespace InputCommon::SDL | ||
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp index ea27ef90d..6fe56833d 100644 --- a/src/tests/core/arm/arm_test_common.cpp +++ b/src/tests/core/arm/arm_test_common.cpp | |||
| @@ -15,7 +15,7 @@ namespace ArmTests { | |||
| 15 | TestEnvironment::TestEnvironment(bool mutable_memory_) | 15 | TestEnvironment::TestEnvironment(bool mutable_memory_) |
| 16 | : mutable_memory(mutable_memory_), | 16 | : mutable_memory(mutable_memory_), |
| 17 | test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} { | 17 | test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} { |
| 18 | auto process = Kernel::Process::Create(kernel, ""); | 18 | auto process = Kernel::Process::Create(Core::System::GetInstance(), ""); |
| 19 | kernel.MakeCurrentProcess(process.get()); | 19 | kernel.MakeCurrentProcess(process.get()); |
| 20 | page_table = &process->VMManager().page_table; | 20 | page_table = &process->VMManager().page_table; |
| 21 | 21 | ||
diff --git a/src/video_core/renderer_opengl/gl_global_cache.cpp b/src/video_core/renderer_opengl/gl_global_cache.cpp index c7f32feaa..7161d1dea 100644 --- a/src/video_core/renderer_opengl/gl_global_cache.cpp +++ b/src/video_core/renderer_opengl/gl_global_cache.cpp | |||
| @@ -57,8 +57,8 @@ GlobalRegion GlobalRegionCacheOpenGL::GetUncachedGlobalRegion(VAddr addr, u32 si | |||
| 57 | return region; | 57 | return region; |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | void GlobalRegionCacheOpenGL::ReserveGlobalRegion(const GlobalRegion& region) { | 60 | void GlobalRegionCacheOpenGL::ReserveGlobalRegion(GlobalRegion region) { |
| 61 | reserve[region->GetAddr()] = region; | 61 | reserve.insert_or_assign(region->GetAddr(), std::move(region)); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | GlobalRegionCacheOpenGL::GlobalRegionCacheOpenGL(RasterizerOpenGL& rasterizer) | 64 | GlobalRegionCacheOpenGL::GlobalRegionCacheOpenGL(RasterizerOpenGL& rasterizer) |
diff --git a/src/video_core/renderer_opengl/gl_global_cache.h b/src/video_core/renderer_opengl/gl_global_cache.h index 37830bb7c..ba2bdc60c 100644 --- a/src/video_core/renderer_opengl/gl_global_cache.h +++ b/src/video_core/renderer_opengl/gl_global_cache.h | |||
| @@ -30,12 +30,12 @@ public: | |||
| 30 | explicit CachedGlobalRegion(VAddr addr, u32 size); | 30 | explicit CachedGlobalRegion(VAddr addr, u32 size); |
| 31 | 31 | ||
| 32 | /// Gets the address of the shader in guest memory, required for cache management | 32 | /// Gets the address of the shader in guest memory, required for cache management |
| 33 | VAddr GetAddr() const { | 33 | VAddr GetAddr() const override { |
| 34 | return addr; | 34 | return addr; |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | /// Gets the size of the shader in guest memory, required for cache management | 37 | /// Gets the size of the shader in guest memory, required for cache management |
| 38 | std::size_t GetSizeInBytes() const { | 38 | std::size_t GetSizeInBytes() const override { |
| 39 | return size; | 39 | return size; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| @@ -70,7 +70,7 @@ public: | |||
| 70 | private: | 70 | private: |
| 71 | GlobalRegion TryGetReservedGlobalRegion(VAddr addr, u32 size) const; | 71 | GlobalRegion TryGetReservedGlobalRegion(VAddr addr, u32 size) const; |
| 72 | GlobalRegion GetUncachedGlobalRegion(VAddr addr, u32 size); | 72 | GlobalRegion GetUncachedGlobalRegion(VAddr addr, u32 size); |
| 73 | void ReserveGlobalRegion(const GlobalRegion& region); | 73 | void ReserveGlobalRegion(GlobalRegion region); |
| 74 | 74 | ||
| 75 | std::unordered_map<VAddr, GlobalRegion> reserve; | 75 | std::unordered_map<VAddr, GlobalRegion> reserve; |
| 76 | }; | 76 | }; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 824863561..976f64c24 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -102,8 +102,9 @@ struct FramebufferCacheKey { | |||
| 102 | 102 | ||
| 103 | RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, Core::System& system, | 103 | RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, Core::System& system, |
| 104 | ScreenInfo& info) | 104 | ScreenInfo& info) |
| 105 | : res_cache{*this}, shader_cache{*this, system}, global_cache{*this}, emu_window{window}, | 105 | : res_cache{*this}, shader_cache{*this, system}, global_cache{*this}, |
| 106 | screen_info{info}, buffer_cache(*this, STREAM_BUFFER_SIZE) { | 106 | emu_window{window}, system{system}, screen_info{info}, |
| 107 | buffer_cache(*this, STREAM_BUFFER_SIZE) { | ||
| 107 | // Create sampler objects | 108 | // Create sampler objects |
| 108 | for (std::size_t i = 0; i < texture_samplers.size(); ++i) { | 109 | for (std::size_t i = 0; i < texture_samplers.size(); ++i) { |
| 109 | texture_samplers[i].Create(); | 110 | texture_samplers[i].Create(); |
| @@ -138,7 +139,7 @@ void RasterizerOpenGL::CheckExtensions() { | |||
| 138 | } | 139 | } |
| 139 | 140 | ||
| 140 | GLuint RasterizerOpenGL::SetupVertexFormat() { | 141 | GLuint RasterizerOpenGL::SetupVertexFormat() { |
| 141 | auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | 142 | auto& gpu = system.GPU().Maxwell3D(); |
| 142 | const auto& regs = gpu.regs; | 143 | const auto& regs = gpu.regs; |
| 143 | 144 | ||
| 144 | if (!gpu.dirty_flags.vertex_attrib_format) { | 145 | if (!gpu.dirty_flags.vertex_attrib_format) { |
| @@ -207,7 +208,7 @@ GLuint RasterizerOpenGL::SetupVertexFormat() { | |||
| 207 | } | 208 | } |
| 208 | 209 | ||
| 209 | void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) { | 210 | void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) { |
| 210 | auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | 211 | auto& gpu = system.GPU().Maxwell3D(); |
| 211 | const auto& regs = gpu.regs; | 212 | const auto& regs = gpu.regs; |
| 212 | 213 | ||
| 213 | if (gpu.dirty_flags.vertex_array.none()) | 214 | if (gpu.dirty_flags.vertex_array.none()) |
| @@ -248,7 +249,7 @@ void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) { | |||
| 248 | } | 249 | } |
| 249 | 250 | ||
| 250 | DrawParameters RasterizerOpenGL::SetupDraw() { | 251 | DrawParameters RasterizerOpenGL::SetupDraw() { |
| 251 | const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | 252 | const auto& gpu = system.GPU().Maxwell3D(); |
| 252 | const auto& regs = gpu.regs; | 253 | const auto& regs = gpu.regs; |
| 253 | const bool is_indexed = accelerate_draw == AccelDraw::Indexed; | 254 | const bool is_indexed = accelerate_draw == AccelDraw::Indexed; |
| 254 | 255 | ||
| @@ -297,7 +298,7 @@ DrawParameters RasterizerOpenGL::SetupDraw() { | |||
| 297 | 298 | ||
| 298 | void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { | 299 | void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { |
| 299 | MICROPROFILE_SCOPE(OpenGL_Shader); | 300 | MICROPROFILE_SCOPE(OpenGL_Shader); |
| 300 | auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | 301 | auto& gpu = system.GPU().Maxwell3D(); |
| 301 | 302 | ||
| 302 | BaseBindings base_bindings; | 303 | BaseBindings base_bindings; |
| 303 | std::array<bool, Maxwell::NumClipDistances> clip_distances{}; | 304 | std::array<bool, Maxwell::NumClipDistances> clip_distances{}; |
| @@ -413,7 +414,7 @@ void RasterizerOpenGL::SetupCachedFramebuffer(const FramebufferCacheKey& fbkey, | |||
| 413 | } | 414 | } |
| 414 | 415 | ||
| 415 | std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { | 416 | std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { |
| 416 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 417 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 417 | 418 | ||
| 418 | std::size_t size = 0; | 419 | std::size_t size = 0; |
| 419 | for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { | 420 | for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { |
| @@ -431,7 +432,7 @@ std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { | |||
| 431 | } | 432 | } |
| 432 | 433 | ||
| 433 | std::size_t RasterizerOpenGL::CalculateIndexBufferSize() const { | 434 | std::size_t RasterizerOpenGL::CalculateIndexBufferSize() const { |
| 434 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 435 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 435 | 436 | ||
| 436 | return static_cast<std::size_t>(regs.index_array.count) * | 437 | return static_cast<std::size_t>(regs.index_array.count) * |
| 437 | static_cast<std::size_t>(regs.index_array.FormatSizeInBytes()); | 438 | static_cast<std::size_t>(regs.index_array.FormatSizeInBytes()); |
| @@ -487,7 +488,7 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( | |||
| 487 | OpenGLState& current_state, bool using_color_fb, bool using_depth_fb, bool preserve_contents, | 488 | OpenGLState& current_state, bool using_color_fb, bool using_depth_fb, bool preserve_contents, |
| 488 | std::optional<std::size_t> single_color_target) { | 489 | std::optional<std::size_t> single_color_target) { |
| 489 | MICROPROFILE_SCOPE(OpenGL_Framebuffer); | 490 | MICROPROFILE_SCOPE(OpenGL_Framebuffer); |
| 490 | auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | 491 | auto& gpu = system.GPU().Maxwell3D(); |
| 491 | const auto& regs = gpu.regs; | 492 | const auto& regs = gpu.regs; |
| 492 | 493 | ||
| 493 | const FramebufferConfigState fb_config_state{using_color_fb, using_depth_fb, preserve_contents, | 494 | const FramebufferConfigState fb_config_state{using_color_fb, using_depth_fb, preserve_contents, |
| @@ -581,7 +582,7 @@ void RasterizerOpenGL::Clear() { | |||
| 581 | const auto prev_state{state}; | 582 | const auto prev_state{state}; |
| 582 | SCOPE_EXIT({ prev_state.Apply(); }); | 583 | SCOPE_EXIT({ prev_state.Apply(); }); |
| 583 | 584 | ||
| 584 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 585 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 585 | bool use_color{}; | 586 | bool use_color{}; |
| 586 | bool use_depth{}; | 587 | bool use_depth{}; |
| 587 | bool use_stencil{}; | 588 | bool use_stencil{}; |
| @@ -672,7 +673,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 672 | return; | 673 | return; |
| 673 | 674 | ||
| 674 | MICROPROFILE_SCOPE(OpenGL_Drawing); | 675 | MICROPROFILE_SCOPE(OpenGL_Drawing); |
| 675 | auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | 676 | auto& gpu = system.GPU().Maxwell3D(); |
| 676 | const auto& regs = gpu.regs; | 677 | const auto& regs = gpu.regs; |
| 677 | 678 | ||
| 678 | ConfigureFramebuffers(state); | 679 | ConfigureFramebuffers(state); |
| @@ -892,7 +893,7 @@ void RasterizerOpenGL::SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::Shader | |||
| 892 | const Shader& shader, GLuint program_handle, | 893 | const Shader& shader, GLuint program_handle, |
| 893 | BaseBindings base_bindings) { | 894 | BaseBindings base_bindings) { |
| 894 | MICROPROFILE_SCOPE(OpenGL_UBO); | 895 | MICROPROFILE_SCOPE(OpenGL_UBO); |
| 895 | const auto& gpu = Core::System::GetInstance().GPU(); | 896 | const auto& gpu = system.GPU(); |
| 896 | const auto& maxwell3d = gpu.Maxwell3D(); | 897 | const auto& maxwell3d = gpu.Maxwell3D(); |
| 897 | const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<std::size_t>(stage)]; | 898 | const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<std::size_t>(stage)]; |
| 898 | const auto& entries = shader->GetShaderEntries().const_buffers; | 899 | const auto& entries = shader->GetShaderEntries().const_buffers; |
| @@ -971,7 +972,7 @@ void RasterizerOpenGL::SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::Shade | |||
| 971 | void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader, | 972 | void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader, |
| 972 | GLuint program_handle, BaseBindings base_bindings) { | 973 | GLuint program_handle, BaseBindings base_bindings) { |
| 973 | MICROPROFILE_SCOPE(OpenGL_Texture); | 974 | MICROPROFILE_SCOPE(OpenGL_Texture); |
| 974 | const auto& gpu = Core::System::GetInstance().GPU(); | 975 | const auto& gpu = system.GPU(); |
| 975 | const auto& maxwell3d = gpu.Maxwell3D(); | 976 | const auto& maxwell3d = gpu.Maxwell3D(); |
| 976 | const auto& entries = shader->GetShaderEntries().samplers; | 977 | const auto& entries = shader->GetShaderEntries().samplers; |
| 977 | 978 | ||
| @@ -998,7 +999,7 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s | |||
| 998 | } | 999 | } |
| 999 | 1000 | ||
| 1000 | void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { | 1001 | void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { |
| 1001 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1002 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1002 | const bool geometry_shaders_enabled = | 1003 | const bool geometry_shaders_enabled = |
| 1003 | regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry)); | 1004 | regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry)); |
| 1004 | const std::size_t viewport_count = | 1005 | const std::size_t viewport_count = |
| @@ -1021,7 +1022,7 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { | |||
| 1021 | void RasterizerOpenGL::SyncClipEnabled( | 1022 | void RasterizerOpenGL::SyncClipEnabled( |
| 1022 | const std::array<bool, Maxwell::Regs::NumClipDistances>& clip_mask) { | 1023 | const std::array<bool, Maxwell::Regs::NumClipDistances>& clip_mask) { |
| 1023 | 1024 | ||
| 1024 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1025 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1025 | const std::array<bool, Maxwell::Regs::NumClipDistances> reg_state{ | 1026 | const std::array<bool, Maxwell::Regs::NumClipDistances> reg_state{ |
| 1026 | regs.clip_distance_enabled.c0 != 0, regs.clip_distance_enabled.c1 != 0, | 1027 | regs.clip_distance_enabled.c0 != 0, regs.clip_distance_enabled.c1 != 0, |
| 1027 | regs.clip_distance_enabled.c2 != 0, regs.clip_distance_enabled.c3 != 0, | 1028 | regs.clip_distance_enabled.c2 != 0, regs.clip_distance_enabled.c3 != 0, |
| @@ -1038,7 +1039,7 @@ void RasterizerOpenGL::SyncClipCoef() { | |||
| 1038 | } | 1039 | } |
| 1039 | 1040 | ||
| 1040 | void RasterizerOpenGL::SyncCullMode() { | 1041 | void RasterizerOpenGL::SyncCullMode() { |
| 1041 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1042 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1042 | 1043 | ||
| 1043 | state.cull.enabled = regs.cull.enabled != 0; | 1044 | state.cull.enabled = regs.cull.enabled != 0; |
| 1044 | 1045 | ||
| @@ -1062,14 +1063,14 @@ void RasterizerOpenGL::SyncCullMode() { | |||
| 1062 | } | 1063 | } |
| 1063 | 1064 | ||
| 1064 | void RasterizerOpenGL::SyncPrimitiveRestart() { | 1065 | void RasterizerOpenGL::SyncPrimitiveRestart() { |
| 1065 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1066 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1066 | 1067 | ||
| 1067 | state.primitive_restart.enabled = regs.primitive_restart.enabled; | 1068 | state.primitive_restart.enabled = regs.primitive_restart.enabled; |
| 1068 | state.primitive_restart.index = regs.primitive_restart.index; | 1069 | state.primitive_restart.index = regs.primitive_restart.index; |
| 1069 | } | 1070 | } |
| 1070 | 1071 | ||
| 1071 | void RasterizerOpenGL::SyncDepthTestState() { | 1072 | void RasterizerOpenGL::SyncDepthTestState() { |
| 1072 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1073 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1073 | 1074 | ||
| 1074 | state.depth.test_enabled = regs.depth_test_enable != 0; | 1075 | state.depth.test_enabled = regs.depth_test_enable != 0; |
| 1075 | state.depth.write_mask = regs.depth_write_enabled ? GL_TRUE : GL_FALSE; | 1076 | state.depth.write_mask = regs.depth_write_enabled ? GL_TRUE : GL_FALSE; |
| @@ -1081,7 +1082,7 @@ void RasterizerOpenGL::SyncDepthTestState() { | |||
| 1081 | } | 1082 | } |
| 1082 | 1083 | ||
| 1083 | void RasterizerOpenGL::SyncStencilTestState() { | 1084 | void RasterizerOpenGL::SyncStencilTestState() { |
| 1084 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1085 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1085 | state.stencil.test_enabled = regs.stencil_enable != 0; | 1086 | state.stencil.test_enabled = regs.stencil_enable != 0; |
| 1086 | 1087 | ||
| 1087 | if (!regs.stencil_enable) { | 1088 | if (!regs.stencil_enable) { |
| @@ -1115,7 +1116,7 @@ void RasterizerOpenGL::SyncStencilTestState() { | |||
| 1115 | } | 1116 | } |
| 1116 | 1117 | ||
| 1117 | void RasterizerOpenGL::SyncColorMask() { | 1118 | void RasterizerOpenGL::SyncColorMask() { |
| 1118 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1119 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1119 | const std::size_t count = | 1120 | const std::size_t count = |
| 1120 | regs.independent_blend_enable ? Tegra::Engines::Maxwell3D::Regs::NumRenderTargets : 1; | 1121 | regs.independent_blend_enable ? Tegra::Engines::Maxwell3D::Regs::NumRenderTargets : 1; |
| 1121 | for (std::size_t i = 0; i < count; i++) { | 1122 | for (std::size_t i = 0; i < count; i++) { |
| @@ -1129,18 +1130,18 @@ void RasterizerOpenGL::SyncColorMask() { | |||
| 1129 | } | 1130 | } |
| 1130 | 1131 | ||
| 1131 | void RasterizerOpenGL::SyncMultiSampleState() { | 1132 | void RasterizerOpenGL::SyncMultiSampleState() { |
| 1132 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1133 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1133 | state.multisample_control.alpha_to_coverage = regs.multisample_control.alpha_to_coverage != 0; | 1134 | state.multisample_control.alpha_to_coverage = regs.multisample_control.alpha_to_coverage != 0; |
| 1134 | state.multisample_control.alpha_to_one = regs.multisample_control.alpha_to_one != 0; | 1135 | state.multisample_control.alpha_to_one = regs.multisample_control.alpha_to_one != 0; |
| 1135 | } | 1136 | } |
| 1136 | 1137 | ||
| 1137 | void RasterizerOpenGL::SyncFragmentColorClampState() { | 1138 | void RasterizerOpenGL::SyncFragmentColorClampState() { |
| 1138 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1139 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1139 | state.fragment_color_clamp.enabled = regs.frag_color_clamp != 0; | 1140 | state.fragment_color_clamp.enabled = regs.frag_color_clamp != 0; |
| 1140 | } | 1141 | } |
| 1141 | 1142 | ||
| 1142 | void RasterizerOpenGL::SyncBlendState() { | 1143 | void RasterizerOpenGL::SyncBlendState() { |
| 1143 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1144 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1144 | 1145 | ||
| 1145 | state.blend_color.red = regs.blend_color.r; | 1146 | state.blend_color.red = regs.blend_color.r; |
| 1146 | state.blend_color.green = regs.blend_color.g; | 1147 | state.blend_color.green = regs.blend_color.g; |
| @@ -1182,7 +1183,7 @@ void RasterizerOpenGL::SyncBlendState() { | |||
| 1182 | } | 1183 | } |
| 1183 | 1184 | ||
| 1184 | void RasterizerOpenGL::SyncLogicOpState() { | 1185 | void RasterizerOpenGL::SyncLogicOpState() { |
| 1185 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1186 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1186 | 1187 | ||
| 1187 | state.logic_op.enabled = regs.logic_op.enable != 0; | 1188 | state.logic_op.enabled = regs.logic_op.enable != 0; |
| 1188 | 1189 | ||
| @@ -1196,7 +1197,7 @@ void RasterizerOpenGL::SyncLogicOpState() { | |||
| 1196 | } | 1197 | } |
| 1197 | 1198 | ||
| 1198 | void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) { | 1199 | void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) { |
| 1199 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1200 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1200 | const bool geometry_shaders_enabled = | 1201 | const bool geometry_shaders_enabled = |
| 1201 | regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry)); | 1202 | regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry)); |
| 1202 | const std::size_t viewport_count = | 1203 | const std::size_t viewport_count = |
| @@ -1218,17 +1219,17 @@ void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) { | |||
| 1218 | } | 1219 | } |
| 1219 | 1220 | ||
| 1220 | void RasterizerOpenGL::SyncTransformFeedback() { | 1221 | void RasterizerOpenGL::SyncTransformFeedback() { |
| 1221 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1222 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1222 | UNIMPLEMENTED_IF_MSG(regs.tfb_enabled != 0, "Transform feedbacks are not implemented"); | 1223 | UNIMPLEMENTED_IF_MSG(regs.tfb_enabled != 0, "Transform feedbacks are not implemented"); |
| 1223 | } | 1224 | } |
| 1224 | 1225 | ||
| 1225 | void RasterizerOpenGL::SyncPointState() { | 1226 | void RasterizerOpenGL::SyncPointState() { |
| 1226 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1227 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1227 | state.point.size = regs.point_size; | 1228 | state.point.size = regs.point_size; |
| 1228 | } | 1229 | } |
| 1229 | 1230 | ||
| 1230 | void RasterizerOpenGL::SyncPolygonOffset() { | 1231 | void RasterizerOpenGL::SyncPolygonOffset() { |
| 1231 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1232 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1232 | state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0; | 1233 | state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0; |
| 1233 | state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0; | 1234 | state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0; |
| 1234 | state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0; | 1235 | state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0; |
| @@ -1238,7 +1239,7 @@ void RasterizerOpenGL::SyncPolygonOffset() { | |||
| 1238 | } | 1239 | } |
| 1239 | 1240 | ||
| 1240 | void RasterizerOpenGL::CheckAlphaTests() { | 1241 | void RasterizerOpenGL::CheckAlphaTests() { |
| 1241 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1242 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1242 | UNIMPLEMENTED_IF_MSG(regs.alpha_test_enabled != 0 && regs.rt_control.count > 1, | 1243 | UNIMPLEMENTED_IF_MSG(regs.alpha_test_enabled != 0 && regs.rt_control.count > 1, |
| 1243 | "Alpha Testing is enabled with more than one rendertarget"); | 1244 | "Alpha Testing is enabled with more than one rendertarget"); |
| 1244 | } | 1245 | } |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 7e63f8008..ca3de0592 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -215,6 +215,7 @@ private: | |||
| 215 | GlobalRegionCacheOpenGL global_cache; | 215 | GlobalRegionCacheOpenGL global_cache; |
| 216 | 216 | ||
| 217 | Core::Frontend::EmuWindow& emu_window; | 217 | Core::Frontend::EmuWindow& emu_window; |
| 218 | Core::System& system; | ||
| 218 | 219 | ||
| 219 | ScreenInfo& screen_info; | 220 | ScreenInfo& screen_info; |
| 220 | 221 | ||
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index ff1165053..93ecc6e31 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h | |||
| @@ -329,7 +329,7 @@ struct TSCEntry { | |||
| 329 | float GetLodBias() const { | 329 | float GetLodBias() const { |
| 330 | // Sign extend the 13-bit value. | 330 | // Sign extend the 13-bit value. |
| 331 | constexpr u32 mask = 1U << (13 - 1); | 331 | constexpr u32 mask = 1U << (13 - 1); |
| 332 | return static_cast<float>((mip_lod_bias ^ mask) - mask) / 256.0f; | 332 | return static_cast<s32>((mip_lod_bias ^ mask) - mask) / 256.0f; |
| 333 | } | 333 | } |
| 334 | 334 | ||
| 335 | std::array<float, 4> GetBorderColor() const { | 335 | std::array<float, 4> GetBorderColor() const { |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 3b070bfbb..d2c97b1f8 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -123,7 +123,6 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) | |||
| 123 | setAttribute(Qt::WA_AcceptTouchEvents); | 123 | setAttribute(Qt::WA_AcceptTouchEvents); |
| 124 | 124 | ||
| 125 | InputCommon::Init(); | 125 | InputCommon::Init(); |
| 126 | InputCommon::StartJoystickEventHandler(); | ||
| 127 | connect(this, &GRenderWindow::FirstFrameDisplayed, static_cast<GMainWindow*>(parent), | 126 | connect(this, &GRenderWindow::FirstFrameDisplayed, static_cast<GMainWindow*>(parent), |
| 128 | &GMainWindow::OnLoadComplete); | 127 | &GMainWindow::OnLoadComplete); |
| 129 | } | 128 | } |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 7df8eff53..de7a26e14 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | |||
| @@ -135,16 +135,16 @@ bool EmuWindow_SDL2::SupportsRequiredGLExtensions() { | |||
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { | 137 | EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { |
| 138 | InputCommon::Init(); | ||
| 139 | |||
| 140 | SDL_SetMainReady(); | ||
| 141 | |||
| 142 | // Initialize the window | 138 | // Initialize the window |
| 143 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { | 139 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { |
| 144 | LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); | 140 | LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); |
| 145 | exit(1); | 141 | exit(1); |
| 146 | } | 142 | } |
| 147 | 143 | ||
| 144 | InputCommon::Init(); | ||
| 145 | |||
| 146 | SDL_SetMainReady(); | ||
| 147 | |||
| 148 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); | 148 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); |
| 149 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | 149 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); |
| 150 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); | 150 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); |
| @@ -201,11 +201,9 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { | |||
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | EmuWindow_SDL2::~EmuWindow_SDL2() { | 203 | EmuWindow_SDL2::~EmuWindow_SDL2() { |
| 204 | InputCommon::SDL::CloseSDLJoysticks(); | 204 | InputCommon::Shutdown(); |
| 205 | SDL_GL_DeleteContext(gl_context); | 205 | SDL_GL_DeleteContext(gl_context); |
| 206 | SDL_Quit(); | 206 | SDL_Quit(); |
| 207 | |||
| 208 | InputCommon::Shutdown(); | ||
| 209 | } | 207 | } |
| 210 | 208 | ||
| 211 | void EmuWindow_SDL2::SwapBuffers() { | 209 | void EmuWindow_SDL2::SwapBuffers() { |
| @@ -262,7 +260,6 @@ void EmuWindow_SDL2::PollEvents() { | |||
| 262 | is_open = false; | 260 | is_open = false; |
| 263 | break; | 261 | break; |
| 264 | default: | 262 | default: |
| 265 | InputCommon::SDL::HandleGameControllerEvent(event); | ||
| 266 | break; | 263 | break; |
| 267 | } | 264 | } |
| 268 | } | 265 | } |