diff options
37 files changed, 367 insertions, 247 deletions
diff --git a/.gitmodules b/.gitmodules index 93ba9b930..a0a89933d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -27,7 +27,7 @@ url = https://github.com/ReinUsesLisp/sirit [submodule "mbedtls"] path = externals/mbedtls - url = https://github.com/DarkLordZach/mbedtls + url = https://github.com/yuzu-emu/mbedtls [submodule "libzip"] path = externals/libzip/libzip url = https://github.com/nih-at/libzip.git diff --git a/externals/dynarmic b/externals/dynarmic -Subproject cafa687684a3e5dbe86be7150c0f8183d2ad53c +Subproject 646fd0592091c5c1e5899fa715bd7b7fcc977a3 diff --git a/externals/mbedtls b/externals/mbedtls -Subproject a280e602f3a4ae001d3a83cbc3e6e04c99c2227 +Subproject eac2416b8fdb2cb9c867a538100bf95326bad75 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1cfd3bbc9..8bd7e5f72 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,7 @@ if (MSVC) # /Zo - Enhanced debug info for optimized builds # /permissive- - Enables stricter C++ standards conformance checks # /EHsc - C++-only exception handling semantics + # /utf-8 - Set source and execution character sets to UTF-8 # /volatile:iso - Use strict standards-compliant volatile semantics. # /Zc:externConstexpr - Allow extern constexpr variables to have external linkage, like the standard mandates # /Zc:inline - Let codegen omit inline functions in object files @@ -38,6 +39,7 @@ if (MSVC) /permissive- /EHsc /std:c++latest + /utf-8 /volatile:iso /Zc:externConstexpr /Zc:inline diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 71b64e32a..4ace2cd33 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -52,9 +52,13 @@ __declspec(dllimport) void __stdcall DebugBreak(void); // Generic function to get last error message. // Call directly after the command or use the error num. // This function might change the error code. -// Defined in Misc.cpp. +// Defined in misc.cpp. [[nodiscard]] std::string GetLastErrorMsg(); +// Like GetLastErrorMsg(), but passing an explicit error code. +// Defined in misc.cpp. +[[nodiscard]] std::string NativeErrorToString(int e); + #define DECLARE_ENUM_FLAG_OPERATORS(type) \ [[nodiscard]] constexpr type operator|(type a, type b) noexcept { \ using T = std::underlying_type_t<type>; \ diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 3c1eefcb7..39532ff58 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp @@ -116,16 +116,19 @@ void Fiber::Rewind() { boost::context::detail::jump_fcontext(impl->rewind_context, this); } -void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { - ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); - ASSERT_MSG(to != nullptr, "Next fiber is null!"); - to->impl->guard.lock(); - to->impl->previous_fiber = from; - auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); - ASSERT(from->impl->previous_fiber != nullptr); - from->impl->previous_fiber->impl->context = transfer.fctx; - from->impl->previous_fiber->impl->guard.unlock(); - from->impl->previous_fiber.reset(); +void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) { + to.impl->guard.lock(); + to.impl->previous_fiber = weak_from.lock(); + + auto transfer = boost::context::detail::jump_fcontext(to.impl->context, &to); + + // "from" might no longer be valid if the thread was killed + if (auto from = weak_from.lock()) { + ASSERT(from->impl->previous_fiber != nullptr); + from->impl->previous_fiber->impl->context = transfer.fctx; + from->impl->previous_fiber->impl->guard.unlock(); + from->impl->previous_fiber.reset(); + } } std::shared_ptr<Fiber> Fiber::ThreadToFiber() { diff --git a/src/common/fiber.h b/src/common/fiber.h index f7f587f8c..f2a8ff29a 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h @@ -41,7 +41,7 @@ public: /// Yields control from Fiber 'from' to Fiber 'to' /// Fiber 'from' must be the currently running fiber. - static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to); + static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to); [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber(); void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param); diff --git a/src/common/misc.cpp b/src/common/misc.cpp index 1d5393597..495385b9e 100644 --- a/src/common/misc.cpp +++ b/src/common/misc.cpp @@ -12,27 +12,41 @@ #include "common/common_funcs.h" -// Generic function to get last error message. -// Call directly after the command or use the error num. -// This function might change the error code. -std::string GetLastErrorMsg() { - static constexpr std::size_t buff_size = 255; - char err_str[buff_size]; - +std::string NativeErrorToString(int e) { #ifdef _WIN32 - FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr); - return std::string(err_str, buff_size); -#elif defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)) + LPSTR err_str; + + DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast<LPSTR>(&err_str), 1, nullptr); + if (!res) { + return "(FormatMessageA failed to format error)"; + } + std::string ret(err_str); + LocalFree(err_str); + return ret; +#else + char err_str[255]; +#if defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)) // Thread safe (GNU-specific) - const char* str = strerror_r(errno, err_str, buff_size); + const char* str = strerror_r(e, err_str, sizeof(err_str)); return std::string(str); #else // Thread safe (XSI-compliant) - const int success = strerror_r(errno, err_str, buff_size); - if (success != 0) { - return {}; + int second_err = strerror_r(e, err_str, sizeof(err_str)); + if (second_err != 0) { + return "(strerror_r failed to format error)"; } return std::string(err_str); +#endif // GLIBC etc. +#endif // _WIN32 +} + +std::string GetLastErrorMsg() { +#ifdef _WIN32 + return NativeErrorToString(GetLastError()); +#else + return NativeErrorToString(errno); #endif } diff --git a/src/core/core.cpp b/src/core/core.cpp index de6305e2a..305f56ff1 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -299,28 +299,17 @@ struct System::Impl { gpu_core->WaitIdle(); } - // Shutdown emulation session services.reset(); service_manager.reset(); cheat_engine.reset(); telemetry_session.reset(); - - // Close all CPU/threading state cpu_manager.Shutdown(); - - // Release the Time Manager's resources time_manager.Shutdown(); - - // Shutdown kernel and core timing core_timing.Shutdown(); - kernel.Shutdown(); - - // Close app loader app_loader.reset(); gpu_core.reset(); perf_stats.reset(); - - // Clear all applets + kernel.Shutdown(); applet_manager.ClearAll(); LOG_DEBUG(Core, "Shutdown OK"); diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 8f04fb8f5..bdb374792 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -148,7 +148,7 @@ void CpuManager::MultiCoreRunSuspendThread() { auto core = kernel.GetCurrentHostThreadID(); auto& scheduler = *kernel.CurrentScheduler(); Kernel::KThread* current_thread = scheduler.GetCurrentThread(); - Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context); + Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); ASSERT(scheduler.ContextSwitchPending()); ASSERT(core == kernel.GetCurrentHostThreadID()); scheduler.RescheduleCurrentCore(); @@ -245,7 +245,7 @@ void CpuManager::SingleCoreRunSuspendThread() { auto core = kernel.GetCurrentHostThreadID(); auto& scheduler = *kernel.CurrentScheduler(); Kernel::KThread* current_thread = scheduler.GetCurrentThread(); - Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context); + Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context); ASSERT(scheduler.ContextSwitchPending()); ASSERT(core == kernel.GetCurrentHostThreadID()); scheduler.RescheduleCurrentCore(); @@ -271,7 +271,7 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) { scheduler.Unload(scheduler.GetCurrentThread()); auto& next_scheduler = kernel.Scheduler(current_core); - Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext()); + Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.ControlContext()); } // May have changed scheduler @@ -363,7 +363,7 @@ void CpuManager::RunThread(std::size_t core) { auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); data.is_running = true; - Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext()); + Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); data.is_running = false; data.is_paused = true; data.exit_barrier->Wait(); diff --git a/src/core/crypto/aes_util.cpp b/src/core/crypto/aes_util.cpp index 6a9734812..cb7506241 100644 --- a/src/core/crypto/aes_util.cpp +++ b/src/core/crypto/aes_util.cpp @@ -105,8 +105,6 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* des } } } - - mbedtls_cipher_finish(context, nullptr, nullptr); } template <typename Key, std::size_t KeySize> diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index bb5f43b53..e7de48476 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -734,7 +734,7 @@ void KScheduler::ScheduleImpl() { } guard.unlock(); - Common::Fiber::YieldTo(*old_context, switch_fiber); + Common::Fiber::YieldTo(*old_context, *switch_fiber); /// When a thread wakes up, the scheduler may have changed to other in another core. auto& next_scheduler = *system.Kernel().CurrentScheduler(); next_scheduler.SwitchContextStep2(); @@ -769,13 +769,8 @@ void KScheduler::SwitchToCurrent() { break; } } - std::shared_ptr<Common::Fiber>* next_context; - if (next_thread != nullptr) { - next_context = &next_thread->GetHostContext(); - } else { - next_context = &idle_thread->GetHostContext(); - } - Common::Fiber::YieldTo(switch_fiber, *next_context); + auto thread = next_thread ? next_thread : idle_thread; + Common::Fiber::YieldTo(switch_fiber, *thread->GetHostContext()); } while (!is_switch_pending()); } } @@ -800,9 +795,9 @@ void KScheduler::Initialize() { std::string name = "Idle Thread Id:" + std::to_string(core_id); std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - auto thread_res = KThread::Create(system, ThreadType::Main, name, 0, - KThread::IdleThreadPriority, 0, static_cast<u32>(core_id), 0, - nullptr, std::move(init_func), init_func_parameter); + auto thread_res = KThread::CreateThread( + system, ThreadType::Main, name, 0, KThread::IdleThreadPriority, 0, + static_cast<u32>(core_id), 0, nullptr, std::move(init_func), init_func_parameter); idle_thread = thread_res.Unwrap().get(); } diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 1661afbd9..e0f53287c 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -995,22 +995,11 @@ std::shared_ptr<Common::Fiber>& KThread::GetHostContext() { return host_context; } -ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags, - std::string name, VAddr entry_point, - u32 priority, u64 arg, s32 processor_id, - VAddr stack_top, Process* owner_process) { - std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc(); - void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top, - owner_process, std::move(init_func), init_func_parameter); -} - -ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags, - std::string name, VAddr entry_point, - u32 priority, u64 arg, s32 processor_id, - VAddr stack_top, Process* owner_process, - std::function<void(void*)>&& thread_start_func, - void* thread_start_parameter) { +ResultVal<std::shared_ptr<KThread>> KThread::CreateThread(Core::System& system, + ThreadType type_flags, std::string name, + VAddr entry_point, u32 priority, u64 arg, + s32 processor_id, VAddr stack_top, + Process* owner_process) { auto& kernel = system.Kernel(); std::shared_ptr<KThread> thread = std::make_shared<KThread>(kernel); @@ -1027,12 +1016,35 @@ ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, Thread auto& scheduler = kernel.GlobalSchedulerContext(); scheduler.AddThread(thread); - thread->host_context = - std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter); - return MakeResult<std::shared_ptr<KThread>>(std::move(thread)); } +ResultVal<std::shared_ptr<KThread>> KThread::CreateThread( + Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority, + u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process, + std::function<void(void*)>&& thread_start_func, void* thread_start_parameter) { + auto thread_result = CreateThread(system, type_flags, name, entry_point, priority, arg, + processor_id, stack_top, owner_process); + + if (thread_result.Succeeded()) { + (*thread_result)->host_context = + std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter); + } + + return thread_result; +} + +ResultVal<std::shared_ptr<KThread>> KThread::CreateUserThread( + Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority, + u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process) { + std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc(); + + void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); + + return CreateThread(system, type_flags, name, entry_point, priority, arg, processor_id, + stack_top, owner_process, std::move(init_func), init_func_parameter); +} + KThread* GetCurrentThreadPointer(KernelCore& kernel) { return kernel.GetCurrentEmuThread(); } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index c8ac656a4..1c19b23dc 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -116,7 +116,7 @@ public: using WaiterList = boost::intrusive::list<KThread>; /** - * Creates and returns a new thread. The new thread is immediately scheduled + * Creates and returns a new thread. * @param system The instance of the whole system * @param name The friendly name desired for the thread * @param entry_point The address at which the thread should start execution @@ -127,12 +127,12 @@ public: * @param owner_process The parent process for the thread, if null, it's a kernel thread * @return A shared pointer to the newly created thread */ - [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> Create( + [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread( Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process); /** - * Creates and returns a new thread. The new thread is immediately scheduled + * Creates and returns a new thread, with a specified entry point. * @param system The instance of the whole system * @param name The friendly name desired for the thread * @param entry_point The address at which the thread should start execution @@ -145,11 +145,27 @@ public: * @param thread_start_parameter The parameter which will passed to host context on init * @return A shared pointer to the newly created thread */ - [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> Create( + [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread( Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process, std::function<void(void*)>&& thread_start_func, void* thread_start_parameter); + /** + * Creates and returns a new thread for the emulated "user" process. + * @param system The instance of the whole system + * @param name The friendly name desired for the thread + * @param entry_point The address at which the thread should start execution + * @param priority The thread's priority + * @param arg User data to pass to the thread + * @param processor_id The ID(s) of the processors on which the thread is desired to be run + * @param stack_top The address of the thread's stack top + * @param owner_process The parent process for the thread, if null, it's a kernel thread + * @return A shared pointer to the newly created thread + */ + [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateUserThread( + Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, + u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process); + [[nodiscard]] std::string GetName() const override { return name; } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 331cf3a60..780008b08 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -181,9 +181,9 @@ struct KernelCore::Impl { std::string name = "Suspend Thread Id:" + std::to_string(i); std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - auto thread_res = KThread::Create(system, ThreadType::HighPriority, std::move(name), 0, - 0, 0, static_cast<u32>(i), 0, nullptr, - std::move(init_func), init_func_parameter); + auto thread_res = KThread::CreateThread( + system, ThreadType::HighPriority, std::move(name), 0, 0, 0, static_cast<u32>(i), 0, + nullptr, std::move(init_func), init_func_parameter); suspend_threads[i] = std::move(thread_res).Unwrap(); } @@ -221,10 +221,9 @@ struct KernelCore::Impl { // Gets the dummy KThread for the caller, allocating a new one if this is the first time KThread* GetHostDummyThread() { const thread_local auto thread = - KThread::Create( + KThread::CreateThread( system, ThreadType::Main, fmt::format("DummyThread:{}", GetHostThreadId()), 0, - KThread::DefaultThreadPriority, 0, static_cast<u32>(3), 0, nullptr, - []([[maybe_unused]] void* arg) { UNREACHABLE(); }, nullptr) + KThread::DefaultThreadPriority, 0, static_cast<u32>(3), 0, nullptr) .Unwrap(); return thread.get(); } diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 73b85d6f9..9d5956ead 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -40,8 +40,9 @@ namespace { void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); - auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0, - owner_process.GetIdealCoreId(), stack_top, &owner_process); + auto thread_res = + KThread::CreateUserThread(system, ThreadType::User, "main", entry_point, priority, 0, + owner_process.GetIdealCoreId(), stack_top, &owner_process); std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap(); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index cc8fa6576..326d3b9ec 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1532,8 +1532,9 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e std::shared_ptr<KThread> thread; { KScopedLightLock lk{process.GetStateLock()}; - CASCADE_RESULT(thread, KThread::Create(system, ThreadType::User, "", entry_point, priority, - arg, core_id, stack_bottom, &process)); + CASCADE_RESULT(thread, + KThread::CreateUserThread(system, ThreadType::User, "", entry_point, + priority, arg, core_id, stack_bottom, &process)); } const auto new_thread_handle = process.GetHandleTable().Create(thread); diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp index 681e93468..526bfa110 100644 --- a/src/core/network/network.cpp +++ b/src/core/network/network.cpp @@ -7,6 +7,7 @@ #include <limits> #include <utility> #include <vector> +#include "common/common_funcs.h" #ifdef _WIN32 #define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname @@ -90,15 +91,36 @@ LINGER MakeLinger(bool enable, u32 linger_value) { return value; } -int LastError() { - return WSAGetLastError(); -} - bool EnableNonBlock(SOCKET fd, bool enable) { u_long value = enable ? 1 : 0; return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR; } +Errno TranslateNativeError(int e) { + switch (e) { + case WSAEBADF: + return Errno::BADF; + case WSAEINVAL: + return Errno::INVAL; + case WSAEMFILE: + return Errno::MFILE; + case WSAENOTCONN: + return Errno::NOTCONN; + case WSAEWOULDBLOCK: + return Errno::AGAIN; + case WSAECONNREFUSED: + return Errno::CONNREFUSED; + case WSAEHOSTUNREACH: + return Errno::HOSTUNREACH; + case WSAENETDOWN: + return Errno::NETDOWN; + case WSAENETUNREACH: + return Errno::NETUNREACH; + default: + return Errno::OTHER; + } +} + #elif YUZU_UNIX // ^ _WIN32 v YUZU_UNIX using SOCKET = int; @@ -108,9 +130,6 @@ using ULONG = u64; constexpr SOCKET INVALID_SOCKET = -1; constexpr SOCKET SOCKET_ERROR = -1; -constexpr int WSAEWOULDBLOCK = EAGAIN; -constexpr int WSAENOTCONN = ENOTCONN; - constexpr int SD_RECEIVE = SHUT_RD; constexpr int SD_SEND = SHUT_WR; constexpr int SD_BOTH = SHUT_RDWR; @@ -162,10 +181,6 @@ linger MakeLinger(bool enable, u32 linger_value) { return value; } -int LastError() { - return errno; -} - bool EnableNonBlock(int fd, bool enable) { int flags = fcntl(fd, F_GETFD); if (flags == -1) { @@ -179,8 +194,43 @@ bool EnableNonBlock(int fd, bool enable) { return fcntl(fd, F_SETFD, flags) == 0; } +Errno TranslateNativeError(int e) { + switch (e) { + case EBADF: + return Errno::BADF; + case EINVAL: + return Errno::INVAL; + case EMFILE: + return Errno::MFILE; + case ENOTCONN: + return Errno::NOTCONN; + case EAGAIN: + return Errno::AGAIN; + case ECONNREFUSED: + return Errno::CONNREFUSED; + case EHOSTUNREACH: + return Errno::HOSTUNREACH; + case ENETDOWN: + return Errno::NETDOWN; + case ENETUNREACH: + return Errno::NETUNREACH; + default: + return Errno::OTHER; + } +} + #endif +Errno GetAndLogLastError() { +#ifdef _WIN32 + int e = WSAGetLastError(); +#else + int e = errno; +#endif + LOG_ERROR(Network, "Socket operation error: {}", NativeErrorToString(e)); + return TranslateNativeError(e); +} + int TranslateDomain(Domain domain) { switch (domain) { case Domain::INET: @@ -290,9 +340,7 @@ Errno SetSockOpt(SOCKET fd, int option, T value) { if (result != SOCKET_ERROR) { return Errno::SUCCESS; } - const int ec = LastError(); - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return Errno::SUCCESS; + return GetAndLogLastError(); } } // Anonymous namespace @@ -308,14 +356,12 @@ NetworkInstance::~NetworkInstance() { std::pair<IPv4Address, Errno> GetHostIPv4Address() { std::array<char, 256> name{}; if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) { - UNIMPLEMENTED_MSG("Unhandled gethostname error"); - return {IPv4Address{}, Errno::SUCCESS}; + return {IPv4Address{}, GetAndLogLastError()}; } hostent* const ent = gethostbyname(name.data()); if (!ent) { - UNIMPLEMENTED_MSG("Unhandled gethostbyname error"); - return {IPv4Address{}, Errno::SUCCESS}; + return {IPv4Address{}, GetAndLogLastError()}; } if (ent->h_addr_list == nullptr) { UNIMPLEMENTED_MSG("No addr provided in hostent->h_addr_list"); @@ -359,9 +405,7 @@ std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) { ASSERT(result == SOCKET_ERROR); - const int ec = LastError(); - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return {-1, Errno::SUCCESS}; + return {-1, GetAndLogLastError()}; } Socket::~Socket() { @@ -380,9 +424,7 @@ Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) { return Errno::SUCCESS; } - const int ec = LastError(); - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return Errno::SUCCESS; + return GetAndLogLastError(); } std::pair<Socket::AcceptResult, Errno> Socket::Accept() { @@ -391,9 +433,7 @@ std::pair<Socket::AcceptResult, Errno> Socket::Accept() { const SOCKET new_socket = accept(fd, &addr, &addrlen); if (new_socket == INVALID_SOCKET) { - const int ec = LastError(); - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return {AcceptResult{}, Errno::SUCCESS}; + return {AcceptResult{}, GetAndLogLastError()}; } AcceptResult result; @@ -412,23 +452,14 @@ Errno Socket::Connect(SockAddrIn addr_in) { return Errno::SUCCESS; } - switch (const int ec = LastError()) { - case WSAEWOULDBLOCK: - LOG_DEBUG(Service, "EAGAIN generated"); - return Errno::AGAIN; - default: - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return Errno::SUCCESS; - } + return GetAndLogLastError(); } std::pair<SockAddrIn, Errno> Socket::GetPeerName() { sockaddr addr; socklen_t addrlen = sizeof(addr); if (getpeername(fd, &addr, &addrlen) == SOCKET_ERROR) { - const int ec = LastError(); - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return {SockAddrIn{}, Errno::SUCCESS}; + return {SockAddrIn{}, GetAndLogLastError()}; } ASSERT(addrlen == sizeof(sockaddr_in)); @@ -439,9 +470,7 @@ std::pair<SockAddrIn, Errno> Socket::GetSockName() { sockaddr addr; socklen_t addrlen = sizeof(addr); if (getsockname(fd, &addr, &addrlen) == SOCKET_ERROR) { - const int ec = LastError(); - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return {SockAddrIn{}, Errno::SUCCESS}; + return {SockAddrIn{}, GetAndLogLastError()}; } ASSERT(addrlen == sizeof(sockaddr_in)); @@ -454,9 +483,7 @@ Errno Socket::Bind(SockAddrIn addr) { return Errno::SUCCESS; } - const int ec = LastError(); - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return Errno::SUCCESS; + return GetAndLogLastError(); } Errno Socket::Listen(s32 backlog) { @@ -464,9 +491,7 @@ Errno Socket::Listen(s32 backlog) { return Errno::SUCCESS; } - const int ec = LastError(); - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return Errno::SUCCESS; + return GetAndLogLastError(); } Errno Socket::Shutdown(ShutdownHow how) { @@ -489,14 +514,7 @@ Errno Socket::Shutdown(ShutdownHow how) { return Errno::SUCCESS; } - switch (const int ec = LastError()) { - case WSAENOTCONN: - LOG_ERROR(Service, "ENOTCONN generated"); - return Errno::NOTCONN; - default: - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return Errno::SUCCESS; - } + return GetAndLogLastError(); } std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) { @@ -509,17 +527,7 @@ std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) { return {static_cast<s32>(result), Errno::SUCCESS}; } - switch (const int ec = LastError()) { - case WSAEWOULDBLOCK: - LOG_DEBUG(Service, "EAGAIN generated"); - return {-1, Errno::AGAIN}; - case WSAENOTCONN: - LOG_ERROR(Service, "ENOTCONN generated"); - return {-1, Errno::NOTCONN}; - default: - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return {0, Errno::SUCCESS}; - } + return {-1, GetAndLogLastError()}; } std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) { @@ -541,17 +549,7 @@ std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, Sock return {static_cast<s32>(result), Errno::SUCCESS}; } - switch (const int ec = LastError()) { - case WSAEWOULDBLOCK: - LOG_DEBUG(Service, "EAGAIN generated"); - return {-1, Errno::AGAIN}; - case WSAENOTCONN: - LOG_ERROR(Service, "ENOTCONN generated"); - return {-1, Errno::NOTCONN}; - default: - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return {-1, Errno::SUCCESS}; - } + return {-1, GetAndLogLastError()}; } std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) { @@ -564,18 +562,7 @@ std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) { return {static_cast<s32>(result), Errno::SUCCESS}; } - const int ec = LastError(); - switch (ec) { - case WSAEWOULDBLOCK: - LOG_DEBUG(Service, "EAGAIN generated"); - return {-1, Errno::AGAIN}; - case WSAENOTCONN: - LOG_ERROR(Service, "ENOTCONN generated"); - return {-1, Errno::NOTCONN}; - default: - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return {-1, Errno::SUCCESS}; - } + return {-1, GetAndLogLastError()}; } std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message, @@ -597,9 +584,7 @@ std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message, return {static_cast<s32>(result), Errno::SUCCESS}; } - const int ec = LastError(); - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return {-1, Errno::SUCCESS}; + return {-1, GetAndLogLastError()}; } Errno Socket::Close() { @@ -642,9 +627,7 @@ Errno Socket::SetNonBlock(bool enable) { if (EnableNonBlock(fd, enable)) { return Errno::SUCCESS; } - const int ec = LastError(); - UNREACHABLE_MSG("Unhandled host socket error={}", ec); - return Errno::SUCCESS; + return GetAndLogLastError(); } bool Socket::IsOpened() const { diff --git a/src/core/network/network.h b/src/core/network/network.h index 76b2821f2..bd30f1899 100644 --- a/src/core/network/network.h +++ b/src/core/network/network.h @@ -7,6 +7,7 @@ #include <array> #include <utility> +#include "common/common_funcs.h" #include "common/common_types.h" namespace Network { @@ -21,6 +22,11 @@ enum class Errno { MFILE, NOTCONN, AGAIN, + CONNREFUSED, + HOSTUNREACH, + NETDOWN, + NETUNREACH, + OTHER, }; /// Address families diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp index b864d26f2..d81e790ee 100644 --- a/src/input_common/mouse/mouse_input.cpp +++ b/src/input_common/mouse/mouse_input.cpp @@ -59,7 +59,7 @@ void Mouse::UpdateYuzuSettings() { }); } -void Mouse::PressButton(int x, int y, int button_) { +void Mouse::PressButton(int x, int y, MouseButton button_) { const auto button_index = static_cast<std::size_t>(button_); if (button_index >= mouse_info.size()) { return; @@ -67,7 +67,7 @@ void Mouse::PressButton(int x, int y, int button_) { const auto button = 1U << button_index; buttons |= static_cast<u16>(button); - last_button = static_cast<MouseButton>(button_index); + last_button = button_; mouse_info[button_index].mouse_origin = Common::MakeVec(x, y); mouse_info[button_index].last_mouse_position = Common::MakeVec(x, y); @@ -129,7 +129,7 @@ void Mouse::MouseMove(int x, int y, int center_x, int center_y) { } } -void Mouse::ReleaseButton(int button_) { +void Mouse::ReleaseButton(MouseButton button_) { const auto button_index = static_cast<std::size_t>(button_); if (button_index >= mouse_info.size()) { return; @@ -152,6 +152,11 @@ void Mouse::BeginConfiguration() { void Mouse::EndConfiguration() { buttons = 0; + for (MouseInfo& info : mouse_info) { + info.tilt_speed = 0; + info.data.pressed = false; + info.data.axis = {0, 0}; + } last_button = MouseButton::Undefined; mouse_queue.Clear(); configuring = false; diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h index 46aa676c1..3622fe080 100644 --- a/src/input_common/mouse/mouse_input.h +++ b/src/input_common/mouse/mouse_input.h @@ -18,10 +18,12 @@ namespace MouseInput { enum class MouseButton { Left, - Wheel, Right, - Forward, + Wheel, Backward, + Forward, + Task, + Extra, Undefined, }; @@ -51,7 +53,7 @@ public: * @param y the y-coordinate of the cursor * @param button_ the button pressed */ - void PressButton(int x, int y, int button_); + void PressButton(int x, int y, MouseButton button_); /** * Signals that mouse has moved. @@ -65,7 +67,7 @@ public: /** * Signals that a motion sensor tilt has ended. */ - void ReleaseButton(int button_); + void ReleaseButton(MouseButton button_); [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue(); [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const; @@ -94,7 +96,7 @@ private: u16 buttons{}; std::thread update_thread; MouseButton last_button{MouseButton::Undefined}; - std::array<MouseInfo, 5> mouse_info; + std::array<MouseInfo, 7> mouse_info; Common::SPSCQueue<MouseStatus> mouse_queue; bool configuring{false}; bool update_thread_running{true}; diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index c4afa4174..df73f9ff7 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp @@ -5,6 +5,7 @@ #include <chrono> #include <cstring> #include <functional> +#include <random> #include <thread> #include <boost/asio.hpp> #include "common/logging/log.h" @@ -26,10 +27,10 @@ class Socket { public: using clock = std::chrono::system_clock; - explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, u32 client_id_, + explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, SocketCallback callback_) : callback(std::move(callback_)), timer(io_service), - socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id_), + socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()), pad_index(pad_index_) { boost::system::error_code ec{}; auto ipv4 = boost::asio::ip::make_address_v4(host, ec); @@ -63,6 +64,11 @@ public: } private: + u32 GenerateRandomClientId() const { + std::random_device device; + return device(); + } + void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) { if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) { switch (*type) { @@ -115,7 +121,7 @@ private: boost::asio::basic_waitable_timer<clock> timer; udp::socket socket; - u32 client_id{}; + const u32 client_id; std::size_t pad_index{}; static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); @@ -203,7 +209,7 @@ void Client::ReloadSockets() { LOG_ERROR(Input, "Duplicated UDP servers found"); continue; } - StartCommunication(client++, udp_input_address, udp_input_port, pad, 24872); + StartCommunication(client++, udp_input_address, udp_input_port, pad); } } } @@ -277,7 +283,7 @@ void Client::OnPadData(Response::PadData data, std::size_t client) { } void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, - std::size_t pad_index, u32 client_id) { + std::size_t pad_index) { SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, [this](Response::PortInfo info) { OnPortInfo(info); }, [this, client](Response::PadData data) { OnPadData(data, client); }}; @@ -287,7 +293,7 @@ void Client::StartCommunication(std::size_t client, const std::string& host, u16 clients[client].port = port; clients[client].pad_index = pad_index; clients[client].active = 0; - clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback); + clients[client].socket = std::make_unique<Socket>(host, port, pad_index, callback); clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; // Set motion parameters // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode @@ -416,7 +422,7 @@ const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const { return pad_queue; } -void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, +void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, const std::function<void()>& success_callback, const std::function<void()>& failure_callback) { std::thread([=] { @@ -426,7 +432,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, .port_info = [](Response::PortInfo) {}, .pad_data = [&](Response::PadData) { success_event.Set(); }, }; - Socket socket{host, port, pad_index, client_id, std::move(callback)}; + Socket socket{host, port, pad_index, std::move(callback)}; std::thread worker_thread{SocketLoop, &socket}; const bool result = success_event.WaitFor(std::chrono::seconds(5)); socket.Stop(); @@ -440,7 +446,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, } CalibrationConfigurationJob::CalibrationConfigurationJob( - const std::string& host, u16 port, std::size_t pad_index, u32 client_id, + const std::string& host, u16 port, std::size_t pad_index, std::function<void(Status)> status_callback, std::function<void(u16, u16, u16, u16)> data_callback) { @@ -485,7 +491,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( complete_event.Set(); } }}; - Socket socket{host, port, pad_index, client_id, std::move(callback)}; + Socket socket{host, port, pad_index, std::move(callback)}; std::thread worker_thread{SocketLoop, &socket}; complete_event.Wait(); socket.Stop(); diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h index a523f6124..e9e438e88 100644 --- a/src/input_common/udp/client.h +++ b/src/input_common/udp/client.h @@ -126,7 +126,7 @@ private: void OnPortInfo(Response::PortInfo); void OnPadData(Response::PadData, std::size_t client); void StartCommunication(std::size_t client, const std::string& host, u16 port, - std::size_t pad_index, u32 client_id); + std::size_t pad_index); void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro); @@ -165,7 +165,7 @@ public: * @param data_callback Called when calibration data is ready */ explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index, - u32 client_id, std::function<void(Status)> status_callback, + std::function<void(Status)> status_callback, std::function<void(u16, u16, u16, u16)> data_callback); ~CalibrationConfigurationJob(); void Stop(); @@ -174,7 +174,7 @@ private: Common::Event complete_event; }; -void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, +void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, const std::function<void()>& success_callback, const std::function<void()>& failure_callback); diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 4ea0076e9..d875c4fee 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(tests common/param_package.cpp common/ring_buffer.cpp core/core_timing.cpp + core/network/network.cpp tests.cpp video_core/buffer_base.cpp ) diff --git a/src/tests/common/fibers.cpp b/src/tests/common/fibers.cpp index d94492fc6..751cbe196 100644 --- a/src/tests/common/fibers.cpp +++ b/src/tests/common/fibers.cpp @@ -67,7 +67,7 @@ void TestControl1::DoWork() { value++; } results[id] = value; - Fiber::YieldTo(work_fibers[id], thread_fibers[id]); + Fiber::YieldTo(work_fibers[id], *thread_fibers[id]); } void TestControl1::ExecuteThread(u32 id) { @@ -76,7 +76,7 @@ void TestControl1::ExecuteThread(u32 id) { thread_fibers[id] = thread_fiber; work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this); items[id] = rand() % 256; - Fiber::YieldTo(thread_fibers[id], work_fibers[id]); + Fiber::YieldTo(thread_fibers[id], *work_fibers[id]); thread_fibers[id]->Exit(); } @@ -117,11 +117,11 @@ public: for (u32 i = 0; i < 12000; i++) { value1 += i; } - Fiber::YieldTo(fiber1, fiber3); + Fiber::YieldTo(fiber1, *fiber3); const u32 id = thread_ids.Get(); assert1 = id == 1; value2 += 5000; - Fiber::YieldTo(fiber1, thread_fibers[id]); + Fiber::YieldTo(fiber1, *thread_fibers[id]); } void DoWork2() { @@ -129,7 +129,7 @@ public: ; value2 = 2000; trap = false; - Fiber::YieldTo(fiber2, fiber1); + Fiber::YieldTo(fiber2, *fiber1); assert3 = false; } @@ -137,19 +137,19 @@ public: const u32 id = thread_ids.Get(); assert2 = id == 0; value1 += 1000; - Fiber::YieldTo(fiber3, thread_fibers[id]); + Fiber::YieldTo(fiber3, *thread_fibers[id]); } void ExecuteThread(u32 id); void CallFiber1() { const u32 id = thread_ids.Get(); - Fiber::YieldTo(thread_fibers[id], fiber1); + Fiber::YieldTo(thread_fibers[id], *fiber1); } void CallFiber2() { const u32 id = thread_ids.Get(); - Fiber::YieldTo(thread_fibers[id], fiber2); + Fiber::YieldTo(thread_fibers[id], *fiber2); } void Exit(); @@ -241,23 +241,23 @@ public: void DoWork1() { value1 += 1; - Fiber::YieldTo(fiber1, fiber2); + Fiber::YieldTo(fiber1, *fiber2); const u32 id = thread_ids.Get(); value3 += 1; - Fiber::YieldTo(fiber1, thread_fibers[id]); + Fiber::YieldTo(fiber1, *thread_fibers[id]); } void DoWork2() { value2 += 1; const u32 id = thread_ids.Get(); - Fiber::YieldTo(fiber2, thread_fibers[id]); + Fiber::YieldTo(fiber2, *thread_fibers[id]); } void ExecuteThread(u32 id); void CallFiber1() { const u32 id = thread_ids.Get(); - Fiber::YieldTo(thread_fibers[id], fiber1); + Fiber::YieldTo(thread_fibers[id], *fiber1); } void Exit(); @@ -332,7 +332,7 @@ public: void Execute() { thread_fiber = Fiber::ThreadToFiber(); - Fiber::YieldTo(thread_fiber, fiber1); + Fiber::YieldTo(thread_fiber, *fiber1); thread_fiber->Exit(); } @@ -340,7 +340,7 @@ public: fiber1->SetRewindPoint(std::function<void(void*)>{WorkControl4}, this); if (rewinded) { goal_reached = true; - Fiber::YieldTo(fiber1, thread_fiber); + Fiber::YieldTo(fiber1, *thread_fiber); } rewinded = true; fiber1->Rewind(); diff --git a/src/tests/core/network/network.cpp b/src/tests/core/network/network.cpp new file mode 100644 index 000000000..b21ad8911 --- /dev/null +++ b/src/tests/core/network/network.cpp @@ -0,0 +1,28 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <catch2/catch.hpp> + +#include "core/network/network.h" +#include "core/network/sockets.h" + +TEST_CASE("Network::Errors", "[core]") { + Network::NetworkInstance network_instance; // initialize network + + Network::Socket socks[2]; + for (Network::Socket& sock : socks) { + REQUIRE(sock.Initialize(Network::Domain::INET, Network::Type::STREAM, + Network::Protocol::TCP) == Network::Errno::SUCCESS); + } + + Network::SockAddrIn addr{ + Network::Domain::INET, + {127, 0, 0, 1}, + 1, // hopefully nobody running this test has something listening on port 1 + }; + REQUIRE(socks[0].Connect(addr) == Network::Errno::CONNREFUSED); + + std::vector<u8> message{1, 2, 3, 4}; + REQUIRE(socks[1].Recv(0, message).second == Network::Errno::NOTCONN); +} diff --git a/src/video_core/renderer_vulkan/vk_command_pool.cpp b/src/video_core/renderer_vulkan/vk_command_pool.cpp index a99df9323..d8e92ac0e 100644 --- a/src/video_core/renderer_vulkan/vk_command_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_command_pool.cpp @@ -10,7 +10,7 @@ namespace Vulkan { -constexpr size_t COMMAND_BUFFER_POOL_SIZE = 0x1000; +constexpr size_t COMMAND_BUFFER_POOL_SIZE = 4; struct CommandPool::Pool { vk::CommandPool handle; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 1c61d419d..ae49cbb45 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -383,6 +383,25 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { input_subsystem->GetKeyboard()->ReleaseKey(event->key()); } +MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) { + switch (button) { + case Qt::LeftButton: + return MouseInput::MouseButton::Left; + case Qt::RightButton: + return MouseInput::MouseButton::Right; + case Qt::MiddleButton: + return MouseInput::MouseButton::Wheel; + case Qt::BackButton: + return MouseInput::MouseButton::Backward; + case Qt::ForwardButton: + return MouseInput::MouseButton::Forward; + case Qt::TaskButton: + return MouseInput::MouseButton::Task; + default: + return MouseInput::MouseButton::Extra; + } +} + void GRenderWindow::mousePressEvent(QMouseEvent* event) { // Touch input is handled in TouchBeginEvent if (event->source() == Qt::MouseEventSynthesizedBySystem) { @@ -391,7 +410,8 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { auto pos = event->pos(); const auto [x, y] = ScaleTouch(pos); - input_subsystem->GetMouse()->PressButton(x, y, event->button()); + const auto button = QtButtonToMouseButton(event->button()); + input_subsystem->GetMouse()->PressButton(x, y, button); if (event->button() == Qt::LeftButton) { this->TouchPressed(x, y, 0); @@ -425,7 +445,8 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { return; } - input_subsystem->GetMouse()->ReleaseButton(event->button()); + const auto button = QtButtonToMouseButton(event->button()); + input_subsystem->GetMouse()->ReleaseButton(button); if (event->button() == Qt::LeftButton) { this->TouchReleased(0); diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index b5ec7de07..acfe2bc8c 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -28,6 +28,10 @@ namespace InputCommon { class InputSubsystem; } +namespace MouseInput { +enum class MouseButton; +} + namespace VideoCore { enum class LoadCallbackStage; } @@ -149,6 +153,9 @@ public: void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; + /// Converts a Qt mouse button into MouseInput mouse button + static MouseInput::MouseButton QtButtonToMouseButton(Qt::MouseButton button); + void mousePressEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 3d6f64300..1bac57bb2 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -235,7 +235,7 @@ const std::array<UISettings::Shortcut, 17> Config::default_hotkeys{{ {QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}}, {QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}}, {QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}}, - {QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("F9"), Qt::ApplicationShortcut}}, + {QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F9"), Qt::ApplicationShortcut}}, {QStringLiteral("Toggle Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Z"), Qt::ApplicationShortcut}}, {QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), Qt::WindowShortcut}}, }}; @@ -508,7 +508,7 @@ void Config::ReadControlValues() { Settings::values.emulate_analog_keyboard = ReadSetting(QStringLiteral("emulate_analog_keyboard"), false).toBool(); - Settings::values.mouse_panning = ReadSetting(QStringLiteral("mouse_panning"), false).toBool(); + Settings::values.mouse_panning = false; Settings::values.mouse_panning_sensitivity = ReadSetting(QStringLiteral("mouse_panning_sensitivity"), 1).toFloat(); @@ -648,7 +648,7 @@ void Config::ReadDebuggingValues() { void Config::ReadServiceValues() { qt_config->beginGroup(QStringLiteral("Services")); Settings::values.bcat_backend = - ReadSetting(QStringLiteral("bcat_backend"), QStringLiteral("null")) + ReadSetting(QStringLiteral("bcat_backend"), QStringLiteral("none")) .toString() .toStdString(); Settings::values.bcat_boxcat_local = @@ -1182,7 +1182,6 @@ void Config::SaveControlValues() { WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false); WriteSetting(QStringLiteral("emulate_analog_keyboard"), Settings::values.emulate_analog_keyboard, false); - WriteSetting(QStringLiteral("mouse_panning"), Settings::values.mouse_panning, false); WriteSetting(QStringLiteral("mouse_panning_sensitivity"), Settings::values.mouse_panning_sensitivity, 1.0f); qt_config->endGroup(); @@ -1239,7 +1238,7 @@ void Config::SaveDebuggingValues() { void Config::SaveServiceValues() { qt_config->beginGroup(QStringLiteral("Services")); WriteSetting(QStringLiteral("bcat_backend"), - QString::fromStdString(Settings::values.bcat_backend), QStringLiteral("null")); + QString::fromStdString(Settings::values.bcat_backend), QStringLiteral("none")); WriteSetting(QStringLiteral("bcat_boxcat_local"), Settings::values.bcat_boxcat_local, false); qt_config->endGroup(); } diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 21d0d3449..bc572d319 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -21,6 +21,7 @@ #include "input_common/mouse/mouse_poller.h" #include "input_common/udp/udp.h" #include "ui_configure_input_player.h" +#include "yuzu/bootmanager.h" #include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_input_player_widget.h" @@ -1345,7 +1346,8 @@ void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) { return; } - input_subsystem->GetMouse()->PressButton(0, 0, event->button()); + const auto button = GRenderWindow::QtButtonToMouseButton(event->button()); + input_subsystem->GetMouse()->PressButton(0, 0, button); } void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) { diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp index 1f2b792e4..52fdf7265 100644 --- a/src/yuzu/configuration/configure_motion_touch.cpp +++ b/src/yuzu/configuration/configure_motion_touch.cpp @@ -24,7 +24,7 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port, - u8 pad_index, u16 client_id) + u8 pad_index) : QDialog(parent) { layout = new QVBoxLayout; status_label = new QLabel(tr("Communicating with the server...")); @@ -41,7 +41,7 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, using namespace InputCommon::CemuhookUDP; job = std::make_unique<CalibrationConfigurationJob>( - host, port, pad_index, client_id, + host, port, pad_index, [this](CalibrationConfigurationJob::Status status) { QString text; switch (status) { @@ -218,7 +218,6 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() { udp_test_in_progress = true; InputCommon::CemuhookUDP::TestCommunication( ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 0, - 24872, [this] { LOG_INFO(Frontend, "UDP input test success"); QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true)); @@ -233,8 +232,7 @@ void ConfigureMotionTouch::OnConfigureTouchCalibration() { ui->touch_calibration_config->setEnabled(false); ui->touch_calibration_config->setText(tr("Configuring")); CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(), - static_cast<u16>(ui->udp_port->text().toUInt()), 0, - 24872); + static_cast<u16>(ui->udp_port->text().toUInt()), 0); dialog.exec(); if (dialog.completed) { min_x = dialog.min_x; diff --git a/src/yuzu/configuration/configure_motion_touch.h b/src/yuzu/configuration/configure_motion_touch.h index 15d61e8ba..d76bc8154 100644 --- a/src/yuzu/configuration/configure_motion_touch.h +++ b/src/yuzu/configuration/configure_motion_touch.h @@ -30,7 +30,7 @@ class CalibrationConfigurationDialog : public QDialog { Q_OBJECT public: explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port, - u8 pad_index, u16 client_id); + u8 pad_index); ~CalibrationConfigurationDialog() override; private: diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 0ba7c07cc..56d892a31 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -854,8 +854,7 @@ void GMainWindow::InitializeHotkeys() { connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this), &QShortcut::activated, this, [&] { Settings::values.mouse_panning = !Settings::values.mouse_panning; - if (UISettings::values.hide_mouse || Settings::values.mouse_panning) { - mouse_hide_timer.start(); + if (Settings::values.mouse_panning) { render_window->installEventFilter(render_window); render_window->setAttribute(Qt::WA_Hover, true); } @@ -1208,11 +1207,14 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) { renderer_status_button->setDisabled(true); if (UISettings::values.hide_mouse || Settings::values.mouse_panning) { - mouse_hide_timer.start(); render_window->installEventFilter(render_window); render_window->setAttribute(Qt::WA_Hover, true); } + if (UISettings::values.hide_mouse) { + mouse_hide_timer.start(); + } + std::string title_name; std::string title_version; const auto res = system.GetGameName(title_name); @@ -2372,12 +2374,15 @@ void GMainWindow::OnConfigure() { if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) { render_window->installEventFilter(render_window); render_window->setAttribute(Qt::WA_Hover, true); - mouse_hide_timer.start(); } else { render_window->removeEventFilter(render_window); render_window->setAttribute(Qt::WA_Hover, false); } + if (UISettings::values.hide_mouse) { + mouse_hide_timer.start(); + } + UpdateStatusButtons(); } @@ -2615,8 +2620,7 @@ void GMainWindow::UpdateUISettings() { } void GMainWindow::HideMouseCursor() { - if (emu_thread == nullptr || - (!UISettings::values.hide_mouse && !Settings::values.mouse_panning)) { + if (emu_thread == nullptr && UISettings::values.hide_mouse) { mouse_hide_timer.stop(); ShowMouseCursor(); return; @@ -2626,8 +2630,7 @@ void GMainWindow::HideMouseCursor() { void GMainWindow::ShowMouseCursor() { render_window->unsetCursor(); - if (emu_thread != nullptr && - (UISettings::values.hide_mouse || Settings::values.mouse_panning)) { + if (emu_thread != nullptr && UISettings::values.hide_mouse) { mouse_hide_timer.start(); } } diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 6d8bc5509..43877fc98 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -457,7 +457,7 @@ void Config::ReadValues() { Settings::values.yuzu_token = sdl2_config->Get("WebService", "yuzu_token", ""); // Services - Settings::values.bcat_backend = sdl2_config->Get("Services", "bcat_backend", "null"); + Settings::values.bcat_backend = sdl2_config->Get("Services", "bcat_backend", "none"); Settings::values.bcat_boxcat_local = sdl2_config->GetBoolean("Services", "bcat_boxcat_local", false); } diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 7e391ab89..ce8b7c218 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp @@ -35,18 +35,36 @@ void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { input_subsystem->GetMouse()->MouseMove(x, y, 0, 0); } +MouseInput::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const { + switch (button) { + case SDL_BUTTON_LEFT: + return MouseInput::MouseButton::Left; + case SDL_BUTTON_RIGHT: + return MouseInput::MouseButton::Right; + case SDL_BUTTON_MIDDLE: + return MouseInput::MouseButton::Wheel; + case SDL_BUTTON_X1: + return MouseInput::MouseButton::Backward; + case SDL_BUTTON_X2: + return MouseInput::MouseButton::Forward; + default: + return MouseInput::MouseButton::Undefined; + } +} + void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { + const auto mouse_button = SDLButtonToMouseButton(button); if (button == SDL_BUTTON_LEFT) { if (state == SDL_PRESSED) { TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); } else { TouchReleased(0); } - } else if (button == SDL_BUTTON_RIGHT) { + } else { if (state == SDL_PRESSED) { - input_subsystem->GetMouse()->PressButton(x, y, button); + input_subsystem->GetMouse()->PressButton(x, y, mouse_button); } else { - input_subsystem->GetMouse()->ReleaseButton(button); + input_subsystem->GetMouse()->ReleaseButton(mouse_button); } } } diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h index 51a12a6a9..0e17bbca7 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h @@ -18,6 +18,10 @@ namespace InputCommon { class InputSubsystem; } +namespace MouseInput { +enum class MouseButton; +} + class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { public: explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem); @@ -42,6 +46,9 @@ protected: /// Called by WaitEvent when the mouse moves. void OnMouseMotion(s32 x, s32 y); + /// Converts a SDL mouse button into MouseInput mouse button + MouseInput::MouseButton SDLButtonToMouseButton(u32 button) const; + /// Called by WaitEvent when a mouse button is pressed or released void OnMouseButton(u32 button, u8 state, s32 x, s32 y); |