diff options
Diffstat (limited to 'src')
51 files changed, 730 insertions, 296 deletions
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) | |||
| 27 | # /Zo - Enhanced debug info for optimized builds | 27 | # /Zo - Enhanced debug info for optimized builds |
| 28 | # /permissive- - Enables stricter C++ standards conformance checks | 28 | # /permissive- - Enables stricter C++ standards conformance checks |
| 29 | # /EHsc - C++-only exception handling semantics | 29 | # /EHsc - C++-only exception handling semantics |
| 30 | # /utf-8 - Set source and execution character sets to UTF-8 | ||
| 30 | # /volatile:iso - Use strict standards-compliant volatile semantics. | 31 | # /volatile:iso - Use strict standards-compliant volatile semantics. |
| 31 | # /Zc:externConstexpr - Allow extern constexpr variables to have external linkage, like the standard mandates | 32 | # /Zc:externConstexpr - Allow extern constexpr variables to have external linkage, like the standard mandates |
| 32 | # /Zc:inline - Let codegen omit inline functions in object files | 33 | # /Zc:inline - Let codegen omit inline functions in object files |
| @@ -38,6 +39,7 @@ if (MSVC) | |||
| 38 | /permissive- | 39 | /permissive- |
| 39 | /EHsc | 40 | /EHsc |
| 40 | /std:c++latest | 41 | /std:c++latest |
| 42 | /utf-8 | ||
| 41 | /volatile:iso | 43 | /volatile:iso |
| 42 | /Zc:externConstexpr | 44 | /Zc:externConstexpr |
| 43 | /Zc:inline | 45 | /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); | |||
| 52 | // Generic function to get last error message. | 52 | // Generic function to get last error message. |
| 53 | // Call directly after the command or use the error num. | 53 | // Call directly after the command or use the error num. |
| 54 | // This function might change the error code. | 54 | // This function might change the error code. |
| 55 | // Defined in Misc.cpp. | 55 | // Defined in misc.cpp. |
| 56 | [[nodiscard]] std::string GetLastErrorMsg(); | 56 | [[nodiscard]] std::string GetLastErrorMsg(); |
| 57 | 57 | ||
| 58 | // Like GetLastErrorMsg(), but passing an explicit error code. | ||
| 59 | // Defined in misc.cpp. | ||
| 60 | [[nodiscard]] std::string NativeErrorToString(int e); | ||
| 61 | |||
| 58 | #define DECLARE_ENUM_FLAG_OPERATORS(type) \ | 62 | #define DECLARE_ENUM_FLAG_OPERATORS(type) \ |
| 59 | [[nodiscard]] constexpr type operator|(type a, type b) noexcept { \ | 63 | [[nodiscard]] constexpr type operator|(type a, type b) noexcept { \ |
| 60 | using T = std::underlying_type_t<type>; \ | 64 | 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() { | |||
| 116 | boost::context::detail::jump_fcontext(impl->rewind_context, this); | 116 | boost::context::detail::jump_fcontext(impl->rewind_context, this); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { | 119 | void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) { |
| 120 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); | 120 | to.impl->guard.lock(); |
| 121 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); | 121 | to.impl->previous_fiber = weak_from.lock(); |
| 122 | to->impl->guard.lock(); | 122 | |
| 123 | to->impl->previous_fiber = from; | 123 | auto transfer = boost::context::detail::jump_fcontext(to.impl->context, &to); |
| 124 | auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); | 124 | |
| 125 | ASSERT(from->impl->previous_fiber != nullptr); | 125 | // "from" might no longer be valid if the thread was killed |
| 126 | from->impl->previous_fiber->impl->context = transfer.fctx; | 126 | if (auto from = weak_from.lock()) { |
| 127 | from->impl->previous_fiber->impl->guard.unlock(); | 127 | ASSERT(from->impl->previous_fiber != nullptr); |
| 128 | from->impl->previous_fiber.reset(); | 128 | from->impl->previous_fiber->impl->context = transfer.fctx; |
| 129 | from->impl->previous_fiber->impl->guard.unlock(); | ||
| 130 | from->impl->previous_fiber.reset(); | ||
| 131 | } | ||
| 129 | } | 132 | } |
| 130 | 133 | ||
| 131 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { | 134 | 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: | |||
| 41 | 41 | ||
| 42 | /// Yields control from Fiber 'from' to Fiber 'to' | 42 | /// Yields control from Fiber 'from' to Fiber 'to' |
| 43 | /// Fiber 'from' must be the currently running fiber. | 43 | /// Fiber 'from' must be the currently running fiber. |
| 44 | static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to); | 44 | static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to); |
| 45 | [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber(); | 45 | [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber(); |
| 46 | 46 | ||
| 47 | void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param); | 47 | 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 @@ | |||
| 12 | 12 | ||
| 13 | #include "common/common_funcs.h" | 13 | #include "common/common_funcs.h" |
| 14 | 14 | ||
| 15 | // Generic function to get last error message. | 15 | std::string NativeErrorToString(int e) { |
| 16 | // Call directly after the command or use the error num. | ||
| 17 | // This function might change the error code. | ||
| 18 | std::string GetLastErrorMsg() { | ||
| 19 | static constexpr std::size_t buff_size = 255; | ||
| 20 | char err_str[buff_size]; | ||
| 21 | |||
| 22 | #ifdef _WIN32 | 16 | #ifdef _WIN32 |
| 23 | FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), | 17 | LPSTR err_str; |
| 24 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr); | 18 | |
| 25 | return std::string(err_str, buff_size); | 19 | DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | |
| 26 | #elif defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)) | 20 | FORMAT_MESSAGE_IGNORE_INSERTS, |
| 21 | nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||
| 22 | reinterpret_cast<LPSTR>(&err_str), 1, nullptr); | ||
| 23 | if (!res) { | ||
| 24 | return "(FormatMessageA failed to format error)"; | ||
| 25 | } | ||
| 26 | std::string ret(err_str); | ||
| 27 | LocalFree(err_str); | ||
| 28 | return ret; | ||
| 29 | #else | ||
| 30 | char err_str[255]; | ||
| 31 | #if defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)) | ||
| 27 | // Thread safe (GNU-specific) | 32 | // Thread safe (GNU-specific) |
| 28 | const char* str = strerror_r(errno, err_str, buff_size); | 33 | const char* str = strerror_r(e, err_str, sizeof(err_str)); |
| 29 | return std::string(str); | 34 | return std::string(str); |
| 30 | #else | 35 | #else |
| 31 | // Thread safe (XSI-compliant) | 36 | // Thread safe (XSI-compliant) |
| 32 | const int success = strerror_r(errno, err_str, buff_size); | 37 | int second_err = strerror_r(e, err_str, sizeof(err_str)); |
| 33 | if (success != 0) { | 38 | if (second_err != 0) { |
| 34 | return {}; | 39 | return "(strerror_r failed to format error)"; |
| 35 | } | 40 | } |
| 36 | return std::string(err_str); | 41 | return std::string(err_str); |
| 42 | #endif // GLIBC etc. | ||
| 43 | #endif // _WIN32 | ||
| 44 | } | ||
| 45 | |||
| 46 | std::string GetLastErrorMsg() { | ||
| 47 | #ifdef _WIN32 | ||
| 48 | return NativeErrorToString(GetLastError()); | ||
| 49 | #else | ||
| 50 | return NativeErrorToString(errno); | ||
| 37 | #endif | 51 | #endif |
| 38 | } | 52 | } |
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 { | |||
| 299 | gpu_core->WaitIdle(); | 299 | gpu_core->WaitIdle(); |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | // Shutdown emulation session | ||
| 303 | services.reset(); | 302 | services.reset(); |
| 304 | service_manager.reset(); | 303 | service_manager.reset(); |
| 305 | cheat_engine.reset(); | 304 | cheat_engine.reset(); |
| 306 | telemetry_session.reset(); | 305 | telemetry_session.reset(); |
| 307 | |||
| 308 | // Close all CPU/threading state | ||
| 309 | cpu_manager.Shutdown(); | 306 | cpu_manager.Shutdown(); |
| 310 | |||
| 311 | // Release the Time Manager's resources | ||
| 312 | time_manager.Shutdown(); | 307 | time_manager.Shutdown(); |
| 313 | |||
| 314 | // Shutdown kernel and core timing | ||
| 315 | core_timing.Shutdown(); | 308 | core_timing.Shutdown(); |
| 316 | kernel.Shutdown(); | ||
| 317 | |||
| 318 | // Close app loader | ||
| 319 | app_loader.reset(); | 309 | app_loader.reset(); |
| 320 | gpu_core.reset(); | 310 | gpu_core.reset(); |
| 321 | perf_stats.reset(); | 311 | perf_stats.reset(); |
| 322 | 312 | kernel.Shutdown(); | |
| 323 | // Clear all applets | ||
| 324 | applet_manager.ClearAll(); | 313 | applet_manager.ClearAll(); |
| 325 | 314 | ||
| 326 | LOG_DEBUG(Core, "Shutdown OK"); | 315 | 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() { | |||
| 148 | auto core = kernel.GetCurrentHostThreadID(); | 148 | auto core = kernel.GetCurrentHostThreadID(); |
| 149 | auto& scheduler = *kernel.CurrentScheduler(); | 149 | auto& scheduler = *kernel.CurrentScheduler(); |
| 150 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); | 150 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); |
| 151 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context); | 151 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); |
| 152 | ASSERT(scheduler.ContextSwitchPending()); | 152 | ASSERT(scheduler.ContextSwitchPending()); |
| 153 | ASSERT(core == kernel.GetCurrentHostThreadID()); | 153 | ASSERT(core == kernel.GetCurrentHostThreadID()); |
| 154 | scheduler.RescheduleCurrentCore(); | 154 | scheduler.RescheduleCurrentCore(); |
| @@ -245,7 +245,7 @@ void CpuManager::SingleCoreRunSuspendThread() { | |||
| 245 | auto core = kernel.GetCurrentHostThreadID(); | 245 | auto core = kernel.GetCurrentHostThreadID(); |
| 246 | auto& scheduler = *kernel.CurrentScheduler(); | 246 | auto& scheduler = *kernel.CurrentScheduler(); |
| 247 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); | 247 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); |
| 248 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context); | 248 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context); |
| 249 | ASSERT(scheduler.ContextSwitchPending()); | 249 | ASSERT(scheduler.ContextSwitchPending()); |
| 250 | ASSERT(core == kernel.GetCurrentHostThreadID()); | 250 | ASSERT(core == kernel.GetCurrentHostThreadID()); |
| 251 | scheduler.RescheduleCurrentCore(); | 251 | scheduler.RescheduleCurrentCore(); |
| @@ -271,7 +271,7 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) { | |||
| 271 | scheduler.Unload(scheduler.GetCurrentThread()); | 271 | scheduler.Unload(scheduler.GetCurrentThread()); |
| 272 | 272 | ||
| 273 | auto& next_scheduler = kernel.Scheduler(current_core); | 273 | auto& next_scheduler = kernel.Scheduler(current_core); |
| 274 | Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext()); | 274 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.ControlContext()); |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | // May have changed scheduler | 277 | // May have changed scheduler |
| @@ -363,7 +363,7 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 363 | 363 | ||
| 364 | auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | 364 | auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); |
| 365 | data.is_running = true; | 365 | data.is_running = true; |
| 366 | Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext()); | 366 | Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); |
| 367 | data.is_running = false; | 367 | data.is_running = false; |
| 368 | data.is_paused = true; | 368 | data.is_paused = true; |
| 369 | data.exit_barrier->Wait(); | 369 | 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 | |||
| 105 | } | 105 | } |
| 106 | } | 106 | } |
| 107 | } | 107 | } |
| 108 | |||
| 109 | mbedtls_cipher_finish(context, nullptr, nullptr); | ||
| 110 | } | 108 | } |
| 111 | 109 | ||
| 112 | template <typename Key, std::size_t KeySize> | 110 | 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() { | |||
| 734 | } | 734 | } |
| 735 | guard.unlock(); | 735 | guard.unlock(); |
| 736 | 736 | ||
| 737 | Common::Fiber::YieldTo(*old_context, switch_fiber); | 737 | Common::Fiber::YieldTo(*old_context, *switch_fiber); |
| 738 | /// When a thread wakes up, the scheduler may have changed to other in another core. | 738 | /// When a thread wakes up, the scheduler may have changed to other in another core. |
| 739 | auto& next_scheduler = *system.Kernel().CurrentScheduler(); | 739 | auto& next_scheduler = *system.Kernel().CurrentScheduler(); |
| 740 | next_scheduler.SwitchContextStep2(); | 740 | next_scheduler.SwitchContextStep2(); |
| @@ -769,13 +769,8 @@ void KScheduler::SwitchToCurrent() { | |||
| 769 | break; | 769 | break; |
| 770 | } | 770 | } |
| 771 | } | 771 | } |
| 772 | std::shared_ptr<Common::Fiber>* next_context; | 772 | auto thread = next_thread ? next_thread : idle_thread; |
| 773 | if (next_thread != nullptr) { | 773 | Common::Fiber::YieldTo(switch_fiber, *thread->GetHostContext()); |
| 774 | next_context = &next_thread->GetHostContext(); | ||
| 775 | } else { | ||
| 776 | next_context = &idle_thread->GetHostContext(); | ||
| 777 | } | ||
| 778 | Common::Fiber::YieldTo(switch_fiber, *next_context); | ||
| 779 | } while (!is_switch_pending()); | 774 | } while (!is_switch_pending()); |
| 780 | } | 775 | } |
| 781 | } | 776 | } |
| @@ -800,9 +795,9 @@ void KScheduler::Initialize() { | |||
| 800 | std::string name = "Idle Thread Id:" + std::to_string(core_id); | 795 | std::string name = "Idle Thread Id:" + std::to_string(core_id); |
| 801 | std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc(); | 796 | std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc(); |
| 802 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); | 797 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); |
| 803 | auto thread_res = KThread::Create(system, ThreadType::Main, name, 0, | 798 | auto thread_res = KThread::CreateThread( |
| 804 | KThread::IdleThreadPriority, 0, static_cast<u32>(core_id), 0, | 799 | system, ThreadType::Main, name, 0, KThread::IdleThreadPriority, 0, |
| 805 | nullptr, std::move(init_func), init_func_parameter); | 800 | static_cast<u32>(core_id), 0, nullptr, std::move(init_func), init_func_parameter); |
| 806 | idle_thread = thread_res.Unwrap().get(); | 801 | idle_thread = thread_res.Unwrap().get(); |
| 807 | } | 802 | } |
| 808 | 803 | ||
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() { | |||
| 995 | return host_context; | 995 | return host_context; |
| 996 | } | 996 | } |
| 997 | 997 | ||
| 998 | ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags, | 998 | ResultVal<std::shared_ptr<KThread>> KThread::CreateThread(Core::System& system, |
| 999 | std::string name, VAddr entry_point, | 999 | ThreadType type_flags, std::string name, |
| 1000 | u32 priority, u64 arg, s32 processor_id, | 1000 | VAddr entry_point, u32 priority, u64 arg, |
| 1001 | VAddr stack_top, Process* owner_process) { | 1001 | s32 processor_id, VAddr stack_top, |
| 1002 | std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc(); | 1002 | Process* owner_process) { |
| 1003 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); | ||
| 1004 | return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top, | ||
| 1005 | owner_process, std::move(init_func), init_func_parameter); | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags, | ||
| 1009 | std::string name, VAddr entry_point, | ||
| 1010 | u32 priority, u64 arg, s32 processor_id, | ||
| 1011 | VAddr stack_top, Process* owner_process, | ||
| 1012 | std::function<void(void*)>&& thread_start_func, | ||
| 1013 | void* thread_start_parameter) { | ||
| 1014 | auto& kernel = system.Kernel(); | 1003 | auto& kernel = system.Kernel(); |
| 1015 | 1004 | ||
| 1016 | std::shared_ptr<KThread> thread = std::make_shared<KThread>(kernel); | 1005 | 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 | |||
| 1027 | auto& scheduler = kernel.GlobalSchedulerContext(); | 1016 | auto& scheduler = kernel.GlobalSchedulerContext(); |
| 1028 | scheduler.AddThread(thread); | 1017 | scheduler.AddThread(thread); |
| 1029 | 1018 | ||
| 1030 | thread->host_context = | ||
| 1031 | std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter); | ||
| 1032 | |||
| 1033 | return MakeResult<std::shared_ptr<KThread>>(std::move(thread)); | 1019 | return MakeResult<std::shared_ptr<KThread>>(std::move(thread)); |
| 1034 | } | 1020 | } |
| 1035 | 1021 | ||
| 1022 | ResultVal<std::shared_ptr<KThread>> KThread::CreateThread( | ||
| 1023 | Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority, | ||
| 1024 | u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process, | ||
| 1025 | std::function<void(void*)>&& thread_start_func, void* thread_start_parameter) { | ||
| 1026 | auto thread_result = CreateThread(system, type_flags, name, entry_point, priority, arg, | ||
| 1027 | processor_id, stack_top, owner_process); | ||
| 1028 | |||
| 1029 | if (thread_result.Succeeded()) { | ||
| 1030 | (*thread_result)->host_context = | ||
| 1031 | std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter); | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | return thread_result; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | ResultVal<std::shared_ptr<KThread>> KThread::CreateUserThread( | ||
| 1038 | Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority, | ||
| 1039 | u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process) { | ||
| 1040 | std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc(); | ||
| 1041 | |||
| 1042 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); | ||
| 1043 | |||
| 1044 | return CreateThread(system, type_flags, name, entry_point, priority, arg, processor_id, | ||
| 1045 | stack_top, owner_process, std::move(init_func), init_func_parameter); | ||
| 1046 | } | ||
| 1047 | |||
| 1036 | KThread* GetCurrentThreadPointer(KernelCore& kernel) { | 1048 | KThread* GetCurrentThreadPointer(KernelCore& kernel) { |
| 1037 | return kernel.GetCurrentEmuThread(); | 1049 | return kernel.GetCurrentEmuThread(); |
| 1038 | } | 1050 | } |
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: | |||
| 116 | using WaiterList = boost::intrusive::list<KThread>; | 116 | using WaiterList = boost::intrusive::list<KThread>; |
| 117 | 117 | ||
| 118 | /** | 118 | /** |
| 119 | * Creates and returns a new thread. The new thread is immediately scheduled | 119 | * Creates and returns a new thread. |
| 120 | * @param system The instance of the whole system | 120 | * @param system The instance of the whole system |
| 121 | * @param name The friendly name desired for the thread | 121 | * @param name The friendly name desired for the thread |
| 122 | * @param entry_point The address at which the thread should start execution | 122 | * @param entry_point The address at which the thread should start execution |
| @@ -127,12 +127,12 @@ public: | |||
| 127 | * @param owner_process The parent process for the thread, if null, it's a kernel thread | 127 | * @param owner_process The parent process for the thread, if null, it's a kernel thread |
| 128 | * @return A shared pointer to the newly created thread | 128 | * @return A shared pointer to the newly created thread |
| 129 | */ | 129 | */ |
| 130 | [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> Create( | 130 | [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread( |
| 131 | Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, | 131 | Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, |
| 132 | u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process); | 132 | u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process); |
| 133 | 133 | ||
| 134 | /** | 134 | /** |
| 135 | * Creates and returns a new thread. The new thread is immediately scheduled | 135 | * Creates and returns a new thread, with a specified entry point. |
| 136 | * @param system The instance of the whole system | 136 | * @param system The instance of the whole system |
| 137 | * @param name The friendly name desired for the thread | 137 | * @param name The friendly name desired for the thread |
| 138 | * @param entry_point The address at which the thread should start execution | 138 | * @param entry_point The address at which the thread should start execution |
| @@ -145,11 +145,27 @@ public: | |||
| 145 | * @param thread_start_parameter The parameter which will passed to host context on init | 145 | * @param thread_start_parameter The parameter which will passed to host context on init |
| 146 | * @return A shared pointer to the newly created thread | 146 | * @return A shared pointer to the newly created thread |
| 147 | */ | 147 | */ |
| 148 | [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> Create( | 148 | [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread( |
| 149 | Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, | 149 | Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, |
| 150 | u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process, | 150 | u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process, |
| 151 | std::function<void(void*)>&& thread_start_func, void* thread_start_parameter); | 151 | std::function<void(void*)>&& thread_start_func, void* thread_start_parameter); |
| 152 | 152 | ||
| 153 | /** | ||
| 154 | * Creates and returns a new thread for the emulated "user" process. | ||
| 155 | * @param system The instance of the whole system | ||
| 156 | * @param name The friendly name desired for the thread | ||
| 157 | * @param entry_point The address at which the thread should start execution | ||
| 158 | * @param priority The thread's priority | ||
| 159 | * @param arg User data to pass to the thread | ||
| 160 | * @param processor_id The ID(s) of the processors on which the thread is desired to be run | ||
| 161 | * @param stack_top The address of the thread's stack top | ||
| 162 | * @param owner_process The parent process for the thread, if null, it's a kernel thread | ||
| 163 | * @return A shared pointer to the newly created thread | ||
| 164 | */ | ||
| 165 | [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateUserThread( | ||
| 166 | Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, | ||
| 167 | u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process); | ||
| 168 | |||
| 153 | [[nodiscard]] std::string GetName() const override { | 169 | [[nodiscard]] std::string GetName() const override { |
| 154 | return name; | 170 | return name; |
| 155 | } | 171 | } |
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 { | |||
| 181 | std::string name = "Suspend Thread Id:" + std::to_string(i); | 181 | std::string name = "Suspend Thread Id:" + std::to_string(i); |
| 182 | std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc(); | 182 | std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc(); |
| 183 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); | 183 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); |
| 184 | auto thread_res = KThread::Create(system, ThreadType::HighPriority, std::move(name), 0, | 184 | auto thread_res = KThread::CreateThread( |
| 185 | 0, 0, static_cast<u32>(i), 0, nullptr, | 185 | system, ThreadType::HighPriority, std::move(name), 0, 0, 0, static_cast<u32>(i), 0, |
| 186 | std::move(init_func), init_func_parameter); | 186 | nullptr, std::move(init_func), init_func_parameter); |
| 187 | 187 | ||
| 188 | suspend_threads[i] = std::move(thread_res).Unwrap(); | 188 | suspend_threads[i] = std::move(thread_res).Unwrap(); |
| 189 | } | 189 | } |
| @@ -221,10 +221,9 @@ struct KernelCore::Impl { | |||
| 221 | // Gets the dummy KThread for the caller, allocating a new one if this is the first time | 221 | // Gets the dummy KThread for the caller, allocating a new one if this is the first time |
| 222 | KThread* GetHostDummyThread() { | 222 | KThread* GetHostDummyThread() { |
| 223 | const thread_local auto thread = | 223 | const thread_local auto thread = |
| 224 | KThread::Create( | 224 | KThread::CreateThread( |
| 225 | system, ThreadType::Main, fmt::format("DummyThread:{}", GetHostThreadId()), 0, | 225 | system, ThreadType::Main, fmt::format("DummyThread:{}", GetHostThreadId()), 0, |
| 226 | KThread::DefaultThreadPriority, 0, static_cast<u32>(3), 0, nullptr, | 226 | KThread::DefaultThreadPriority, 0, static_cast<u32>(3), 0, nullptr) |
| 227 | []([[maybe_unused]] void* arg) { UNREACHABLE(); }, nullptr) | ||
| 228 | .Unwrap(); | 227 | .Unwrap(); |
| 229 | return thread.get(); | 228 | return thread.get(); |
| 230 | } | 229 | } |
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 { | |||
| 40 | void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { | 40 | void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { |
| 41 | const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); | 41 | const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); |
| 42 | ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); | 42 | ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); |
| 43 | auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0, | 43 | auto thread_res = |
| 44 | owner_process.GetIdealCoreId(), stack_top, &owner_process); | 44 | KThread::CreateUserThread(system, ThreadType::User, "main", entry_point, priority, 0, |
| 45 | owner_process.GetIdealCoreId(), stack_top, &owner_process); | ||
| 45 | 46 | ||
| 46 | std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap(); | 47 | std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap(); |
| 47 | 48 | ||
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 | |||
| 1532 | std::shared_ptr<KThread> thread; | 1532 | std::shared_ptr<KThread> thread; |
| 1533 | { | 1533 | { |
| 1534 | KScopedLightLock lk{process.GetStateLock()}; | 1534 | KScopedLightLock lk{process.GetStateLock()}; |
| 1535 | CASCADE_RESULT(thread, KThread::Create(system, ThreadType::User, "", entry_point, priority, | 1535 | CASCADE_RESULT(thread, |
| 1536 | arg, core_id, stack_bottom, &process)); | 1536 | KThread::CreateUserThread(system, ThreadType::User, "", entry_point, |
| 1537 | priority, arg, core_id, stack_bottom, &process)); | ||
| 1537 | } | 1538 | } |
| 1538 | 1539 | ||
| 1539 | const auto new_thread_handle = process.GetHandleTable().Create(thread); | 1540 | 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 @@ | |||
| 7 | #include <limits> | 7 | #include <limits> |
| 8 | #include <utility> | 8 | #include <utility> |
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | #include "common/common_funcs.h" | ||
| 10 | 11 | ||
| 11 | #ifdef _WIN32 | 12 | #ifdef _WIN32 |
| 12 | #define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname | 13 | #define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname |
| @@ -90,15 +91,36 @@ LINGER MakeLinger(bool enable, u32 linger_value) { | |||
| 90 | return value; | 91 | return value; |
| 91 | } | 92 | } |
| 92 | 93 | ||
| 93 | int LastError() { | ||
| 94 | return WSAGetLastError(); | ||
| 95 | } | ||
| 96 | |||
| 97 | bool EnableNonBlock(SOCKET fd, bool enable) { | 94 | bool EnableNonBlock(SOCKET fd, bool enable) { |
| 98 | u_long value = enable ? 1 : 0; | 95 | u_long value = enable ? 1 : 0; |
| 99 | return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR; | 96 | return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR; |
| 100 | } | 97 | } |
| 101 | 98 | ||
| 99 | Errno TranslateNativeError(int e) { | ||
| 100 | switch (e) { | ||
| 101 | case WSAEBADF: | ||
| 102 | return Errno::BADF; | ||
| 103 | case WSAEINVAL: | ||
| 104 | return Errno::INVAL; | ||
| 105 | case WSAEMFILE: | ||
| 106 | return Errno::MFILE; | ||
| 107 | case WSAENOTCONN: | ||
| 108 | return Errno::NOTCONN; | ||
| 109 | case WSAEWOULDBLOCK: | ||
| 110 | return Errno::AGAIN; | ||
| 111 | case WSAECONNREFUSED: | ||
| 112 | return Errno::CONNREFUSED; | ||
| 113 | case WSAEHOSTUNREACH: | ||
| 114 | return Errno::HOSTUNREACH; | ||
| 115 | case WSAENETDOWN: | ||
| 116 | return Errno::NETDOWN; | ||
| 117 | case WSAENETUNREACH: | ||
| 118 | return Errno::NETUNREACH; | ||
| 119 | default: | ||
| 120 | return Errno::OTHER; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 102 | #elif YUZU_UNIX // ^ _WIN32 v YUZU_UNIX | 124 | #elif YUZU_UNIX // ^ _WIN32 v YUZU_UNIX |
| 103 | 125 | ||
| 104 | using SOCKET = int; | 126 | using SOCKET = int; |
| @@ -108,9 +130,6 @@ using ULONG = u64; | |||
| 108 | constexpr SOCKET INVALID_SOCKET = -1; | 130 | constexpr SOCKET INVALID_SOCKET = -1; |
| 109 | constexpr SOCKET SOCKET_ERROR = -1; | 131 | constexpr SOCKET SOCKET_ERROR = -1; |
| 110 | 132 | ||
| 111 | constexpr int WSAEWOULDBLOCK = EAGAIN; | ||
| 112 | constexpr int WSAENOTCONN = ENOTCONN; | ||
| 113 | |||
| 114 | constexpr int SD_RECEIVE = SHUT_RD; | 133 | constexpr int SD_RECEIVE = SHUT_RD; |
| 115 | constexpr int SD_SEND = SHUT_WR; | 134 | constexpr int SD_SEND = SHUT_WR; |
| 116 | constexpr int SD_BOTH = SHUT_RDWR; | 135 | constexpr int SD_BOTH = SHUT_RDWR; |
| @@ -162,10 +181,6 @@ linger MakeLinger(bool enable, u32 linger_value) { | |||
| 162 | return value; | 181 | return value; |
| 163 | } | 182 | } |
| 164 | 183 | ||
| 165 | int LastError() { | ||
| 166 | return errno; | ||
| 167 | } | ||
| 168 | |||
| 169 | bool EnableNonBlock(int fd, bool enable) { | 184 | bool EnableNonBlock(int fd, bool enable) { |
| 170 | int flags = fcntl(fd, F_GETFD); | 185 | int flags = fcntl(fd, F_GETFD); |
| 171 | if (flags == -1) { | 186 | if (flags == -1) { |
| @@ -179,8 +194,43 @@ bool EnableNonBlock(int fd, bool enable) { | |||
| 179 | return fcntl(fd, F_SETFD, flags) == 0; | 194 | return fcntl(fd, F_SETFD, flags) == 0; |
| 180 | } | 195 | } |
| 181 | 196 | ||
| 197 | Errno TranslateNativeError(int e) { | ||
| 198 | switch (e) { | ||
| 199 | case EBADF: | ||
| 200 | return Errno::BADF; | ||
| 201 | case EINVAL: | ||
| 202 | return Errno::INVAL; | ||
| 203 | case EMFILE: | ||
| 204 | return Errno::MFILE; | ||
| 205 | case ENOTCONN: | ||
| 206 | return Errno::NOTCONN; | ||
| 207 | case EAGAIN: | ||
| 208 | return Errno::AGAIN; | ||
| 209 | case ECONNREFUSED: | ||
| 210 | return Errno::CONNREFUSED; | ||
| 211 | case EHOSTUNREACH: | ||
| 212 | return Errno::HOSTUNREACH; | ||
| 213 | case ENETDOWN: | ||
| 214 | return Errno::NETDOWN; | ||
| 215 | case ENETUNREACH: | ||
| 216 | return Errno::NETUNREACH; | ||
| 217 | default: | ||
| 218 | return Errno::OTHER; | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 182 | #endif | 222 | #endif |
| 183 | 223 | ||
| 224 | Errno GetAndLogLastError() { | ||
| 225 | #ifdef _WIN32 | ||
| 226 | int e = WSAGetLastError(); | ||
| 227 | #else | ||
| 228 | int e = errno; | ||
| 229 | #endif | ||
| 230 | LOG_ERROR(Network, "Socket operation error: {}", NativeErrorToString(e)); | ||
| 231 | return TranslateNativeError(e); | ||
| 232 | } | ||
| 233 | |||
| 184 | int TranslateDomain(Domain domain) { | 234 | int TranslateDomain(Domain domain) { |
| 185 | switch (domain) { | 235 | switch (domain) { |
| 186 | case Domain::INET: | 236 | case Domain::INET: |
| @@ -290,9 +340,7 @@ Errno SetSockOpt(SOCKET fd, int option, T value) { | |||
| 290 | if (result != SOCKET_ERROR) { | 340 | if (result != SOCKET_ERROR) { |
| 291 | return Errno::SUCCESS; | 341 | return Errno::SUCCESS; |
| 292 | } | 342 | } |
| 293 | const int ec = LastError(); | 343 | return GetAndLogLastError(); |
| 294 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 295 | return Errno::SUCCESS; | ||
| 296 | } | 344 | } |
| 297 | 345 | ||
| 298 | } // Anonymous namespace | 346 | } // Anonymous namespace |
| @@ -308,14 +356,12 @@ NetworkInstance::~NetworkInstance() { | |||
| 308 | std::pair<IPv4Address, Errno> GetHostIPv4Address() { | 356 | std::pair<IPv4Address, Errno> GetHostIPv4Address() { |
| 309 | std::array<char, 256> name{}; | 357 | std::array<char, 256> name{}; |
| 310 | if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) { | 358 | if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) { |
| 311 | UNIMPLEMENTED_MSG("Unhandled gethostname error"); | 359 | return {IPv4Address{}, GetAndLogLastError()}; |
| 312 | return {IPv4Address{}, Errno::SUCCESS}; | ||
| 313 | } | 360 | } |
| 314 | 361 | ||
| 315 | hostent* const ent = gethostbyname(name.data()); | 362 | hostent* const ent = gethostbyname(name.data()); |
| 316 | if (!ent) { | 363 | if (!ent) { |
| 317 | UNIMPLEMENTED_MSG("Unhandled gethostbyname error"); | 364 | return {IPv4Address{}, GetAndLogLastError()}; |
| 318 | return {IPv4Address{}, Errno::SUCCESS}; | ||
| 319 | } | 365 | } |
| 320 | if (ent->h_addr_list == nullptr) { | 366 | if (ent->h_addr_list == nullptr) { |
| 321 | UNIMPLEMENTED_MSG("No addr provided in hostent->h_addr_list"); | 367 | 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) { | |||
| 359 | 405 | ||
| 360 | ASSERT(result == SOCKET_ERROR); | 406 | ASSERT(result == SOCKET_ERROR); |
| 361 | 407 | ||
| 362 | const int ec = LastError(); | 408 | return {-1, GetAndLogLastError()}; |
| 363 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 364 | return {-1, Errno::SUCCESS}; | ||
| 365 | } | 409 | } |
| 366 | 410 | ||
| 367 | Socket::~Socket() { | 411 | Socket::~Socket() { |
| @@ -380,9 +424,7 @@ Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) { | |||
| 380 | return Errno::SUCCESS; | 424 | return Errno::SUCCESS; |
| 381 | } | 425 | } |
| 382 | 426 | ||
| 383 | const int ec = LastError(); | 427 | return GetAndLogLastError(); |
| 384 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 385 | return Errno::SUCCESS; | ||
| 386 | } | 428 | } |
| 387 | 429 | ||
| 388 | std::pair<Socket::AcceptResult, Errno> Socket::Accept() { | 430 | std::pair<Socket::AcceptResult, Errno> Socket::Accept() { |
| @@ -391,9 +433,7 @@ std::pair<Socket::AcceptResult, Errno> Socket::Accept() { | |||
| 391 | const SOCKET new_socket = accept(fd, &addr, &addrlen); | 433 | const SOCKET new_socket = accept(fd, &addr, &addrlen); |
| 392 | 434 | ||
| 393 | if (new_socket == INVALID_SOCKET) { | 435 | if (new_socket == INVALID_SOCKET) { |
| 394 | const int ec = LastError(); | 436 | return {AcceptResult{}, GetAndLogLastError()}; |
| 395 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 396 | return {AcceptResult{}, Errno::SUCCESS}; | ||
| 397 | } | 437 | } |
| 398 | 438 | ||
| 399 | AcceptResult result; | 439 | AcceptResult result; |
| @@ -412,23 +452,14 @@ Errno Socket::Connect(SockAddrIn addr_in) { | |||
| 412 | return Errno::SUCCESS; | 452 | return Errno::SUCCESS; |
| 413 | } | 453 | } |
| 414 | 454 | ||
| 415 | switch (const int ec = LastError()) { | 455 | return GetAndLogLastError(); |
| 416 | case WSAEWOULDBLOCK: | ||
| 417 | LOG_DEBUG(Service, "EAGAIN generated"); | ||
| 418 | return Errno::AGAIN; | ||
| 419 | default: | ||
| 420 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 421 | return Errno::SUCCESS; | ||
| 422 | } | ||
| 423 | } | 456 | } |
| 424 | 457 | ||
| 425 | std::pair<SockAddrIn, Errno> Socket::GetPeerName() { | 458 | std::pair<SockAddrIn, Errno> Socket::GetPeerName() { |
| 426 | sockaddr addr; | 459 | sockaddr addr; |
| 427 | socklen_t addrlen = sizeof(addr); | 460 | socklen_t addrlen = sizeof(addr); |
| 428 | if (getpeername(fd, &addr, &addrlen) == SOCKET_ERROR) { | 461 | if (getpeername(fd, &addr, &addrlen) == SOCKET_ERROR) { |
| 429 | const int ec = LastError(); | 462 | return {SockAddrIn{}, GetAndLogLastError()}; |
| 430 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 431 | return {SockAddrIn{}, Errno::SUCCESS}; | ||
| 432 | } | 463 | } |
| 433 | 464 | ||
| 434 | ASSERT(addrlen == sizeof(sockaddr_in)); | 465 | ASSERT(addrlen == sizeof(sockaddr_in)); |
| @@ -439,9 +470,7 @@ std::pair<SockAddrIn, Errno> Socket::GetSockName() { | |||
| 439 | sockaddr addr; | 470 | sockaddr addr; |
| 440 | socklen_t addrlen = sizeof(addr); | 471 | socklen_t addrlen = sizeof(addr); |
| 441 | if (getsockname(fd, &addr, &addrlen) == SOCKET_ERROR) { | 472 | if (getsockname(fd, &addr, &addrlen) == SOCKET_ERROR) { |
| 442 | const int ec = LastError(); | 473 | return {SockAddrIn{}, GetAndLogLastError()}; |
| 443 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 444 | return {SockAddrIn{}, Errno::SUCCESS}; | ||
| 445 | } | 474 | } |
| 446 | 475 | ||
| 447 | ASSERT(addrlen == sizeof(sockaddr_in)); | 476 | ASSERT(addrlen == sizeof(sockaddr_in)); |
| @@ -454,9 +483,7 @@ Errno Socket::Bind(SockAddrIn addr) { | |||
| 454 | return Errno::SUCCESS; | 483 | return Errno::SUCCESS; |
| 455 | } | 484 | } |
| 456 | 485 | ||
| 457 | const int ec = LastError(); | 486 | return GetAndLogLastError(); |
| 458 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 459 | return Errno::SUCCESS; | ||
| 460 | } | 487 | } |
| 461 | 488 | ||
| 462 | Errno Socket::Listen(s32 backlog) { | 489 | Errno Socket::Listen(s32 backlog) { |
| @@ -464,9 +491,7 @@ Errno Socket::Listen(s32 backlog) { | |||
| 464 | return Errno::SUCCESS; | 491 | return Errno::SUCCESS; |
| 465 | } | 492 | } |
| 466 | 493 | ||
| 467 | const int ec = LastError(); | 494 | return GetAndLogLastError(); |
| 468 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 469 | return Errno::SUCCESS; | ||
| 470 | } | 495 | } |
| 471 | 496 | ||
| 472 | Errno Socket::Shutdown(ShutdownHow how) { | 497 | Errno Socket::Shutdown(ShutdownHow how) { |
| @@ -489,14 +514,7 @@ Errno Socket::Shutdown(ShutdownHow how) { | |||
| 489 | return Errno::SUCCESS; | 514 | return Errno::SUCCESS; |
| 490 | } | 515 | } |
| 491 | 516 | ||
| 492 | switch (const int ec = LastError()) { | 517 | return GetAndLogLastError(); |
| 493 | case WSAENOTCONN: | ||
| 494 | LOG_ERROR(Service, "ENOTCONN generated"); | ||
| 495 | return Errno::NOTCONN; | ||
| 496 | default: | ||
| 497 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 498 | return Errno::SUCCESS; | ||
| 499 | } | ||
| 500 | } | 518 | } |
| 501 | 519 | ||
| 502 | std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) { | 520 | 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) { | |||
| 509 | return {static_cast<s32>(result), Errno::SUCCESS}; | 527 | return {static_cast<s32>(result), Errno::SUCCESS}; |
| 510 | } | 528 | } |
| 511 | 529 | ||
| 512 | switch (const int ec = LastError()) { | 530 | return {-1, GetAndLogLastError()}; |
| 513 | case WSAEWOULDBLOCK: | ||
| 514 | LOG_DEBUG(Service, "EAGAIN generated"); | ||
| 515 | return {-1, Errno::AGAIN}; | ||
| 516 | case WSAENOTCONN: | ||
| 517 | LOG_ERROR(Service, "ENOTCONN generated"); | ||
| 518 | return {-1, Errno::NOTCONN}; | ||
| 519 | default: | ||
| 520 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 521 | return {0, Errno::SUCCESS}; | ||
| 522 | } | ||
| 523 | } | 531 | } |
| 524 | 532 | ||
| 525 | std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) { | 533 | 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 | |||
| 541 | return {static_cast<s32>(result), Errno::SUCCESS}; | 549 | return {static_cast<s32>(result), Errno::SUCCESS}; |
| 542 | } | 550 | } |
| 543 | 551 | ||
| 544 | switch (const int ec = LastError()) { | 552 | return {-1, GetAndLogLastError()}; |
| 545 | case WSAEWOULDBLOCK: | ||
| 546 | LOG_DEBUG(Service, "EAGAIN generated"); | ||
| 547 | return {-1, Errno::AGAIN}; | ||
| 548 | case WSAENOTCONN: | ||
| 549 | LOG_ERROR(Service, "ENOTCONN generated"); | ||
| 550 | return {-1, Errno::NOTCONN}; | ||
| 551 | default: | ||
| 552 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 553 | return {-1, Errno::SUCCESS}; | ||
| 554 | } | ||
| 555 | } | 553 | } |
| 556 | 554 | ||
| 557 | std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) { | 555 | 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) { | |||
| 564 | return {static_cast<s32>(result), Errno::SUCCESS}; | 562 | return {static_cast<s32>(result), Errno::SUCCESS}; |
| 565 | } | 563 | } |
| 566 | 564 | ||
| 567 | const int ec = LastError(); | 565 | return {-1, GetAndLogLastError()}; |
| 568 | switch (ec) { | ||
| 569 | case WSAEWOULDBLOCK: | ||
| 570 | LOG_DEBUG(Service, "EAGAIN generated"); | ||
| 571 | return {-1, Errno::AGAIN}; | ||
| 572 | case WSAENOTCONN: | ||
| 573 | LOG_ERROR(Service, "ENOTCONN generated"); | ||
| 574 | return {-1, Errno::NOTCONN}; | ||
| 575 | default: | ||
| 576 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 577 | return {-1, Errno::SUCCESS}; | ||
| 578 | } | ||
| 579 | } | 566 | } |
| 580 | 567 | ||
| 581 | std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message, | 568 | 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, | |||
| 597 | return {static_cast<s32>(result), Errno::SUCCESS}; | 584 | return {static_cast<s32>(result), Errno::SUCCESS}; |
| 598 | } | 585 | } |
| 599 | 586 | ||
| 600 | const int ec = LastError(); | 587 | return {-1, GetAndLogLastError()}; |
| 601 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 602 | return {-1, Errno::SUCCESS}; | ||
| 603 | } | 588 | } |
| 604 | 589 | ||
| 605 | Errno Socket::Close() { | 590 | Errno Socket::Close() { |
| @@ -642,9 +627,7 @@ Errno Socket::SetNonBlock(bool enable) { | |||
| 642 | if (EnableNonBlock(fd, enable)) { | 627 | if (EnableNonBlock(fd, enable)) { |
| 643 | return Errno::SUCCESS; | 628 | return Errno::SUCCESS; |
| 644 | } | 629 | } |
| 645 | const int ec = LastError(); | 630 | return GetAndLogLastError(); |
| 646 | UNREACHABLE_MSG("Unhandled host socket error={}", ec); | ||
| 647 | return Errno::SUCCESS; | ||
| 648 | } | 631 | } |
| 649 | 632 | ||
| 650 | bool Socket::IsOpened() const { | 633 | 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 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <utility> | 8 | #include <utility> |
| 9 | 9 | ||
| 10 | #include "common/common_funcs.h" | ||
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 11 | 12 | ||
| 12 | namespace Network { | 13 | namespace Network { |
| @@ -21,6 +22,11 @@ enum class Errno { | |||
| 21 | MFILE, | 22 | MFILE, |
| 22 | NOTCONN, | 23 | NOTCONN, |
| 23 | AGAIN, | 24 | AGAIN, |
| 25 | CONNREFUSED, | ||
| 26 | HOSTUNREACH, | ||
| 27 | NETDOWN, | ||
| 28 | NETUNREACH, | ||
| 29 | OTHER, | ||
| 24 | }; | 30 | }; |
| 25 | 31 | ||
| 26 | /// Address families | 32 | /// Address families |
diff --git a/src/input_common/keyboard.cpp b/src/input_common/keyboard.cpp index 24a6f7a33..c467ff4c5 100644 --- a/src/input_common/keyboard.cpp +++ b/src/input_common/keyboard.cpp | |||
| @@ -12,20 +12,39 @@ namespace InputCommon { | |||
| 12 | 12 | ||
| 13 | class KeyButton final : public Input::ButtonDevice { | 13 | class KeyButton final : public Input::ButtonDevice { |
| 14 | public: | 14 | public: |
| 15 | explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_) | 15 | explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_, bool toggle_) |
| 16 | : key_button_list(std::move(key_button_list_)) {} | 16 | : key_button_list(std::move(key_button_list_)), toggle(toggle_) {} |
| 17 | 17 | ||
| 18 | ~KeyButton() override; | 18 | ~KeyButton() override; |
| 19 | 19 | ||
| 20 | bool GetStatus() const override { | 20 | bool GetStatus() const override { |
| 21 | if (toggle) { | ||
| 22 | return toggled_status.load(std::memory_order_relaxed); | ||
| 23 | } | ||
| 21 | return status.load(); | 24 | return status.load(); |
| 22 | } | 25 | } |
| 23 | 26 | ||
| 27 | void ToggleButton() { | ||
| 28 | if (lock) { | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | lock = true; | ||
| 32 | const bool old_toggle_status = toggled_status.load(); | ||
| 33 | toggled_status.store(!old_toggle_status); | ||
| 34 | } | ||
| 35 | |||
| 36 | void UnlockButton() { | ||
| 37 | lock = false; | ||
| 38 | } | ||
| 39 | |||
| 24 | friend class KeyButtonList; | 40 | friend class KeyButtonList; |
| 25 | 41 | ||
| 26 | private: | 42 | private: |
| 27 | std::shared_ptr<KeyButtonList> key_button_list; | 43 | std::shared_ptr<KeyButtonList> key_button_list; |
| 28 | std::atomic<bool> status{false}; | 44 | std::atomic<bool> status{false}; |
| 45 | std::atomic<bool> toggled_status{false}; | ||
| 46 | bool lock{false}; | ||
| 47 | const bool toggle; | ||
| 29 | }; | 48 | }; |
| 30 | 49 | ||
| 31 | struct KeyButtonPair { | 50 | struct KeyButtonPair { |
| @@ -51,6 +70,11 @@ public: | |||
| 51 | for (const KeyButtonPair& pair : list) { | 70 | for (const KeyButtonPair& pair : list) { |
| 52 | if (pair.key_code == key_code) { | 71 | if (pair.key_code == key_code) { |
| 53 | pair.key_button->status.store(pressed); | 72 | pair.key_button->status.store(pressed); |
| 73 | if (pressed) { | ||
| 74 | pair.key_button->ToggleButton(); | ||
| 75 | } else { | ||
| 76 | pair.key_button->UnlockButton(); | ||
| 77 | } | ||
| 54 | } | 78 | } |
| 55 | } | 79 | } |
| 56 | } | 80 | } |
| @@ -75,7 +99,8 @@ KeyButton::~KeyButton() { | |||
| 75 | 99 | ||
| 76 | std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage& params) { | 100 | std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage& params) { |
| 77 | const int key_code = params.Get("code", 0); | 101 | const int key_code = params.Get("code", 0); |
| 78 | std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list); | 102 | const bool toggle = params.Get("toggle", false); |
| 103 | std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list, toggle); | ||
| 79 | key_button_list->AddKeyButton(key_code, button.get()); | 104 | key_button_list->AddKeyButton(key_code, button.get()); |
| 80 | return button; | 105 | return button; |
| 81 | } | 106 | } |
diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp index b864d26f2..329e416c7 100644 --- a/src/input_common/mouse/mouse_input.cpp +++ b/src/input_common/mouse/mouse_input.cpp | |||
| @@ -59,7 +59,7 @@ void Mouse::UpdateYuzuSettings() { | |||
| 59 | }); | 59 | }); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | void Mouse::PressButton(int x, int y, int button_) { | 62 | void Mouse::PressButton(int x, int y, MouseButton button_) { |
| 63 | const auto button_index = static_cast<std::size_t>(button_); | 63 | const auto button_index = static_cast<std::size_t>(button_); |
| 64 | if (button_index >= mouse_info.size()) { | 64 | if (button_index >= mouse_info.size()) { |
| 65 | return; | 65 | return; |
| @@ -67,7 +67,7 @@ void Mouse::PressButton(int x, int y, int button_) { | |||
| 67 | 67 | ||
| 68 | const auto button = 1U << button_index; | 68 | const auto button = 1U << button_index; |
| 69 | buttons |= static_cast<u16>(button); | 69 | buttons |= static_cast<u16>(button); |
| 70 | last_button = static_cast<MouseButton>(button_index); | 70 | last_button = button_; |
| 71 | 71 | ||
| 72 | mouse_info[button_index].mouse_origin = Common::MakeVec(x, y); | 72 | mouse_info[button_index].mouse_origin = Common::MakeVec(x, y); |
| 73 | mouse_info[button_index].last_mouse_position = Common::MakeVec(x, y); | 73 | 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) { | |||
| 129 | } | 129 | } |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | void Mouse::ReleaseButton(int button_) { | 132 | void Mouse::ReleaseButton(MouseButton button_) { |
| 133 | const auto button_index = static_cast<std::size_t>(button_); | 133 | const auto button_index = static_cast<std::size_t>(button_); |
| 134 | if (button_index >= mouse_info.size()) { | 134 | if (button_index >= mouse_info.size()) { |
| 135 | return; | 135 | return; |
| @@ -152,11 +152,52 @@ void Mouse::BeginConfiguration() { | |||
| 152 | 152 | ||
| 153 | void Mouse::EndConfiguration() { | 153 | void Mouse::EndConfiguration() { |
| 154 | buttons = 0; | 154 | buttons = 0; |
| 155 | for (MouseInfo& info : mouse_info) { | ||
| 156 | info.tilt_speed = 0; | ||
| 157 | info.data.pressed = false; | ||
| 158 | info.data.axis = {0, 0}; | ||
| 159 | } | ||
| 155 | last_button = MouseButton::Undefined; | 160 | last_button = MouseButton::Undefined; |
| 156 | mouse_queue.Clear(); | 161 | mouse_queue.Clear(); |
| 157 | configuring = false; | 162 | configuring = false; |
| 158 | } | 163 | } |
| 159 | 164 | ||
| 165 | bool Mouse::ToggleButton(std::size_t button_) { | ||
| 166 | if (button_ >= mouse_info.size()) { | ||
| 167 | return false; | ||
| 168 | } | ||
| 169 | const auto button = 1U << button_; | ||
| 170 | const bool button_state = (toggle_buttons & button) != 0; | ||
| 171 | const bool button_lock = (lock_buttons & button) != 0; | ||
| 172 | |||
| 173 | if (button_lock) { | ||
| 174 | return button_state; | ||
| 175 | } | ||
| 176 | |||
| 177 | lock_buttons |= static_cast<u16>(button); | ||
| 178 | |||
| 179 | if (button_state) { | ||
| 180 | toggle_buttons &= static_cast<u16>(0xFF - button); | ||
| 181 | } else { | ||
| 182 | toggle_buttons |= static_cast<u16>(button); | ||
| 183 | } | ||
| 184 | |||
| 185 | return !button_state; | ||
| 186 | } | ||
| 187 | |||
| 188 | bool Mouse::UnlockButton(std::size_t button_) { | ||
| 189 | if (button_ >= mouse_info.size()) { | ||
| 190 | return false; | ||
| 191 | } | ||
| 192 | |||
| 193 | const auto button = 1U << button_; | ||
| 194 | const bool button_state = (toggle_buttons & button) != 0; | ||
| 195 | |||
| 196 | lock_buttons &= static_cast<u16>(0xFF - button); | ||
| 197 | |||
| 198 | return button_state; | ||
| 199 | } | ||
| 200 | |||
| 160 | Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() { | 201 | Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() { |
| 161 | return mouse_queue; | 202 | return mouse_queue; |
| 162 | } | 203 | } |
diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h index 46aa676c1..750d9b011 100644 --- a/src/input_common/mouse/mouse_input.h +++ b/src/input_common/mouse/mouse_input.h | |||
| @@ -18,10 +18,12 @@ namespace MouseInput { | |||
| 18 | 18 | ||
| 19 | enum class MouseButton { | 19 | enum class MouseButton { |
| 20 | Left, | 20 | Left, |
| 21 | Wheel, | ||
| 22 | Right, | 21 | Right, |
| 23 | Forward, | 22 | Wheel, |
| 24 | Backward, | 23 | Backward, |
| 24 | Forward, | ||
| 25 | Task, | ||
| 26 | Extra, | ||
| 25 | Undefined, | 27 | Undefined, |
| 26 | }; | 28 | }; |
| 27 | 29 | ||
| @@ -51,7 +53,7 @@ public: | |||
| 51 | * @param y the y-coordinate of the cursor | 53 | * @param y the y-coordinate of the cursor |
| 52 | * @param button_ the button pressed | 54 | * @param button_ the button pressed |
| 53 | */ | 55 | */ |
| 54 | void PressButton(int x, int y, int button_); | 56 | void PressButton(int x, int y, MouseButton button_); |
| 55 | 57 | ||
| 56 | /** | 58 | /** |
| 57 | * Signals that mouse has moved. | 59 | * Signals that mouse has moved. |
| @@ -65,7 +67,10 @@ public: | |||
| 65 | /** | 67 | /** |
| 66 | * Signals that a motion sensor tilt has ended. | 68 | * Signals that a motion sensor tilt has ended. |
| 67 | */ | 69 | */ |
| 68 | void ReleaseButton(int button_); | 70 | void ReleaseButton(MouseButton button_); |
| 71 | |||
| 72 | [[nodiscard]] bool ToggleButton(std::size_t button_); | ||
| 73 | [[nodiscard]] bool UnlockButton(std::size_t button_); | ||
| 69 | 74 | ||
| 70 | [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue(); | 75 | [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue(); |
| 71 | [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const; | 76 | [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const; |
| @@ -92,9 +97,11 @@ private: | |||
| 92 | }; | 97 | }; |
| 93 | 98 | ||
| 94 | u16 buttons{}; | 99 | u16 buttons{}; |
| 100 | u16 toggle_buttons{}; | ||
| 101 | u16 lock_buttons{}; | ||
| 95 | std::thread update_thread; | 102 | std::thread update_thread; |
| 96 | MouseButton last_button{MouseButton::Undefined}; | 103 | MouseButton last_button{MouseButton::Undefined}; |
| 97 | std::array<MouseInfo, 5> mouse_info; | 104 | std::array<MouseInfo, 7> mouse_info; |
| 98 | Common::SPSCQueue<MouseStatus> mouse_queue; | 105 | Common::SPSCQueue<MouseStatus> mouse_queue; |
| 99 | bool configuring{false}; | 106 | bool configuring{false}; |
| 100 | bool update_thread_running{true}; | 107 | bool update_thread_running{true}; |
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp index bb56787ee..0e1db54fb 100644 --- a/src/input_common/mouse/mouse_poller.cpp +++ b/src/input_common/mouse/mouse_poller.cpp | |||
| @@ -14,16 +14,25 @@ namespace InputCommon { | |||
| 14 | 14 | ||
| 15 | class MouseButton final : public Input::ButtonDevice { | 15 | class MouseButton final : public Input::ButtonDevice { |
| 16 | public: | 16 | public: |
| 17 | explicit MouseButton(u32 button_, const MouseInput::Mouse* mouse_input_) | 17 | explicit MouseButton(u32 button_, bool toggle_, MouseInput::Mouse* mouse_input_) |
| 18 | : button(button_), mouse_input(mouse_input_) {} | 18 | : button(button_), toggle(toggle_), mouse_input(mouse_input_) {} |
| 19 | 19 | ||
| 20 | bool GetStatus() const override { | 20 | bool GetStatus() const override { |
| 21 | return mouse_input->GetMouseState(button).pressed; | 21 | const bool button_state = mouse_input->GetMouseState(button).pressed; |
| 22 | if (!toggle) { | ||
| 23 | return button_state; | ||
| 24 | } | ||
| 25 | |||
| 26 | if (button_state) { | ||
| 27 | return mouse_input->ToggleButton(button); | ||
| 28 | } | ||
| 29 | return mouse_input->UnlockButton(button); | ||
| 22 | } | 30 | } |
| 23 | 31 | ||
| 24 | private: | 32 | private: |
| 25 | const u32 button; | 33 | const u32 button; |
| 26 | const MouseInput::Mouse* mouse_input; | 34 | const bool toggle; |
| 35 | MouseInput::Mouse* mouse_input; | ||
| 27 | }; | 36 | }; |
| 28 | 37 | ||
| 29 | MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_) | 38 | MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_) |
| @@ -32,8 +41,9 @@ MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_ | |||
| 32 | std::unique_ptr<Input::ButtonDevice> MouseButtonFactory::Create( | 41 | std::unique_ptr<Input::ButtonDevice> MouseButtonFactory::Create( |
| 33 | const Common::ParamPackage& params) { | 42 | const Common::ParamPackage& params) { |
| 34 | const auto button_id = params.Get("button", 0); | 43 | const auto button_id = params.Get("button", 0); |
| 44 | const auto toggle = params.Get("toggle", false); | ||
| 35 | 45 | ||
| 36 | return std::make_unique<MouseButton>(button_id, mouse_input.get()); | 46 | return std::make_unique<MouseButton>(button_id, toggle, mouse_input.get()); |
| 37 | } | 47 | } |
| 38 | 48 | ||
| 39 | Common::ParamPackage MouseButtonFactory::GetNextInput() const { | 49 | Common::ParamPackage MouseButtonFactory::GetNextInput() const { |
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 @@ | |||
| 5 | #include <chrono> | 5 | #include <chrono> |
| 6 | #include <cstring> | 6 | #include <cstring> |
| 7 | #include <functional> | 7 | #include <functional> |
| 8 | #include <random> | ||
| 8 | #include <thread> | 9 | #include <thread> |
| 9 | #include <boost/asio.hpp> | 10 | #include <boost/asio.hpp> |
| 10 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| @@ -26,10 +27,10 @@ class Socket { | |||
| 26 | public: | 27 | public: |
| 27 | using clock = std::chrono::system_clock; | 28 | using clock = std::chrono::system_clock; |
| 28 | 29 | ||
| 29 | explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, u32 client_id_, | 30 | explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, |
| 30 | SocketCallback callback_) | 31 | SocketCallback callback_) |
| 31 | : callback(std::move(callback_)), timer(io_service), | 32 | : callback(std::move(callback_)), timer(io_service), |
| 32 | socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id_), | 33 | socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()), |
| 33 | pad_index(pad_index_) { | 34 | pad_index(pad_index_) { |
| 34 | boost::system::error_code ec{}; | 35 | boost::system::error_code ec{}; |
| 35 | auto ipv4 = boost::asio::ip::make_address_v4(host, ec); | 36 | auto ipv4 = boost::asio::ip::make_address_v4(host, ec); |
| @@ -63,6 +64,11 @@ public: | |||
| 63 | } | 64 | } |
| 64 | 65 | ||
| 65 | private: | 66 | private: |
| 67 | u32 GenerateRandomClientId() const { | ||
| 68 | std::random_device device; | ||
| 69 | return device(); | ||
| 70 | } | ||
| 71 | |||
| 66 | void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) { | 72 | void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) { |
| 67 | if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) { | 73 | if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) { |
| 68 | switch (*type) { | 74 | switch (*type) { |
| @@ -115,7 +121,7 @@ private: | |||
| 115 | boost::asio::basic_waitable_timer<clock> timer; | 121 | boost::asio::basic_waitable_timer<clock> timer; |
| 116 | udp::socket socket; | 122 | udp::socket socket; |
| 117 | 123 | ||
| 118 | u32 client_id{}; | 124 | const u32 client_id; |
| 119 | std::size_t pad_index{}; | 125 | std::size_t pad_index{}; |
| 120 | 126 | ||
| 121 | static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); | 127 | static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); |
| @@ -203,7 +209,7 @@ void Client::ReloadSockets() { | |||
| 203 | LOG_ERROR(Input, "Duplicated UDP servers found"); | 209 | LOG_ERROR(Input, "Duplicated UDP servers found"); |
| 204 | continue; | 210 | continue; |
| 205 | } | 211 | } |
| 206 | StartCommunication(client++, udp_input_address, udp_input_port, pad, 24872); | 212 | StartCommunication(client++, udp_input_address, udp_input_port, pad); |
| 207 | } | 213 | } |
| 208 | } | 214 | } |
| 209 | } | 215 | } |
| @@ -277,7 +283,7 @@ void Client::OnPadData(Response::PadData data, std::size_t client) { | |||
| 277 | } | 283 | } |
| 278 | 284 | ||
| 279 | void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, | 285 | void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, |
| 280 | std::size_t pad_index, u32 client_id) { | 286 | std::size_t pad_index) { |
| 281 | SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, | 287 | SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, |
| 282 | [this](Response::PortInfo info) { OnPortInfo(info); }, | 288 | [this](Response::PortInfo info) { OnPortInfo(info); }, |
| 283 | [this, client](Response::PadData data) { OnPadData(data, client); }}; | 289 | [this, client](Response::PadData data) { OnPadData(data, client); }}; |
| @@ -287,7 +293,7 @@ void Client::StartCommunication(std::size_t client, const std::string& host, u16 | |||
| 287 | clients[client].port = port; | 293 | clients[client].port = port; |
| 288 | clients[client].pad_index = pad_index; | 294 | clients[client].pad_index = pad_index; |
| 289 | clients[client].active = 0; | 295 | clients[client].active = 0; |
| 290 | clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback); | 296 | clients[client].socket = std::make_unique<Socket>(host, port, pad_index, callback); |
| 291 | clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; | 297 | clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; |
| 292 | // Set motion parameters | 298 | // Set motion parameters |
| 293 | // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode | 299 | // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode |
| @@ -416,7 +422,7 @@ const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const { | |||
| 416 | return pad_queue; | 422 | return pad_queue; |
| 417 | } | 423 | } |
| 418 | 424 | ||
| 419 | void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, | 425 | void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, |
| 420 | const std::function<void()>& success_callback, | 426 | const std::function<void()>& success_callback, |
| 421 | const std::function<void()>& failure_callback) { | 427 | const std::function<void()>& failure_callback) { |
| 422 | std::thread([=] { | 428 | std::thread([=] { |
| @@ -426,7 +432,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, | |||
| 426 | .port_info = [](Response::PortInfo) {}, | 432 | .port_info = [](Response::PortInfo) {}, |
| 427 | .pad_data = [&](Response::PadData) { success_event.Set(); }, | 433 | .pad_data = [&](Response::PadData) { success_event.Set(); }, |
| 428 | }; | 434 | }; |
| 429 | Socket socket{host, port, pad_index, client_id, std::move(callback)}; | 435 | Socket socket{host, port, pad_index, std::move(callback)}; |
| 430 | std::thread worker_thread{SocketLoop, &socket}; | 436 | std::thread worker_thread{SocketLoop, &socket}; |
| 431 | const bool result = success_event.WaitFor(std::chrono::seconds(5)); | 437 | const bool result = success_event.WaitFor(std::chrono::seconds(5)); |
| 432 | socket.Stop(); | 438 | socket.Stop(); |
| @@ -440,7 +446,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, | |||
| 440 | } | 446 | } |
| 441 | 447 | ||
| 442 | CalibrationConfigurationJob::CalibrationConfigurationJob( | 448 | CalibrationConfigurationJob::CalibrationConfigurationJob( |
| 443 | const std::string& host, u16 port, std::size_t pad_index, u32 client_id, | 449 | const std::string& host, u16 port, std::size_t pad_index, |
| 444 | std::function<void(Status)> status_callback, | 450 | std::function<void(Status)> status_callback, |
| 445 | std::function<void(u16, u16, u16, u16)> data_callback) { | 451 | std::function<void(u16, u16, u16, u16)> data_callback) { |
| 446 | 452 | ||
| @@ -485,7 +491,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( | |||
| 485 | complete_event.Set(); | 491 | complete_event.Set(); |
| 486 | } | 492 | } |
| 487 | }}; | 493 | }}; |
| 488 | Socket socket{host, port, pad_index, client_id, std::move(callback)}; | 494 | Socket socket{host, port, pad_index, std::move(callback)}; |
| 489 | std::thread worker_thread{SocketLoop, &socket}; | 495 | std::thread worker_thread{SocketLoop, &socket}; |
| 490 | complete_event.Wait(); | 496 | complete_event.Wait(); |
| 491 | socket.Stop(); | 497 | 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: | |||
| 126 | void OnPortInfo(Response::PortInfo); | 126 | void OnPortInfo(Response::PortInfo); |
| 127 | void OnPadData(Response::PadData, std::size_t client); | 127 | void OnPadData(Response::PadData, std::size_t client); |
| 128 | void StartCommunication(std::size_t client, const std::string& host, u16 port, | 128 | void StartCommunication(std::size_t client, const std::string& host, u16 port, |
| 129 | std::size_t pad_index, u32 client_id); | 129 | std::size_t pad_index); |
| 130 | void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, | 130 | void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, |
| 131 | const Common::Vec3<float>& gyro); | 131 | const Common::Vec3<float>& gyro); |
| 132 | 132 | ||
| @@ -165,7 +165,7 @@ public: | |||
| 165 | * @param data_callback Called when calibration data is ready | 165 | * @param data_callback Called when calibration data is ready |
| 166 | */ | 166 | */ |
| 167 | explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index, | 167 | explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index, |
| 168 | u32 client_id, std::function<void(Status)> status_callback, | 168 | std::function<void(Status)> status_callback, |
| 169 | std::function<void(u16, u16, u16, u16)> data_callback); | 169 | std::function<void(u16, u16, u16, u16)> data_callback); |
| 170 | ~CalibrationConfigurationJob(); | 170 | ~CalibrationConfigurationJob(); |
| 171 | void Stop(); | 171 | void Stop(); |
| @@ -174,7 +174,7 @@ private: | |||
| 174 | Common::Event complete_event; | 174 | Common::Event complete_event; |
| 175 | }; | 175 | }; |
| 176 | 176 | ||
| 177 | void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, | 177 | void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, |
| 178 | const std::function<void()>& success_callback, | 178 | const std::function<void()>& success_callback, |
| 179 | const std::function<void()>& failure_callback); | 179 | const std::function<void()>& failure_callback); |
| 180 | 180 | ||
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 | |||
| 5 | common/param_package.cpp | 5 | common/param_package.cpp |
| 6 | common/ring_buffer.cpp | 6 | common/ring_buffer.cpp |
| 7 | core/core_timing.cpp | 7 | core/core_timing.cpp |
| 8 | core/network/network.cpp | ||
| 8 | tests.cpp | 9 | tests.cpp |
| 9 | video_core/buffer_base.cpp | 10 | video_core/buffer_base.cpp |
| 10 | ) | 11 | ) |
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() { | |||
| 67 | value++; | 67 | value++; |
| 68 | } | 68 | } |
| 69 | results[id] = value; | 69 | results[id] = value; |
| 70 | Fiber::YieldTo(work_fibers[id], thread_fibers[id]); | 70 | Fiber::YieldTo(work_fibers[id], *thread_fibers[id]); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | void TestControl1::ExecuteThread(u32 id) { | 73 | void TestControl1::ExecuteThread(u32 id) { |
| @@ -76,7 +76,7 @@ void TestControl1::ExecuteThread(u32 id) { | |||
| 76 | thread_fibers[id] = thread_fiber; | 76 | thread_fibers[id] = thread_fiber; |
| 77 | work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this); | 77 | work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this); |
| 78 | items[id] = rand() % 256; | 78 | items[id] = rand() % 256; |
| 79 | Fiber::YieldTo(thread_fibers[id], work_fibers[id]); | 79 | Fiber::YieldTo(thread_fibers[id], *work_fibers[id]); |
| 80 | thread_fibers[id]->Exit(); | 80 | thread_fibers[id]->Exit(); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| @@ -117,11 +117,11 @@ public: | |||
| 117 | for (u32 i = 0; i < 12000; i++) { | 117 | for (u32 i = 0; i < 12000; i++) { |
| 118 | value1 += i; | 118 | value1 += i; |
| 119 | } | 119 | } |
| 120 | Fiber::YieldTo(fiber1, fiber3); | 120 | Fiber::YieldTo(fiber1, *fiber3); |
| 121 | const u32 id = thread_ids.Get(); | 121 | const u32 id = thread_ids.Get(); |
| 122 | assert1 = id == 1; | 122 | assert1 = id == 1; |
| 123 | value2 += 5000; | 123 | value2 += 5000; |
| 124 | Fiber::YieldTo(fiber1, thread_fibers[id]); | 124 | Fiber::YieldTo(fiber1, *thread_fibers[id]); |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | void DoWork2() { | 127 | void DoWork2() { |
| @@ -129,7 +129,7 @@ public: | |||
| 129 | ; | 129 | ; |
| 130 | value2 = 2000; | 130 | value2 = 2000; |
| 131 | trap = false; | 131 | trap = false; |
| 132 | Fiber::YieldTo(fiber2, fiber1); | 132 | Fiber::YieldTo(fiber2, *fiber1); |
| 133 | assert3 = false; | 133 | assert3 = false; |
| 134 | } | 134 | } |
| 135 | 135 | ||
| @@ -137,19 +137,19 @@ public: | |||
| 137 | const u32 id = thread_ids.Get(); | 137 | const u32 id = thread_ids.Get(); |
| 138 | assert2 = id == 0; | 138 | assert2 = id == 0; |
| 139 | value1 += 1000; | 139 | value1 += 1000; |
| 140 | Fiber::YieldTo(fiber3, thread_fibers[id]); | 140 | Fiber::YieldTo(fiber3, *thread_fibers[id]); |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | void ExecuteThread(u32 id); | 143 | void ExecuteThread(u32 id); |
| 144 | 144 | ||
| 145 | void CallFiber1() { | 145 | void CallFiber1() { |
| 146 | const u32 id = thread_ids.Get(); | 146 | const u32 id = thread_ids.Get(); |
| 147 | Fiber::YieldTo(thread_fibers[id], fiber1); | 147 | Fiber::YieldTo(thread_fibers[id], *fiber1); |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | void CallFiber2() { | 150 | void CallFiber2() { |
| 151 | const u32 id = thread_ids.Get(); | 151 | const u32 id = thread_ids.Get(); |
| 152 | Fiber::YieldTo(thread_fibers[id], fiber2); | 152 | Fiber::YieldTo(thread_fibers[id], *fiber2); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | void Exit(); | 155 | void Exit(); |
| @@ -241,23 +241,23 @@ public: | |||
| 241 | 241 | ||
| 242 | void DoWork1() { | 242 | void DoWork1() { |
| 243 | value1 += 1; | 243 | value1 += 1; |
| 244 | Fiber::YieldTo(fiber1, fiber2); | 244 | Fiber::YieldTo(fiber1, *fiber2); |
| 245 | const u32 id = thread_ids.Get(); | 245 | const u32 id = thread_ids.Get(); |
| 246 | value3 += 1; | 246 | value3 += 1; |
| 247 | Fiber::YieldTo(fiber1, thread_fibers[id]); | 247 | Fiber::YieldTo(fiber1, *thread_fibers[id]); |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | void DoWork2() { | 250 | void DoWork2() { |
| 251 | value2 += 1; | 251 | value2 += 1; |
| 252 | const u32 id = thread_ids.Get(); | 252 | const u32 id = thread_ids.Get(); |
| 253 | Fiber::YieldTo(fiber2, thread_fibers[id]); | 253 | Fiber::YieldTo(fiber2, *thread_fibers[id]); |
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | void ExecuteThread(u32 id); | 256 | void ExecuteThread(u32 id); |
| 257 | 257 | ||
| 258 | void CallFiber1() { | 258 | void CallFiber1() { |
| 259 | const u32 id = thread_ids.Get(); | 259 | const u32 id = thread_ids.Get(); |
| 260 | Fiber::YieldTo(thread_fibers[id], fiber1); | 260 | Fiber::YieldTo(thread_fibers[id], *fiber1); |
| 261 | } | 261 | } |
| 262 | 262 | ||
| 263 | void Exit(); | 263 | void Exit(); |
| @@ -332,7 +332,7 @@ public: | |||
| 332 | 332 | ||
| 333 | void Execute() { | 333 | void Execute() { |
| 334 | thread_fiber = Fiber::ThreadToFiber(); | 334 | thread_fiber = Fiber::ThreadToFiber(); |
| 335 | Fiber::YieldTo(thread_fiber, fiber1); | 335 | Fiber::YieldTo(thread_fiber, *fiber1); |
| 336 | thread_fiber->Exit(); | 336 | thread_fiber->Exit(); |
| 337 | } | 337 | } |
| 338 | 338 | ||
| @@ -340,7 +340,7 @@ public: | |||
| 340 | fiber1->SetRewindPoint(std::function<void(void*)>{WorkControl4}, this); | 340 | fiber1->SetRewindPoint(std::function<void(void*)>{WorkControl4}, this); |
| 341 | if (rewinded) { | 341 | if (rewinded) { |
| 342 | goal_reached = true; | 342 | goal_reached = true; |
| 343 | Fiber::YieldTo(fiber1, thread_fiber); | 343 | Fiber::YieldTo(fiber1, *thread_fiber); |
| 344 | } | 344 | } |
| 345 | rewinded = true; | 345 | rewinded = true; |
| 346 | fiber1->Rewind(); | 346 | 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 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <catch2/catch.hpp> | ||
| 6 | |||
| 7 | #include "core/network/network.h" | ||
| 8 | #include "core/network/sockets.h" | ||
| 9 | |||
| 10 | TEST_CASE("Network::Errors", "[core]") { | ||
| 11 | Network::NetworkInstance network_instance; // initialize network | ||
| 12 | |||
| 13 | Network::Socket socks[2]; | ||
| 14 | for (Network::Socket& sock : socks) { | ||
| 15 | REQUIRE(sock.Initialize(Network::Domain::INET, Network::Type::STREAM, | ||
| 16 | Network::Protocol::TCP) == Network::Errno::SUCCESS); | ||
| 17 | } | ||
| 18 | |||
| 19 | Network::SockAddrIn addr{ | ||
| 20 | Network::Domain::INET, | ||
| 21 | {127, 0, 0, 1}, | ||
| 22 | 1, // hopefully nobody running this test has something listening on port 1 | ||
| 23 | }; | ||
| 24 | REQUIRE(socks[0].Connect(addr) == Network::Errno::CONNREFUSED); | ||
| 25 | |||
| 26 | std::vector<u8> message{1, 2, 3, 4}; | ||
| 27 | REQUIRE(socks[1].Recv(0, message).second == Network::Errno::NOTCONN); | ||
| 28 | } | ||
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 2a6844ab1..4de1e37e5 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <deque> | 9 | #include <deque> |
| 10 | #include <memory> | 10 | #include <memory> |
| 11 | #include <mutex> | 11 | #include <mutex> |
| 12 | #include <numeric> | ||
| 12 | #include <span> | 13 | #include <span> |
| 13 | #include <unordered_map> | 14 | #include <unordered_map> |
| 14 | #include <vector> | 15 | #include <vector> |
| @@ -91,7 +92,7 @@ class BufferCache { | |||
| 91 | }; | 92 | }; |
| 92 | 93 | ||
| 93 | public: | 94 | public: |
| 94 | static constexpr u32 SKIP_CACHE_SIZE = 4096; | 95 | static constexpr u32 DEFAULT_SKIP_CACHE_SIZE = 4096; |
| 95 | 96 | ||
| 96 | explicit BufferCache(VideoCore::RasterizerInterface& rasterizer_, | 97 | explicit BufferCache(VideoCore::RasterizerInterface& rasterizer_, |
| 97 | Tegra::Engines::Maxwell3D& maxwell3d_, | 98 | Tegra::Engines::Maxwell3D& maxwell3d_, |
| @@ -240,9 +241,9 @@ private: | |||
| 240 | template <bool insert> | 241 | template <bool insert> |
| 241 | void ChangeRegister(BufferId buffer_id); | 242 | void ChangeRegister(BufferId buffer_id); |
| 242 | 243 | ||
| 243 | void SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size); | 244 | bool SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size); |
| 244 | 245 | ||
| 245 | void SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 size); | 246 | bool SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 size); |
| 246 | 247 | ||
| 247 | void UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy, | 248 | void UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy, |
| 248 | std::span<BufferCopy> copies); | 249 | std::span<BufferCopy> copies); |
| @@ -297,6 +298,11 @@ private: | |||
| 297 | 298 | ||
| 298 | std::array<u32, NUM_STAGES> fast_bound_uniform_buffers{}; | 299 | std::array<u32, NUM_STAGES> fast_bound_uniform_buffers{}; |
| 299 | 300 | ||
| 301 | std::array<u32, 16> uniform_cache_hits{}; | ||
| 302 | std::array<u32, 16> uniform_cache_shots{}; | ||
| 303 | |||
| 304 | u32 uniform_buffer_skip_cache_size = DEFAULT_SKIP_CACHE_SIZE; | ||
| 305 | |||
| 300 | bool has_deleted_buffers = false; | 306 | bool has_deleted_buffers = false; |
| 301 | 307 | ||
| 302 | std::conditional_t<HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS, std::array<u32, NUM_STAGES>, Empty> | 308 | std::conditional_t<HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS, std::array<u32, NUM_STAGES>, Empty> |
| @@ -328,6 +334,19 @@ BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_, | |||
| 328 | 334 | ||
| 329 | template <class P> | 335 | template <class P> |
| 330 | void BufferCache<P>::TickFrame() { | 336 | void BufferCache<P>::TickFrame() { |
| 337 | // Calculate hits and shots and move hit bits to the right | ||
| 338 | const u32 hits = std::reduce(uniform_cache_hits.begin(), uniform_cache_hits.end()); | ||
| 339 | const u32 shots = std::reduce(uniform_cache_shots.begin(), uniform_cache_shots.end()); | ||
| 340 | std::copy_n(uniform_cache_hits.begin(), uniform_cache_hits.size() - 1, | ||
| 341 | uniform_cache_hits.begin() + 1); | ||
| 342 | std::copy_n(uniform_cache_shots.begin(), uniform_cache_shots.size() - 1, | ||
| 343 | uniform_cache_shots.begin() + 1); | ||
| 344 | uniform_cache_hits[0] = 0; | ||
| 345 | uniform_cache_shots[0] = 0; | ||
| 346 | |||
| 347 | const bool skip_preferred = hits * 256 < shots * 251; | ||
| 348 | uniform_buffer_skip_cache_size = skip_preferred ? DEFAULT_SKIP_CACHE_SIZE : 0; | ||
| 349 | |||
| 331 | delayed_destruction_ring.Tick(); | 350 | delayed_destruction_ring.Tick(); |
| 332 | } | 351 | } |
| 333 | 352 | ||
| @@ -671,7 +690,7 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 | |||
| 671 | const VAddr cpu_addr = binding.cpu_addr; | 690 | const VAddr cpu_addr = binding.cpu_addr; |
| 672 | const u32 size = binding.size; | 691 | const u32 size = binding.size; |
| 673 | Buffer& buffer = slot_buffers[binding.buffer_id]; | 692 | Buffer& buffer = slot_buffers[binding.buffer_id]; |
| 674 | if (size <= SKIP_CACHE_SIZE && !buffer.IsRegionGpuModified(cpu_addr, size)) { | 693 | if (size <= uniform_buffer_skip_cache_size && !buffer.IsRegionGpuModified(cpu_addr, size)) { |
| 675 | if constexpr (IS_OPENGL) { | 694 | if constexpr (IS_OPENGL) { |
| 676 | if (runtime.HasFastBufferSubData()) { | 695 | if (runtime.HasFastBufferSubData()) { |
| 677 | // Fast path for Nvidia | 696 | // Fast path for Nvidia |
| @@ -692,7 +711,12 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 | |||
| 692 | return; | 711 | return; |
| 693 | } | 712 | } |
| 694 | // Classic cached path | 713 | // Classic cached path |
| 695 | SynchronizeBuffer(buffer, cpu_addr, size); | 714 | const bool sync_cached = SynchronizeBuffer(buffer, cpu_addr, size); |
| 715 | if (sync_cached) { | ||
| 716 | ++uniform_cache_hits[0]; | ||
| 717 | } | ||
| 718 | ++uniform_cache_shots[0]; | ||
| 719 | |||
| 696 | if (!needs_bind && !HasFastUniformBufferBound(stage, binding_index)) { | 720 | if (!needs_bind && !HasFastUniformBufferBound(stage, binding_index)) { |
| 697 | // Skip binding if it's not needed and if the bound buffer is not the fast version | 721 | // Skip binding if it's not needed and if the bound buffer is not the fast version |
| 698 | // This exists to avoid instances where the fast buffer is bound and a GPU write happens | 722 | // This exists to avoid instances where the fast buffer is bound and a GPU write happens |
| @@ -1106,15 +1130,15 @@ void BufferCache<P>::ChangeRegister(BufferId buffer_id) { | |||
| 1106 | } | 1130 | } |
| 1107 | 1131 | ||
| 1108 | template <class P> | 1132 | template <class P> |
| 1109 | void BufferCache<P>::SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size) { | 1133 | bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size) { |
| 1110 | if (buffer.CpuAddr() == 0) { | 1134 | if (buffer.CpuAddr() == 0) { |
| 1111 | return; | 1135 | return true; |
| 1112 | } | 1136 | } |
| 1113 | SynchronizeBufferImpl(buffer, cpu_addr, size); | 1137 | return SynchronizeBufferImpl(buffer, cpu_addr, size); |
| 1114 | } | 1138 | } |
| 1115 | 1139 | ||
| 1116 | template <class P> | 1140 | template <class P> |
| 1117 | void BufferCache<P>::SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 size) { | 1141 | bool BufferCache<P>::SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 size) { |
| 1118 | boost::container::small_vector<BufferCopy, 4> copies; | 1142 | boost::container::small_vector<BufferCopy, 4> copies; |
| 1119 | u64 total_size_bytes = 0; | 1143 | u64 total_size_bytes = 0; |
| 1120 | u64 largest_copy = 0; | 1144 | u64 largest_copy = 0; |
| @@ -1128,10 +1152,11 @@ void BufferCache<P>::SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 s | |||
| 1128 | largest_copy = std::max(largest_copy, range_size); | 1152 | largest_copy = std::max(largest_copy, range_size); |
| 1129 | }); | 1153 | }); |
| 1130 | if (total_size_bytes == 0) { | 1154 | if (total_size_bytes == 0) { |
| 1131 | return; | 1155 | return true; |
| 1132 | } | 1156 | } |
| 1133 | const std::span<BufferCopy> copies_span(copies.data(), copies.size()); | 1157 | const std::span<BufferCopy> copies_span(copies.data(), copies.size()); |
| 1134 | UploadMemory(buffer, total_size_bytes, largest_copy, copies_span); | 1158 | UploadMemory(buffer, total_size_bytes, largest_copy, copies_span); |
| 1159 | return false; | ||
| 1135 | } | 1160 | } |
| 1136 | 1161 | ||
| 1137 | template <class P> | 1162 | template <class P> |
diff --git a/src/video_core/compatible_formats.cpp b/src/video_core/compatible_formats.cpp index acf2668dc..8317d0636 100644 --- a/src/video_core/compatible_formats.cpp +++ b/src/video_core/compatible_formats.cpp | |||
| @@ -48,6 +48,15 @@ constexpr std::array VIEW_CLASS_32_BITS{ | |||
| 48 | PixelFormat::A2B10G10R10_UINT, | 48 | PixelFormat::A2B10G10R10_UINT, |
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | constexpr std::array VIEW_CLASS_32_BITS_NO_BGR{ | ||
| 52 | PixelFormat::R16G16_FLOAT, PixelFormat::B10G11R11_FLOAT, PixelFormat::R32_FLOAT, | ||
| 53 | PixelFormat::A2B10G10R10_UNORM, PixelFormat::R16G16_UINT, PixelFormat::R32_UINT, | ||
| 54 | PixelFormat::R16G16_SINT, PixelFormat::R32_SINT, PixelFormat::A8B8G8R8_UNORM, | ||
| 55 | PixelFormat::R16G16_UNORM, PixelFormat::A8B8G8R8_SNORM, PixelFormat::R16G16_SNORM, | ||
| 56 | PixelFormat::A8B8G8R8_SRGB, PixelFormat::E5B9G9R9_FLOAT, PixelFormat::A8B8G8R8_UINT, | ||
| 57 | PixelFormat::A8B8G8R8_SINT, PixelFormat::A2B10G10R10_UINT, | ||
| 58 | }; | ||
| 59 | |||
| 51 | // TODO: How should we handle 24 bits? | 60 | // TODO: How should we handle 24 bits? |
| 52 | 61 | ||
| 53 | constexpr std::array VIEW_CLASS_16_BITS{ | 62 | constexpr std::array VIEW_CLASS_16_BITS{ |
| @@ -205,7 +214,6 @@ constexpr Table MakeViewTable() { | |||
| 205 | EnableRange(view, VIEW_CLASS_128_BITS); | 214 | EnableRange(view, VIEW_CLASS_128_BITS); |
| 206 | EnableRange(view, VIEW_CLASS_96_BITS); | 215 | EnableRange(view, VIEW_CLASS_96_BITS); |
| 207 | EnableRange(view, VIEW_CLASS_64_BITS); | 216 | EnableRange(view, VIEW_CLASS_64_BITS); |
| 208 | EnableRange(view, VIEW_CLASS_32_BITS); | ||
| 209 | EnableRange(view, VIEW_CLASS_16_BITS); | 217 | EnableRange(view, VIEW_CLASS_16_BITS); |
| 210 | EnableRange(view, VIEW_CLASS_8_BITS); | 218 | EnableRange(view, VIEW_CLASS_8_BITS); |
| 211 | EnableRange(view, VIEW_CLASS_RGTC1_RED); | 219 | EnableRange(view, VIEW_CLASS_RGTC1_RED); |
| @@ -231,20 +239,47 @@ constexpr Table MakeCopyTable() { | |||
| 231 | EnableRange(copy, COPY_CLASS_64_BITS); | 239 | EnableRange(copy, COPY_CLASS_64_BITS); |
| 232 | return copy; | 240 | return copy; |
| 233 | } | 241 | } |
| 242 | |||
| 243 | constexpr Table MakeNativeBgrViewTable() { | ||
| 244 | Table copy = MakeViewTable(); | ||
| 245 | EnableRange(copy, VIEW_CLASS_32_BITS); | ||
| 246 | return copy; | ||
| 247 | } | ||
| 248 | |||
| 249 | constexpr Table MakeNonNativeBgrViewTable() { | ||
| 250 | Table copy = MakeViewTable(); | ||
| 251 | EnableRange(copy, VIEW_CLASS_32_BITS_NO_BGR); | ||
| 252 | return copy; | ||
| 253 | } | ||
| 254 | |||
| 255 | constexpr Table MakeNativeBgrCopyTable() { | ||
| 256 | Table copy = MakeCopyTable(); | ||
| 257 | EnableRange(copy, VIEW_CLASS_32_BITS); | ||
| 258 | return copy; | ||
| 259 | } | ||
| 260 | |||
| 261 | constexpr Table MakeNonNativeBgrCopyTable() { | ||
| 262 | Table copy = MakeCopyTable(); | ||
| 263 | EnableRange(copy, VIEW_CLASS_32_BITS); | ||
| 264 | return copy; | ||
| 265 | } | ||
| 234 | } // Anonymous namespace | 266 | } // Anonymous namespace |
| 235 | 267 | ||
| 236 | bool IsViewCompatible(PixelFormat format_a, PixelFormat format_b, bool broken_views) { | 268 | bool IsViewCompatible(PixelFormat format_a, PixelFormat format_b, bool broken_views, |
| 269 | bool native_bgr) { | ||
| 237 | if (broken_views) { | 270 | if (broken_views) { |
| 238 | // If format views are broken, only accept formats that are identical. | 271 | // If format views are broken, only accept formats that are identical. |
| 239 | return format_a == format_b; | 272 | return format_a == format_b; |
| 240 | } | 273 | } |
| 241 | static constexpr Table TABLE = MakeViewTable(); | 274 | static constexpr Table BGR_TABLE = MakeNativeBgrViewTable(); |
| 242 | return IsSupported(TABLE, format_a, format_b); | 275 | static constexpr Table NO_BGR_TABLE = MakeNonNativeBgrViewTable(); |
| 276 | return IsSupported(native_bgr ? BGR_TABLE : NO_BGR_TABLE, format_a, format_b); | ||
| 243 | } | 277 | } |
| 244 | 278 | ||
| 245 | bool IsCopyCompatible(PixelFormat format_a, PixelFormat format_b) { | 279 | bool IsCopyCompatible(PixelFormat format_a, PixelFormat format_b, bool native_bgr) { |
| 246 | static constexpr Table TABLE = MakeCopyTable(); | 280 | static constexpr Table BGR_TABLE = MakeNativeBgrCopyTable(); |
| 247 | return IsSupported(TABLE, format_a, format_b); | 281 | static constexpr Table NO_BGR_TABLE = MakeNonNativeBgrCopyTable(); |
| 282 | return IsSupported(native_bgr ? BGR_TABLE : NO_BGR_TABLE, format_a, format_b); | ||
| 248 | } | 283 | } |
| 249 | 284 | ||
| 250 | } // namespace VideoCore::Surface | 285 | } // namespace VideoCore::Surface |
diff --git a/src/video_core/compatible_formats.h b/src/video_core/compatible_formats.h index 9a0522988..55745e042 100644 --- a/src/video_core/compatible_formats.h +++ b/src/video_core/compatible_formats.h | |||
| @@ -8,8 +8,9 @@ | |||
| 8 | 8 | ||
| 9 | namespace VideoCore::Surface { | 9 | namespace VideoCore::Surface { |
| 10 | 10 | ||
| 11 | bool IsViewCompatible(PixelFormat format_a, PixelFormat format_b, bool broken_views); | 11 | bool IsViewCompatible(PixelFormat format_a, PixelFormat format_b, bool broken_views, |
| 12 | bool native_bgr); | ||
| 12 | 13 | ||
| 13 | bool IsCopyCompatible(PixelFormat format_a, PixelFormat format_b); | 14 | bool IsCopyCompatible(PixelFormat format_a, PixelFormat format_b, bool native_bgr); |
| 14 | 15 | ||
| 15 | } // namespace VideoCore::Surface | 16 | } // namespace VideoCore::Surface |
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 970120acc..3494318ca 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt | |||
| @@ -5,6 +5,7 @@ set(SHADER_FILES | |||
| 5 | convert_float_to_depth.frag | 5 | convert_float_to_depth.frag |
| 6 | full_screen_triangle.vert | 6 | full_screen_triangle.vert |
| 7 | opengl_copy_bc4.comp | 7 | opengl_copy_bc4.comp |
| 8 | opengl_copy_bgra.comp | ||
| 8 | opengl_present.frag | 9 | opengl_present.frag |
| 9 | opengl_present.vert | 10 | opengl_present.vert |
| 10 | pitch_unswizzle.comp | 11 | pitch_unswizzle.comp |
diff --git a/src/video_core/host_shaders/opengl_copy_bgra.comp b/src/video_core/host_shaders/opengl_copy_bgra.comp new file mode 100644 index 000000000..2571a4abf --- /dev/null +++ b/src/video_core/host_shaders/opengl_copy_bgra.comp | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #version 430 core | ||
| 6 | |||
| 7 | layout (local_size_x = 4, local_size_y = 4) in; | ||
| 8 | |||
| 9 | layout(binding = 0, rgba8) readonly uniform image2DArray bgr_input; | ||
| 10 | layout(binding = 1, rgba8) writeonly uniform image2DArray bgr_output; | ||
| 11 | |||
| 12 | void main() { | ||
| 13 | vec4 color = imageLoad(bgr_input, ivec3(gl_GlobalInvocationID)); | ||
| 14 | imageStore(bgr_output, ivec3(gl_GlobalInvocationID), color.bgra); | ||
| 15 | } | ||
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index 6da3906a4..c225d1fc9 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp | |||
| @@ -73,7 +73,8 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_) | |||
| 73 | for (auto& stage_uniforms : fast_uniforms) { | 73 | for (auto& stage_uniforms : fast_uniforms) { |
| 74 | for (OGLBuffer& buffer : stage_uniforms) { | 74 | for (OGLBuffer& buffer : stage_uniforms) { |
| 75 | buffer.Create(); | 75 | buffer.Create(); |
| 76 | glNamedBufferData(buffer.handle, BufferCache::SKIP_CACHE_SIZE, nullptr, GL_STREAM_DRAW); | 76 | glNamedBufferData(buffer.handle, BufferCache::DEFAULT_SKIP_CACHE_SIZE, nullptr, |
| 77 | GL_STREAM_DRAW); | ||
| 77 | } | 78 | } |
| 78 | } | 79 | } |
| 79 | for (auto& stage_uniforms : copy_uniforms) { | 80 | for (auto& stage_uniforms : copy_uniforms) { |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 12434db67..e028677e9 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -96,7 +96,7 @@ constexpr std::array<FormatTuple, MaxPixelFormat> FORMAT_TABLE = {{ | |||
| 96 | {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT}, // BC6H_UFLOAT | 96 | {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT}, // BC6H_UFLOAT |
| 97 | {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT}, // BC6H_SFLOAT | 97 | {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT}, // BC6H_SFLOAT |
| 98 | {GL_COMPRESSED_RGBA_ASTC_4x4_KHR}, // ASTC_2D_4X4_UNORM | 98 | {GL_COMPRESSED_RGBA_ASTC_4x4_KHR}, // ASTC_2D_4X4_UNORM |
| 99 | {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE}, // B8G8R8A8_UNORM | 99 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // B8G8R8A8_UNORM |
| 100 | {GL_RGBA32F, GL_RGBA, GL_FLOAT}, // R32G32B32A32_FLOAT | 100 | {GL_RGBA32F, GL_RGBA, GL_FLOAT}, // R32G32B32A32_FLOAT |
| 101 | {GL_RGBA32I, GL_RGBA_INTEGER, GL_INT}, // R32G32B32A32_SINT | 101 | {GL_RGBA32I, GL_RGBA_INTEGER, GL_INT}, // R32G32B32A32_SINT |
| 102 | {GL_RG32F, GL_RG, GL_FLOAT}, // R32G32_FLOAT | 102 | {GL_RG32F, GL_RG, GL_FLOAT}, // R32G32_FLOAT |
| @@ -125,7 +125,7 @@ constexpr std::array<FormatTuple, MaxPixelFormat> FORMAT_TABLE = {{ | |||
| 125 | {GL_COMPRESSED_RGBA_ASTC_8x8_KHR}, // ASTC_2D_8X8_UNORM | 125 | {GL_COMPRESSED_RGBA_ASTC_8x8_KHR}, // ASTC_2D_8X8_UNORM |
| 126 | {GL_COMPRESSED_RGBA_ASTC_8x5_KHR}, // ASTC_2D_8X5_UNORM | 126 | {GL_COMPRESSED_RGBA_ASTC_8x5_KHR}, // ASTC_2D_8X5_UNORM |
| 127 | {GL_COMPRESSED_RGBA_ASTC_5x4_KHR}, // ASTC_2D_5X4_UNORM | 127 | {GL_COMPRESSED_RGBA_ASTC_5x4_KHR}, // ASTC_2D_5X4_UNORM |
| 128 | {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE}, // B8G8R8A8_UNORM | 128 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE}, // B8G8R8A8_SRGB |
| 129 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT}, // BC1_RGBA_SRGB | 129 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT}, // BC1_RGBA_SRGB |
| 130 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT}, // BC2_SRGB | 130 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT}, // BC2_SRGB |
| 131 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}, // BC3_SRGB | 131 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}, // BC3_SRGB |
| @@ -396,6 +396,17 @@ void AttachTexture(GLuint fbo, GLenum attachment, const ImageView* image_view) { | |||
| 396 | } | 396 | } |
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | [[nodiscard]] bool IsPixelFormatBGR(PixelFormat format) { | ||
| 400 | switch (format) { | ||
| 401 | case PixelFormat::B5G6R5_UNORM: | ||
| 402 | case PixelFormat::B8G8R8A8_UNORM: | ||
| 403 | case PixelFormat::B8G8R8A8_SRGB: | ||
| 404 | return true; | ||
| 405 | default: | ||
| 406 | return false; | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 399 | } // Anonymous namespace | 410 | } // Anonymous namespace |
| 400 | 411 | ||
| 401 | ImageBufferMap::~ImageBufferMap() { | 412 | ImageBufferMap::~ImageBufferMap() { |
| @@ -512,6 +523,9 @@ bool TextureCacheRuntime::CanImageBeCopied(const Image& dst, const Image& src) { | |||
| 512 | if (dst.info.type == ImageType::e3D && dst.info.format == PixelFormat::BC4_UNORM) { | 523 | if (dst.info.type == ImageType::e3D && dst.info.format == PixelFormat::BC4_UNORM) { |
| 513 | return false; | 524 | return false; |
| 514 | } | 525 | } |
| 526 | if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) { | ||
| 527 | return false; | ||
| 528 | } | ||
| 515 | return true; | 529 | return true; |
| 516 | } | 530 | } |
| 517 | 531 | ||
| @@ -520,6 +534,8 @@ void TextureCacheRuntime::EmulateCopyImage(Image& dst, Image& src, | |||
| 520 | if (dst.info.type == ImageType::e3D && dst.info.format == PixelFormat::BC4_UNORM) { | 534 | if (dst.info.type == ImageType::e3D && dst.info.format == PixelFormat::BC4_UNORM) { |
| 521 | ASSERT(src.info.type == ImageType::e3D); | 535 | ASSERT(src.info.type == ImageType::e3D); |
| 522 | util_shaders.CopyBC4(dst, src, copies); | 536 | util_shaders.CopyBC4(dst, src, copies); |
| 537 | } else if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) { | ||
| 538 | util_shaders.CopyBGR(dst, src, copies); | ||
| 523 | } else { | 539 | } else { |
| 524 | UNREACHABLE(); | 540 | UNREACHABLE(); |
| 525 | } | 541 | } |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index a6172f009..3fbaa102f 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h | |||
| @@ -86,6 +86,11 @@ public: | |||
| 86 | 86 | ||
| 87 | FormatProperties FormatInfo(VideoCommon::ImageType type, GLenum internal_format) const; | 87 | FormatProperties FormatInfo(VideoCommon::ImageType type, GLenum internal_format) const; |
| 88 | 88 | ||
| 89 | bool HasNativeBgr() const noexcept { | ||
| 90 | // OpenGL does not have native support for the BGR internal format | ||
| 91 | return false; | ||
| 92 | } | ||
| 93 | |||
| 89 | bool HasBrokenTextureViewFormats() const noexcept { | 94 | bool HasBrokenTextureViewFormats() const noexcept { |
| 90 | return has_broken_texture_view_formats; | 95 | return has_broken_texture_view_formats; |
| 91 | } | 96 | } |
diff --git a/src/video_core/renderer_opengl/util_shaders.cpp b/src/video_core/renderer_opengl/util_shaders.cpp index 31ec68505..2fe4799bc 100644 --- a/src/video_core/renderer_opengl/util_shaders.cpp +++ b/src/video_core/renderer_opengl/util_shaders.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h" | 14 | #include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h" |
| 15 | #include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h" | 15 | #include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h" |
| 16 | #include "video_core/host_shaders/opengl_copy_bc4_comp.h" | 16 | #include "video_core/host_shaders/opengl_copy_bc4_comp.h" |
| 17 | #include "video_core/host_shaders/opengl_copy_bgra_comp.h" | ||
| 17 | #include "video_core/host_shaders/pitch_unswizzle_comp.h" | 18 | #include "video_core/host_shaders/pitch_unswizzle_comp.h" |
| 18 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 19 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 19 | #include "video_core/renderer_opengl/gl_shader_manager.h" | 20 | #include "video_core/renderer_opengl/gl_shader_manager.h" |
| @@ -48,6 +49,11 @@ OGLProgram MakeProgram(std::string_view source) { | |||
| 48 | return program; | 49 | return program; |
| 49 | } | 50 | } |
| 50 | 51 | ||
| 52 | size_t NumPixelsInCopy(const VideoCommon::ImageCopy& copy) { | ||
| 53 | return static_cast<size_t>(copy.extent.width * copy.extent.height * | ||
| 54 | copy.src_subresource.num_layers); | ||
| 55 | } | ||
| 56 | |||
| 51 | } // Anonymous namespace | 57 | } // Anonymous namespace |
| 52 | 58 | ||
| 53 | UtilShaders::UtilShaders(ProgramManager& program_manager_) | 59 | UtilShaders::UtilShaders(ProgramManager& program_manager_) |
| @@ -55,6 +61,7 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_) | |||
| 55 | block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)), | 61 | block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)), |
| 56 | block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)), | 62 | block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)), |
| 57 | pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)), | 63 | pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)), |
| 64 | copy_bgra_program(MakeProgram(OPENGL_COPY_BGRA_COMP)), | ||
| 58 | copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) { | 65 | copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) { |
| 59 | const auto swizzle_table = Tegra::Texture::MakeSwizzleTable(); | 66 | const auto swizzle_table = Tegra::Texture::MakeSwizzleTable(); |
| 60 | swizzle_table_buffer.Create(); | 67 | swizzle_table_buffer.Create(); |
| @@ -205,6 +212,43 @@ void UtilShaders::CopyBC4(Image& dst_image, Image& src_image, std::span<const Im | |||
| 205 | program_manager.RestoreGuestCompute(); | 212 | program_manager.RestoreGuestCompute(); |
| 206 | } | 213 | } |
| 207 | 214 | ||
| 215 | void UtilShaders::CopyBGR(Image& dst_image, Image& src_image, | ||
| 216 | std::span<const VideoCommon::ImageCopy> copies) { | ||
| 217 | static constexpr GLuint BINDING_INPUT_IMAGE = 0; | ||
| 218 | static constexpr GLuint BINDING_OUTPUT_IMAGE = 1; | ||
| 219 | static constexpr VideoCommon::Offset3D zero_offset{0, 0, 0}; | ||
| 220 | const u32 bytes_per_block = BytesPerBlock(dst_image.info.format); | ||
| 221 | switch (bytes_per_block) { | ||
| 222 | case 2: | ||
| 223 | // BGR565 copy | ||
| 224 | for (const ImageCopy& copy : copies) { | ||
| 225 | ASSERT(copy.src_offset == zero_offset); | ||
| 226 | ASSERT(copy.dst_offset == zero_offset); | ||
| 227 | bgr_copy_pass.Execute(dst_image, src_image, copy); | ||
| 228 | } | ||
| 229 | break; | ||
| 230 | case 4: { | ||
| 231 | // BGRA8 copy | ||
| 232 | program_manager.BindHostCompute(copy_bgra_program.handle); | ||
| 233 | constexpr GLenum FORMAT = GL_RGBA8; | ||
| 234 | for (const ImageCopy& copy : copies) { | ||
| 235 | ASSERT(copy.src_offset == zero_offset); | ||
| 236 | ASSERT(copy.dst_offset == zero_offset); | ||
| 237 | glBindImageTexture(BINDING_INPUT_IMAGE, src_image.StorageHandle(), | ||
| 238 | copy.src_subresource.base_level, GL_FALSE, 0, GL_READ_ONLY, FORMAT); | ||
| 239 | glBindImageTexture(BINDING_OUTPUT_IMAGE, dst_image.StorageHandle(), | ||
| 240 | copy.dst_subresource.base_level, GL_FALSE, 0, GL_WRITE_ONLY, FORMAT); | ||
| 241 | glDispatchCompute(copy.extent.width, copy.extent.height, copy.extent.depth); | ||
| 242 | } | ||
| 243 | program_manager.RestoreGuestCompute(); | ||
| 244 | break; | ||
| 245 | } | ||
| 246 | default: | ||
| 247 | UNREACHABLE(); | ||
| 248 | break; | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 208 | GLenum StoreFormat(u32 bytes_per_block) { | 252 | GLenum StoreFormat(u32 bytes_per_block) { |
| 209 | switch (bytes_per_block) { | 253 | switch (bytes_per_block) { |
| 210 | case 1: | 254 | case 1: |
| @@ -222,4 +266,36 @@ GLenum StoreFormat(u32 bytes_per_block) { | |||
| 222 | return GL_R8UI; | 266 | return GL_R8UI; |
| 223 | } | 267 | } |
| 224 | 268 | ||
| 269 | void Bgr565CopyPass::Execute(const Image& dst_image, const Image& src_image, | ||
| 270 | const ImageCopy& copy) { | ||
| 271 | if (CopyBufferCreationNeeded(copy)) { | ||
| 272 | CreateNewCopyBuffer(copy, GL_TEXTURE_2D_ARRAY, GL_RGB565); | ||
| 273 | } | ||
| 274 | // Copy from source to PBO | ||
| 275 | glPixelStorei(GL_PACK_ALIGNMENT, 1); | ||
| 276 | glPixelStorei(GL_PACK_ROW_LENGTH, copy.extent.width); | ||
| 277 | glBindBuffer(GL_PIXEL_PACK_BUFFER, bgr16_pbo.handle); | ||
| 278 | glGetTextureSubImage(src_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height, | ||
| 279 | copy.src_subresource.num_layers, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, | ||
| 280 | static_cast<GLsizei>(bgr16_pbo_size), nullptr); | ||
| 281 | |||
| 282 | // Copy from PBO to destination in reverse order | ||
| 283 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | ||
| 284 | glPixelStorei(GL_UNPACK_ROW_LENGTH, copy.extent.width); | ||
| 285 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bgr16_pbo.handle); | ||
| 286 | glTextureSubImage3D(dst_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height, | ||
| 287 | copy.dst_subresource.num_layers, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, | ||
| 288 | nullptr); | ||
| 289 | } | ||
| 290 | |||
| 291 | bool Bgr565CopyPass::CopyBufferCreationNeeded(const ImageCopy& copy) { | ||
| 292 | return bgr16_pbo_size < NumPixelsInCopy(copy) * sizeof(u16); | ||
| 293 | } | ||
| 294 | |||
| 295 | void Bgr565CopyPass::CreateNewCopyBuffer(const ImageCopy& copy, GLenum target, GLuint format) { | ||
| 296 | bgr16_pbo.Create(); | ||
| 297 | bgr16_pbo_size = NumPixelsInCopy(copy) * sizeof(u16); | ||
| 298 | glNamedBufferData(bgr16_pbo.handle, bgr16_pbo_size, nullptr, GL_STREAM_COPY); | ||
| 299 | } | ||
| 300 | |||
| 225 | } // namespace OpenGL | 301 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/util_shaders.h b/src/video_core/renderer_opengl/util_shaders.h index 7b1d16b09..93b009743 100644 --- a/src/video_core/renderer_opengl/util_shaders.h +++ b/src/video_core/renderer_opengl/util_shaders.h | |||
| @@ -19,6 +19,22 @@ class ProgramManager; | |||
| 19 | 19 | ||
| 20 | struct ImageBufferMap; | 20 | struct ImageBufferMap; |
| 21 | 21 | ||
| 22 | class Bgr565CopyPass { | ||
| 23 | public: | ||
| 24 | Bgr565CopyPass() = default; | ||
| 25 | ~Bgr565CopyPass() = default; | ||
| 26 | |||
| 27 | void Execute(const Image& dst_image, const Image& src_image, | ||
| 28 | const VideoCommon::ImageCopy& copy); | ||
| 29 | |||
| 30 | private: | ||
| 31 | [[nodiscard]] bool CopyBufferCreationNeeded(const VideoCommon::ImageCopy& copy); | ||
| 32 | void CreateNewCopyBuffer(const VideoCommon::ImageCopy& copy, GLenum target, GLuint format); | ||
| 33 | |||
| 34 | OGLBuffer bgr16_pbo; | ||
| 35 | size_t bgr16_pbo_size{}; | ||
| 36 | }; | ||
| 37 | |||
| 22 | class UtilShaders { | 38 | class UtilShaders { |
| 23 | public: | 39 | public: |
| 24 | explicit UtilShaders(ProgramManager& program_manager); | 40 | explicit UtilShaders(ProgramManager& program_manager); |
| @@ -36,6 +52,9 @@ public: | |||
| 36 | void CopyBC4(Image& dst_image, Image& src_image, | 52 | void CopyBC4(Image& dst_image, Image& src_image, |
| 37 | std::span<const VideoCommon::ImageCopy> copies); | 53 | std::span<const VideoCommon::ImageCopy> copies); |
| 38 | 54 | ||
| 55 | void CopyBGR(Image& dst_image, Image& src_image, | ||
| 56 | std::span<const VideoCommon::ImageCopy> copies); | ||
| 57 | |||
| 39 | private: | 58 | private: |
| 40 | ProgramManager& program_manager; | 59 | ProgramManager& program_manager; |
| 41 | 60 | ||
| @@ -44,7 +63,10 @@ private: | |||
| 44 | OGLProgram block_linear_unswizzle_2d_program; | 63 | OGLProgram block_linear_unswizzle_2d_program; |
| 45 | OGLProgram block_linear_unswizzle_3d_program; | 64 | OGLProgram block_linear_unswizzle_3d_program; |
| 46 | OGLProgram pitch_unswizzle_program; | 65 | OGLProgram pitch_unswizzle_program; |
| 66 | OGLProgram copy_bgra_program; | ||
| 47 | OGLProgram copy_bc4_program; | 67 | OGLProgram copy_bc4_program; |
| 68 | |||
| 69 | Bgr565CopyPass bgr_copy_pass; | ||
| 48 | }; | 70 | }; |
| 49 | 71 | ||
| 50 | GLenum StoreFormat(u32 bytes_per_block); | 72 | GLenum StoreFormat(u32 bytes_per_block); |
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 @@ | |||
| 10 | 10 | ||
| 11 | namespace Vulkan { | 11 | namespace Vulkan { |
| 12 | 12 | ||
| 13 | constexpr size_t COMMAND_BUFFER_POOL_SIZE = 0x1000; | 13 | constexpr size_t COMMAND_BUFFER_POOL_SIZE = 4; |
| 14 | 14 | ||
| 15 | struct CommandPool::Pool { | 15 | struct CommandPool::Pool { |
| 16 | vk::CommandPool handle; | 16 | vk::CommandPool handle; |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index b08c23459..3aee27ce0 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -93,6 +93,11 @@ struct TextureCacheRuntime { | |||
| 93 | // No known Vulkan driver has broken image views | 93 | // No known Vulkan driver has broken image views |
| 94 | return false; | 94 | return false; |
| 95 | } | 95 | } |
| 96 | |||
| 97 | bool HasNativeBgr() const noexcept { | ||
| 98 | // All known Vulkan drivers can natively handle BGR textures | ||
| 99 | return true; | ||
| 100 | } | ||
| 96 | }; | 101 | }; |
| 97 | 102 | ||
| 98 | class Image : public VideoCommon::ImageBase { | 103 | class Image : public VideoCommon::ImageBase { |
diff --git a/src/video_core/texture_cache/image_base.cpp b/src/video_core/texture_cache/image_base.cpp index 959b3f115..9914926b3 100644 --- a/src/video_core/texture_cache/image_base.cpp +++ b/src/video_core/texture_cache/image_base.cpp | |||
| @@ -120,9 +120,10 @@ void AddImageAlias(ImageBase& lhs, ImageBase& rhs, ImageId lhs_id, ImageId rhs_i | |||
| 120 | if (lhs.info.type == ImageType::Linear) { | 120 | if (lhs.info.type == ImageType::Linear) { |
| 121 | base = SubresourceBase{.level = 0, .layer = 0}; | 121 | base = SubresourceBase{.level = 0, .layer = 0}; |
| 122 | } else { | 122 | } else { |
| 123 | // We are passing relaxed formats as an option, having broken views or not won't matter | 123 | // We are passing relaxed formats as an option, having broken views/bgr or not won't matter |
| 124 | static constexpr bool broken_views = false; | 124 | static constexpr bool broken_views = false; |
| 125 | base = FindSubresource(rhs.info, lhs, rhs.gpu_addr, OPTIONS, broken_views); | 125 | static constexpr bool native_bgr = true; |
| 126 | base = FindSubresource(rhs.info, lhs, rhs.gpu_addr, OPTIONS, broken_views, native_bgr); | ||
| 126 | } | 127 | } |
| 127 | if (!base) { | 128 | if (!base) { |
| 128 | LOG_ERROR(HW_GPU, "Image alias should have been flipped"); | 129 | LOG_ERROR(HW_GPU, "Image alias should have been flipped"); |
diff --git a/src/video_core/texture_cache/image_view_base.cpp b/src/video_core/texture_cache/image_view_base.cpp index 18f72e508..f89a40b4c 100644 --- a/src/video_core/texture_cache/image_view_base.cpp +++ b/src/video_core/texture_cache/image_view_base.cpp | |||
| @@ -24,7 +24,7 @@ ImageViewBase::ImageViewBase(const ImageViewInfo& info, const ImageInfo& image_i | |||
| 24 | .height = std::max(image_info.size.height >> range.base.level, 1u), | 24 | .height = std::max(image_info.size.height >> range.base.level, 1u), |
| 25 | .depth = std::max(image_info.size.depth >> range.base.level, 1u), | 25 | .depth = std::max(image_info.size.depth >> range.base.level, 1u), |
| 26 | } { | 26 | } { |
| 27 | ASSERT_MSG(VideoCore::Surface::IsViewCompatible(image_info.format, info.format, false), | 27 | ASSERT_MSG(VideoCore::Surface::IsViewCompatible(image_info.format, info.format, false, true), |
| 28 | "Image view format {} is incompatible with image format {}", info.format, | 28 | "Image view format {} is incompatible with image format {}", info.format, |
| 29 | image_info.format); | 29 | image_info.format); |
| 30 | const bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue(); | 30 | const bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue(); |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index b1da69971..98e33c3a0 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -876,6 +876,7 @@ ImageId TextureCache<P>::FindImage(const ImageInfo& info, GPUVAddr gpu_addr, | |||
| 876 | return ImageId{}; | 876 | return ImageId{}; |
| 877 | } | 877 | } |
| 878 | const bool broken_views = runtime.HasBrokenTextureViewFormats(); | 878 | const bool broken_views = runtime.HasBrokenTextureViewFormats(); |
| 879 | const bool native_bgr = runtime.HasNativeBgr(); | ||
| 879 | ImageId image_id; | 880 | ImageId image_id; |
| 880 | const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { | 881 | const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { |
| 881 | if (info.type == ImageType::Linear || existing_image.info.type == ImageType::Linear) { | 882 | if (info.type == ImageType::Linear || existing_image.info.type == ImageType::Linear) { |
| @@ -885,11 +886,12 @@ ImageId TextureCache<P>::FindImage(const ImageInfo& info, GPUVAddr gpu_addr, | |||
| 885 | if (existing_image.gpu_addr == gpu_addr && existing.type == info.type && | 886 | if (existing_image.gpu_addr == gpu_addr && existing.type == info.type && |
| 886 | existing.pitch == info.pitch && | 887 | existing.pitch == info.pitch && |
| 887 | IsPitchLinearSameSize(existing, info, strict_size) && | 888 | IsPitchLinearSameSize(existing, info, strict_size) && |
| 888 | IsViewCompatible(existing.format, info.format, broken_views)) { | 889 | IsViewCompatible(existing.format, info.format, broken_views, native_bgr)) { |
| 889 | image_id = existing_image_id; | 890 | image_id = existing_image_id; |
| 890 | return true; | 891 | return true; |
| 891 | } | 892 | } |
| 892 | } else if (IsSubresource(info, existing_image, gpu_addr, options, broken_views)) { | 893 | } else if (IsSubresource(info, existing_image, gpu_addr, options, broken_views, |
| 894 | native_bgr)) { | ||
| 893 | image_id = existing_image_id; | 895 | image_id = existing_image_id; |
| 894 | return true; | 896 | return true; |
| 895 | } | 897 | } |
| @@ -920,6 +922,7 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA | |||
| 920 | ImageInfo new_info = info; | 922 | ImageInfo new_info = info; |
| 921 | const size_t size_bytes = CalculateGuestSizeInBytes(new_info); | 923 | const size_t size_bytes = CalculateGuestSizeInBytes(new_info); |
| 922 | const bool broken_views = runtime.HasBrokenTextureViewFormats(); | 924 | const bool broken_views = runtime.HasBrokenTextureViewFormats(); |
| 925 | const bool native_bgr = runtime.HasNativeBgr(); | ||
| 923 | std::vector<ImageId> overlap_ids; | 926 | std::vector<ImageId> overlap_ids; |
| 924 | std::vector<ImageId> left_aliased_ids; | 927 | std::vector<ImageId> left_aliased_ids; |
| 925 | std::vector<ImageId> right_aliased_ids; | 928 | std::vector<ImageId> right_aliased_ids; |
| @@ -935,8 +938,8 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA | |||
| 935 | return; | 938 | return; |
| 936 | } | 939 | } |
| 937 | static constexpr bool strict_size = true; | 940 | static constexpr bool strict_size = true; |
| 938 | const std::optional<OverlapResult> solution = | 941 | const std::optional<OverlapResult> solution = ResolveOverlap( |
| 939 | ResolveOverlap(new_info, gpu_addr, cpu_addr, overlap, strict_size, broken_views); | 942 | new_info, gpu_addr, cpu_addr, overlap, strict_size, broken_views, native_bgr); |
| 940 | if (solution) { | 943 | if (solution) { |
| 941 | gpu_addr = solution->gpu_addr; | 944 | gpu_addr = solution->gpu_addr; |
| 942 | cpu_addr = solution->cpu_addr; | 945 | cpu_addr = solution->cpu_addr; |
| @@ -946,10 +949,10 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA | |||
| 946 | } | 949 | } |
| 947 | static constexpr auto options = RelaxedOptions::Size | RelaxedOptions::Format; | 950 | static constexpr auto options = RelaxedOptions::Size | RelaxedOptions::Format; |
| 948 | const ImageBase new_image_base(new_info, gpu_addr, cpu_addr); | 951 | const ImageBase new_image_base(new_info, gpu_addr, cpu_addr); |
| 949 | if (IsSubresource(new_info, overlap, gpu_addr, options, broken_views)) { | 952 | if (IsSubresource(new_info, overlap, gpu_addr, options, broken_views, native_bgr)) { |
| 950 | left_aliased_ids.push_back(overlap_id); | 953 | left_aliased_ids.push_back(overlap_id); |
| 951 | } else if (IsSubresource(overlap.info, new_image_base, overlap.gpu_addr, options, | 954 | } else if (IsSubresource(overlap.info, new_image_base, overlap.gpu_addr, options, |
| 952 | broken_views)) { | 955 | broken_views, native_bgr)) { |
| 953 | right_aliased_ids.push_back(overlap_id); | 956 | right_aliased_ids.push_back(overlap_id); |
| 954 | } | 957 | } |
| 955 | }); | 958 | }); |
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index a0bc1f7b6..2c42d1449 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp | |||
| @@ -1035,13 +1035,13 @@ bool IsPitchLinearSameSize(const ImageInfo& lhs, const ImageInfo& rhs, bool stri | |||
| 1035 | 1035 | ||
| 1036 | std::optional<OverlapResult> ResolveOverlap(const ImageInfo& new_info, GPUVAddr gpu_addr, | 1036 | std::optional<OverlapResult> ResolveOverlap(const ImageInfo& new_info, GPUVAddr gpu_addr, |
| 1037 | VAddr cpu_addr, const ImageBase& overlap, | 1037 | VAddr cpu_addr, const ImageBase& overlap, |
| 1038 | bool strict_size, bool broken_views) { | 1038 | bool strict_size, bool broken_views, bool native_bgr) { |
| 1039 | ASSERT(new_info.type != ImageType::Linear); | 1039 | ASSERT(new_info.type != ImageType::Linear); |
| 1040 | ASSERT(overlap.info.type != ImageType::Linear); | 1040 | ASSERT(overlap.info.type != ImageType::Linear); |
| 1041 | if (!IsLayerStrideCompatible(new_info, overlap.info)) { | 1041 | if (!IsLayerStrideCompatible(new_info, overlap.info)) { |
| 1042 | return std::nullopt; | 1042 | return std::nullopt; |
| 1043 | } | 1043 | } |
| 1044 | if (!IsViewCompatible(overlap.info.format, new_info.format, broken_views)) { | 1044 | if (!IsViewCompatible(overlap.info.format, new_info.format, broken_views, native_bgr)) { |
| 1045 | return std::nullopt; | 1045 | return std::nullopt; |
| 1046 | } | 1046 | } |
| 1047 | if (gpu_addr == overlap.gpu_addr) { | 1047 | if (gpu_addr == overlap.gpu_addr) { |
| @@ -1085,14 +1085,14 @@ bool IsLayerStrideCompatible(const ImageInfo& lhs, const ImageInfo& rhs) { | |||
| 1085 | 1085 | ||
| 1086 | std::optional<SubresourceBase> FindSubresource(const ImageInfo& candidate, const ImageBase& image, | 1086 | std::optional<SubresourceBase> FindSubresource(const ImageInfo& candidate, const ImageBase& image, |
| 1087 | GPUVAddr candidate_addr, RelaxedOptions options, | 1087 | GPUVAddr candidate_addr, RelaxedOptions options, |
| 1088 | bool broken_views) { | 1088 | bool broken_views, bool native_bgr) { |
| 1089 | const std::optional<SubresourceBase> base = image.TryFindBase(candidate_addr); | 1089 | const std::optional<SubresourceBase> base = image.TryFindBase(candidate_addr); |
| 1090 | if (!base) { | 1090 | if (!base) { |
| 1091 | return std::nullopt; | 1091 | return std::nullopt; |
| 1092 | } | 1092 | } |
| 1093 | const ImageInfo& existing = image.info; | 1093 | const ImageInfo& existing = image.info; |
| 1094 | if (False(options & RelaxedOptions::Format)) { | 1094 | if (False(options & RelaxedOptions::Format)) { |
| 1095 | if (!IsViewCompatible(existing.format, candidate.format, broken_views)) { | 1095 | if (!IsViewCompatible(existing.format, candidate.format, broken_views, native_bgr)) { |
| 1096 | return std::nullopt; | 1096 | return std::nullopt; |
| 1097 | } | 1097 | } |
| 1098 | } | 1098 | } |
| @@ -1129,8 +1129,9 @@ std::optional<SubresourceBase> FindSubresource(const ImageInfo& candidate, const | |||
| 1129 | } | 1129 | } |
| 1130 | 1130 | ||
| 1131 | bool IsSubresource(const ImageInfo& candidate, const ImageBase& image, GPUVAddr candidate_addr, | 1131 | bool IsSubresource(const ImageInfo& candidate, const ImageBase& image, GPUVAddr candidate_addr, |
| 1132 | RelaxedOptions options, bool broken_views) { | 1132 | RelaxedOptions options, bool broken_views, bool native_bgr) { |
| 1133 | return FindSubresource(candidate, image, candidate_addr, options, broken_views).has_value(); | 1133 | return FindSubresource(candidate, image, candidate_addr, options, broken_views, native_bgr) |
| 1134 | .has_value(); | ||
| 1134 | } | 1135 | } |
| 1135 | 1136 | ||
| 1136 | void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst, | 1137 | void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst, |
diff --git a/src/video_core/texture_cache/util.h b/src/video_core/texture_cache/util.h index 52a9207d6..4d0072867 100644 --- a/src/video_core/texture_cache/util.h +++ b/src/video_core/texture_cache/util.h | |||
| @@ -87,7 +87,8 @@ void SwizzleImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const Ima | |||
| 87 | [[nodiscard]] std::optional<OverlapResult> ResolveOverlap(const ImageInfo& new_info, | 87 | [[nodiscard]] std::optional<OverlapResult> ResolveOverlap(const ImageInfo& new_info, |
| 88 | GPUVAddr gpu_addr, VAddr cpu_addr, | 88 | GPUVAddr gpu_addr, VAddr cpu_addr, |
| 89 | const ImageBase& overlap, | 89 | const ImageBase& overlap, |
| 90 | bool strict_size, bool broken_views); | 90 | bool strict_size, bool broken_views, |
| 91 | bool native_bgr); | ||
| 91 | 92 | ||
| 92 | [[nodiscard]] bool IsLayerStrideCompatible(const ImageInfo& lhs, const ImageInfo& rhs); | 93 | [[nodiscard]] bool IsLayerStrideCompatible(const ImageInfo& lhs, const ImageInfo& rhs); |
| 93 | 94 | ||
| @@ -95,11 +96,11 @@ void SwizzleImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const Ima | |||
| 95 | const ImageBase& image, | 96 | const ImageBase& image, |
| 96 | GPUVAddr candidate_addr, | 97 | GPUVAddr candidate_addr, |
| 97 | RelaxedOptions options, | 98 | RelaxedOptions options, |
| 98 | bool broken_views); | 99 | bool broken_views, bool native_bgr); |
| 99 | 100 | ||
| 100 | [[nodiscard]] bool IsSubresource(const ImageInfo& candidate, const ImageBase& image, | 101 | [[nodiscard]] bool IsSubresource(const ImageInfo& candidate, const ImageBase& image, |
| 101 | GPUVAddr candidate_addr, RelaxedOptions options, | 102 | GPUVAddr candidate_addr, RelaxedOptions options, bool broken_views, |
| 102 | bool broken_views); | 103 | bool native_bgr); |
| 103 | 104 | ||
| 104 | void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst, | 105 | void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst, |
| 105 | const ImageBase* src); | 106 | const ImageBase* src); |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 1c61d419d..15c09e0ad 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -376,11 +376,34 @@ void GRenderWindow::closeEvent(QCloseEvent* event) { | |||
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | void GRenderWindow::keyPressEvent(QKeyEvent* event) { | 378 | void GRenderWindow::keyPressEvent(QKeyEvent* event) { |
| 379 | input_subsystem->GetKeyboard()->PressKey(event->key()); | 379 | if (!event->isAutoRepeat()) { |
| 380 | input_subsystem->GetKeyboard()->PressKey(event->key()); | ||
| 381 | } | ||
| 380 | } | 382 | } |
| 381 | 383 | ||
| 382 | void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { | 384 | void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { |
| 383 | input_subsystem->GetKeyboard()->ReleaseKey(event->key()); | 385 | if (!event->isAutoRepeat()) { |
| 386 | input_subsystem->GetKeyboard()->ReleaseKey(event->key()); | ||
| 387 | } | ||
| 388 | } | ||
| 389 | |||
| 390 | MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) { | ||
| 391 | switch (button) { | ||
| 392 | case Qt::LeftButton: | ||
| 393 | return MouseInput::MouseButton::Left; | ||
| 394 | case Qt::RightButton: | ||
| 395 | return MouseInput::MouseButton::Right; | ||
| 396 | case Qt::MiddleButton: | ||
| 397 | return MouseInput::MouseButton::Wheel; | ||
| 398 | case Qt::BackButton: | ||
| 399 | return MouseInput::MouseButton::Backward; | ||
| 400 | case Qt::ForwardButton: | ||
| 401 | return MouseInput::MouseButton::Forward; | ||
| 402 | case Qt::TaskButton: | ||
| 403 | return MouseInput::MouseButton::Task; | ||
| 404 | default: | ||
| 405 | return MouseInput::MouseButton::Extra; | ||
| 406 | } | ||
| 384 | } | 407 | } |
| 385 | 408 | ||
| 386 | void GRenderWindow::mousePressEvent(QMouseEvent* event) { | 409 | void GRenderWindow::mousePressEvent(QMouseEvent* event) { |
| @@ -391,7 +414,8 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { | |||
| 391 | 414 | ||
| 392 | auto pos = event->pos(); | 415 | auto pos = event->pos(); |
| 393 | const auto [x, y] = ScaleTouch(pos); | 416 | const auto [x, y] = ScaleTouch(pos); |
| 394 | input_subsystem->GetMouse()->PressButton(x, y, event->button()); | 417 | const auto button = QtButtonToMouseButton(event->button()); |
| 418 | input_subsystem->GetMouse()->PressButton(x, y, button); | ||
| 395 | 419 | ||
| 396 | if (event->button() == Qt::LeftButton) { | 420 | if (event->button() == Qt::LeftButton) { |
| 397 | this->TouchPressed(x, y, 0); | 421 | this->TouchPressed(x, y, 0); |
| @@ -425,7 +449,8 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { | |||
| 425 | return; | 449 | return; |
| 426 | } | 450 | } |
| 427 | 451 | ||
| 428 | input_subsystem->GetMouse()->ReleaseButton(event->button()); | 452 | const auto button = QtButtonToMouseButton(event->button()); |
| 453 | input_subsystem->GetMouse()->ReleaseButton(button); | ||
| 429 | 454 | ||
| 430 | if (event->button() == Qt::LeftButton) { | 455 | if (event->button() == Qt::LeftButton) { |
| 431 | this->TouchReleased(0); | 456 | 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 { | |||
| 28 | class InputSubsystem; | 28 | class InputSubsystem; |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | namespace MouseInput { | ||
| 32 | enum class MouseButton; | ||
| 33 | } | ||
| 34 | |||
| 31 | namespace VideoCore { | 35 | namespace VideoCore { |
| 32 | enum class LoadCallbackStage; | 36 | enum class LoadCallbackStage; |
| 33 | } | 37 | } |
| @@ -149,6 +153,9 @@ public: | |||
| 149 | void keyPressEvent(QKeyEvent* event) override; | 153 | void keyPressEvent(QKeyEvent* event) override; |
| 150 | void keyReleaseEvent(QKeyEvent* event) override; | 154 | void keyReleaseEvent(QKeyEvent* event) override; |
| 151 | 155 | ||
| 156 | /// Converts a Qt mouse button into MouseInput mouse button | ||
| 157 | static MouseInput::MouseButton QtButtonToMouseButton(Qt::MouseButton button); | ||
| 158 | |||
| 152 | void mousePressEvent(QMouseEvent* event) override; | 159 | void mousePressEvent(QMouseEvent* event) override; |
| 153 | void mouseMoveEvent(QMouseEvent* event) override; | 160 | void mouseMoveEvent(QMouseEvent* event) override; |
| 154 | void mouseReleaseEvent(QMouseEvent* event) override; | 161 | void mouseReleaseEvent(QMouseEvent* event) override; |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index b319d69fc..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{{ | |||
| 235 | {QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}}, | 235 | {QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}}, |
| 236 | {QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}}, | 236 | {QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}}, |
| 237 | {QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}}, | 237 | {QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}}, |
| 238 | {QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("F9"), Qt::ApplicationShortcut}}, | 238 | {QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F9"), Qt::ApplicationShortcut}}, |
| 239 | {QStringLiteral("Toggle Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Z"), Qt::ApplicationShortcut}}, | 239 | {QStringLiteral("Toggle Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Z"), Qt::ApplicationShortcut}}, |
| 240 | {QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), Qt::WindowShortcut}}, | 240 | {QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), Qt::WindowShortcut}}, |
| 241 | }}; | 241 | }}; |
| @@ -508,7 +508,7 @@ void Config::ReadControlValues() { | |||
| 508 | 508 | ||
| 509 | Settings::values.emulate_analog_keyboard = | 509 | Settings::values.emulate_analog_keyboard = |
| 510 | ReadSetting(QStringLiteral("emulate_analog_keyboard"), false).toBool(); | 510 | ReadSetting(QStringLiteral("emulate_analog_keyboard"), false).toBool(); |
| 511 | Settings::values.mouse_panning = ReadSetting(QStringLiteral("mouse_panning"), false).toBool(); | 511 | Settings::values.mouse_panning = false; |
| 512 | Settings::values.mouse_panning_sensitivity = | 512 | Settings::values.mouse_panning_sensitivity = |
| 513 | ReadSetting(QStringLiteral("mouse_panning_sensitivity"), 1).toFloat(); | 513 | ReadSetting(QStringLiteral("mouse_panning_sensitivity"), 1).toFloat(); |
| 514 | 514 | ||
| @@ -1182,7 +1182,6 @@ void Config::SaveControlValues() { | |||
| 1182 | WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false); | 1182 | WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false); |
| 1183 | WriteSetting(QStringLiteral("emulate_analog_keyboard"), | 1183 | WriteSetting(QStringLiteral("emulate_analog_keyboard"), |
| 1184 | Settings::values.emulate_analog_keyboard, false); | 1184 | Settings::values.emulate_analog_keyboard, false); |
| 1185 | WriteSetting(QStringLiteral("mouse_panning"), Settings::values.mouse_panning, false); | ||
| 1186 | WriteSetting(QStringLiteral("mouse_panning_sensitivity"), | 1185 | WriteSetting(QStringLiteral("mouse_panning_sensitivity"), |
| 1187 | Settings::values.mouse_panning_sensitivity, 1.0f); | 1186 | Settings::values.mouse_panning_sensitivity, 1.0f); |
| 1188 | qt_config->endGroup(); | 1187 | qt_config->endGroup(); |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 21d0d3449..c9318c562 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include "input_common/mouse/mouse_poller.h" | 21 | #include "input_common/mouse/mouse_poller.h" |
| 22 | #include "input_common/udp/udp.h" | 22 | #include "input_common/udp/udp.h" |
| 23 | #include "ui_configure_input_player.h" | 23 | #include "ui_configure_input_player.h" |
| 24 | #include "yuzu/bootmanager.h" | ||
| 24 | #include "yuzu/configuration/config.h" | 25 | #include "yuzu/configuration/config.h" |
| 25 | #include "yuzu/configuration/configure_input_player.h" | 26 | #include "yuzu/configuration/configure_input_player.h" |
| 26 | #include "yuzu/configuration/configure_input_player_widget.h" | 27 | #include "yuzu/configuration/configure_input_player_widget.h" |
| @@ -104,7 +105,9 @@ QString ButtonToText(const Common::ParamPackage& param) { | |||
| 104 | } | 105 | } |
| 105 | 106 | ||
| 106 | if (param.Get("engine", "") == "keyboard") { | 107 | if (param.Get("engine", "") == "keyboard") { |
| 107 | return GetKeyName(param.Get("code", 0)); | 108 | const QString button_str = GetKeyName(param.Get("code", 0)); |
| 109 | const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); | ||
| 110 | return QObject::tr("%1%2").arg(toggle, button_str); | ||
| 108 | } | 111 | } |
| 109 | 112 | ||
| 110 | if (param.Get("engine", "") == "gcpad") { | 113 | if (param.Get("engine", "") == "gcpad") { |
| @@ -156,7 +159,8 @@ QString ButtonToText(const Common::ParamPackage& param) { | |||
| 156 | if (param.Get("engine", "") == "mouse") { | 159 | if (param.Get("engine", "") == "mouse") { |
| 157 | if (param.Has("button")) { | 160 | if (param.Has("button")) { |
| 158 | const QString button_str = QString::number(int(param.Get("button", 0))); | 161 | const QString button_str = QString::number(int(param.Get("button", 0))); |
| 159 | return QObject::tr("Click %1").arg(button_str); | 162 | const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); |
| 163 | return QObject::tr("%1Click %2").arg(toggle, button_str); | ||
| 160 | } | 164 | } |
| 161 | return GetKeyName(param.Get("code", 0)); | 165 | return GetKeyName(param.Get("code", 0)); |
| 162 | } | 166 | } |
| @@ -300,6 +304,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 300 | buttons_param[button_id].Clear(); | 304 | buttons_param[button_id].Clear(); |
| 301 | button_map[button_id]->setText(tr("[not set]")); | 305 | button_map[button_id]->setText(tr("[not set]")); |
| 302 | }); | 306 | }); |
| 307 | context_menu.addAction(tr("Toggle button"), [&] { | ||
| 308 | const bool toggle_value = !buttons_param[button_id].Get("toggle", false); | ||
| 309 | buttons_param[button_id].Set("toggle", toggle_value); | ||
| 310 | button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); | ||
| 311 | }); | ||
| 303 | context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); | 312 | context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); |
| 304 | ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); | 313 | ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); |
| 305 | }); | 314 | }); |
| @@ -412,6 +421,15 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 412 | analogs_param[analog_id].Set("modifier", ""); | 421 | analogs_param[analog_id].Set("modifier", ""); |
| 413 | analog_map_modifier_button[analog_id]->setText(tr("[not set]")); | 422 | analog_map_modifier_button[analog_id]->setText(tr("[not set]")); |
| 414 | }); | 423 | }); |
| 424 | context_menu.addAction(tr("Toggle button"), [&] { | ||
| 425 | Common::ParamPackage modifier_param = | ||
| 426 | Common::ParamPackage{analogs_param[analog_id].Get("modifier", "")}; | ||
| 427 | const bool toggle_value = !modifier_param.Get("toggle", false); | ||
| 428 | modifier_param.Set("toggle", toggle_value); | ||
| 429 | analogs_param[analog_id].Set("modifier", modifier_param.Serialize()); | ||
| 430 | analog_map_modifier_button[analog_id]->setText( | ||
| 431 | ButtonToText(modifier_param)); | ||
| 432 | }); | ||
| 415 | context_menu.exec( | 433 | context_menu.exec( |
| 416 | analog_map_modifier_button[analog_id]->mapToGlobal(menu_location)); | 434 | analog_map_modifier_button[analog_id]->mapToGlobal(menu_location)); |
| 417 | }); | 435 | }); |
| @@ -1345,7 +1363,8 @@ void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) { | |||
| 1345 | return; | 1363 | return; |
| 1346 | } | 1364 | } |
| 1347 | 1365 | ||
| 1348 | input_subsystem->GetMouse()->PressButton(0, 0, event->button()); | 1366 | const auto button = GRenderWindow::QtButtonToMouseButton(event->button()); |
| 1367 | input_subsystem->GetMouse()->PressButton(0, 0, button); | ||
| 1349 | } | 1368 | } |
| 1350 | 1369 | ||
| 1351 | void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) { | 1370 | 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 @@ | |||
| 24 | 24 | ||
| 25 | CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, | 25 | CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, |
| 26 | const std::string& host, u16 port, | 26 | const std::string& host, u16 port, |
| 27 | u8 pad_index, u16 client_id) | 27 | u8 pad_index) |
| 28 | : QDialog(parent) { | 28 | : QDialog(parent) { |
| 29 | layout = new QVBoxLayout; | 29 | layout = new QVBoxLayout; |
| 30 | status_label = new QLabel(tr("Communicating with the server...")); | 30 | status_label = new QLabel(tr("Communicating with the server...")); |
| @@ -41,7 +41,7 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, | |||
| 41 | 41 | ||
| 42 | using namespace InputCommon::CemuhookUDP; | 42 | using namespace InputCommon::CemuhookUDP; |
| 43 | job = std::make_unique<CalibrationConfigurationJob>( | 43 | job = std::make_unique<CalibrationConfigurationJob>( |
| 44 | host, port, pad_index, client_id, | 44 | host, port, pad_index, |
| 45 | [this](CalibrationConfigurationJob::Status status) { | 45 | [this](CalibrationConfigurationJob::Status status) { |
| 46 | QString text; | 46 | QString text; |
| 47 | switch (status) { | 47 | switch (status) { |
| @@ -218,7 +218,6 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() { | |||
| 218 | udp_test_in_progress = true; | 218 | udp_test_in_progress = true; |
| 219 | InputCommon::CemuhookUDP::TestCommunication( | 219 | InputCommon::CemuhookUDP::TestCommunication( |
| 220 | ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 0, | 220 | ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 0, |
| 221 | 24872, | ||
| 222 | [this] { | 221 | [this] { |
| 223 | LOG_INFO(Frontend, "UDP input test success"); | 222 | LOG_INFO(Frontend, "UDP input test success"); |
| 224 | QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true)); | 223 | QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true)); |
| @@ -233,8 +232,7 @@ void ConfigureMotionTouch::OnConfigureTouchCalibration() { | |||
| 233 | ui->touch_calibration_config->setEnabled(false); | 232 | ui->touch_calibration_config->setEnabled(false); |
| 234 | ui->touch_calibration_config->setText(tr("Configuring")); | 233 | ui->touch_calibration_config->setText(tr("Configuring")); |
| 235 | CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(), | 234 | CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(), |
| 236 | static_cast<u16>(ui->udp_port->text().toUInt()), 0, | 235 | static_cast<u16>(ui->udp_port->text().toUInt()), 0); |
| 237 | 24872); | ||
| 238 | dialog.exec(); | 236 | dialog.exec(); |
| 239 | if (dialog.completed) { | 237 | if (dialog.completed) { |
| 240 | min_x = dialog.min_x; | 238 | 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 { | |||
| 30 | Q_OBJECT | 30 | Q_OBJECT |
| 31 | public: | 31 | public: |
| 32 | explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port, | 32 | explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port, |
| 33 | u8 pad_index, u16 client_id); | 33 | u8 pad_index); |
| 34 | ~CalibrationConfigurationDialog() override; | 34 | ~CalibrationConfigurationDialog() override; |
| 35 | 35 | ||
| 36 | private: | 36 | private: |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 0ba7c07cc..24bfa4d34 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -60,6 +60,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||
| 60 | #include <QPushButton> | 60 | #include <QPushButton> |
| 61 | #include <QShortcut> | 61 | #include <QShortcut> |
| 62 | #include <QStatusBar> | 62 | #include <QStatusBar> |
| 63 | #include <QString> | ||
| 63 | #include <QSysInfo> | 64 | #include <QSysInfo> |
| 64 | #include <QUrl> | 65 | #include <QUrl> |
| 65 | #include <QtConcurrent/QtConcurrent> | 66 | #include <QtConcurrent/QtConcurrent> |
| @@ -854,8 +855,7 @@ void GMainWindow::InitializeHotkeys() { | |||
| 854 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this), | 855 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this), |
| 855 | &QShortcut::activated, this, [&] { | 856 | &QShortcut::activated, this, [&] { |
| 856 | Settings::values.mouse_panning = !Settings::values.mouse_panning; | 857 | Settings::values.mouse_panning = !Settings::values.mouse_panning; |
| 857 | if (UISettings::values.hide_mouse || Settings::values.mouse_panning) { | 858 | if (Settings::values.mouse_panning) { |
| 858 | mouse_hide_timer.start(); | ||
| 859 | render_window->installEventFilter(render_window); | 859 | render_window->installEventFilter(render_window); |
| 860 | render_window->setAttribute(Qt::WA_Hover, true); | 860 | render_window->setAttribute(Qt::WA_Hover, true); |
| 861 | } | 861 | } |
| @@ -1208,11 +1208,14 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) { | |||
| 1208 | renderer_status_button->setDisabled(true); | 1208 | renderer_status_button->setDisabled(true); |
| 1209 | 1209 | ||
| 1210 | if (UISettings::values.hide_mouse || Settings::values.mouse_panning) { | 1210 | if (UISettings::values.hide_mouse || Settings::values.mouse_panning) { |
| 1211 | mouse_hide_timer.start(); | ||
| 1212 | render_window->installEventFilter(render_window); | 1211 | render_window->installEventFilter(render_window); |
| 1213 | render_window->setAttribute(Qt::WA_Hover, true); | 1212 | render_window->setAttribute(Qt::WA_Hover, true); |
| 1214 | } | 1213 | } |
| 1215 | 1214 | ||
| 1215 | if (UISettings::values.hide_mouse) { | ||
| 1216 | mouse_hide_timer.start(); | ||
| 1217 | } | ||
| 1218 | |||
| 1216 | std::string title_name; | 1219 | std::string title_name; |
| 1217 | std::string title_version; | 1220 | std::string title_version; |
| 1218 | const auto res = system.GetGameName(title_name); | 1221 | const auto res = system.GetGameName(title_name); |
| @@ -2372,12 +2375,15 @@ void GMainWindow::OnConfigure() { | |||
| 2372 | if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) { | 2375 | if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) { |
| 2373 | render_window->installEventFilter(render_window); | 2376 | render_window->installEventFilter(render_window); |
| 2374 | render_window->setAttribute(Qt::WA_Hover, true); | 2377 | render_window->setAttribute(Qt::WA_Hover, true); |
| 2375 | mouse_hide_timer.start(); | ||
| 2376 | } else { | 2378 | } else { |
| 2377 | render_window->removeEventFilter(render_window); | 2379 | render_window->removeEventFilter(render_window); |
| 2378 | render_window->setAttribute(Qt::WA_Hover, false); | 2380 | render_window->setAttribute(Qt::WA_Hover, false); |
| 2379 | } | 2381 | } |
| 2380 | 2382 | ||
| 2383 | if (UISettings::values.hide_mouse) { | ||
| 2384 | mouse_hide_timer.start(); | ||
| 2385 | } | ||
| 2386 | |||
| 2381 | UpdateStatusButtons(); | 2387 | UpdateStatusButtons(); |
| 2382 | } | 2388 | } |
| 2383 | 2389 | ||
| @@ -2615,8 +2621,7 @@ void GMainWindow::UpdateUISettings() { | |||
| 2615 | } | 2621 | } |
| 2616 | 2622 | ||
| 2617 | void GMainWindow::HideMouseCursor() { | 2623 | void GMainWindow::HideMouseCursor() { |
| 2618 | if (emu_thread == nullptr || | 2624 | if (emu_thread == nullptr && UISettings::values.hide_mouse) { |
| 2619 | (!UISettings::values.hide_mouse && !Settings::values.mouse_panning)) { | ||
| 2620 | mouse_hide_timer.stop(); | 2625 | mouse_hide_timer.stop(); |
| 2621 | ShowMouseCursor(); | 2626 | ShowMouseCursor(); |
| 2622 | return; | 2627 | return; |
| @@ -2626,8 +2631,7 @@ void GMainWindow::HideMouseCursor() { | |||
| 2626 | 2631 | ||
| 2627 | void GMainWindow::ShowMouseCursor() { | 2632 | void GMainWindow::ShowMouseCursor() { |
| 2628 | render_window->unsetCursor(); | 2633 | render_window->unsetCursor(); |
| 2629 | if (emu_thread != nullptr && | 2634 | if (emu_thread != nullptr && UISettings::values.hide_mouse) { |
| 2630 | (UISettings::values.hide_mouse || Settings::values.mouse_panning)) { | ||
| 2631 | mouse_hide_timer.start(); | 2635 | mouse_hide_timer.start(); |
| 2632 | } | 2636 | } |
| 2633 | } | 2637 | } |
| @@ -3058,6 +3062,14 @@ int main(int argc, char* argv[]) { | |||
| 3058 | chdir(bin_path.c_str()); | 3062 | chdir(bin_path.c_str()); |
| 3059 | #endif | 3063 | #endif |
| 3060 | 3064 | ||
| 3065 | #ifdef __linux__ | ||
| 3066 | // Set the DISPLAY variable in order to open web browsers | ||
| 3067 | // TODO (lat9nq): Find a better solution for AppImages to start external applications | ||
| 3068 | if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) { | ||
| 3069 | qputenv("DISPLAY", ":0"); | ||
| 3070 | } | ||
| 3071 | #endif | ||
| 3072 | |||
| 3061 | // Enables the core to make the qt created contexts current on std::threads | 3073 | // Enables the core to make the qt created contexts current on std::threads |
| 3062 | QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); | 3074 | QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); |
| 3063 | QApplication app(argc, argv); | 3075 | QApplication app(argc, argv); |
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) { | |||
| 35 | input_subsystem->GetMouse()->MouseMove(x, y, 0, 0); | 35 | input_subsystem->GetMouse()->MouseMove(x, y, 0, 0); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | MouseInput::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const { | ||
| 39 | switch (button) { | ||
| 40 | case SDL_BUTTON_LEFT: | ||
| 41 | return MouseInput::MouseButton::Left; | ||
| 42 | case SDL_BUTTON_RIGHT: | ||
| 43 | return MouseInput::MouseButton::Right; | ||
| 44 | case SDL_BUTTON_MIDDLE: | ||
| 45 | return MouseInput::MouseButton::Wheel; | ||
| 46 | case SDL_BUTTON_X1: | ||
| 47 | return MouseInput::MouseButton::Backward; | ||
| 48 | case SDL_BUTTON_X2: | ||
| 49 | return MouseInput::MouseButton::Forward; | ||
| 50 | default: | ||
| 51 | return MouseInput::MouseButton::Undefined; | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 38 | void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { | 55 | void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { |
| 56 | const auto mouse_button = SDLButtonToMouseButton(button); | ||
| 39 | if (button == SDL_BUTTON_LEFT) { | 57 | if (button == SDL_BUTTON_LEFT) { |
| 40 | if (state == SDL_PRESSED) { | 58 | if (state == SDL_PRESSED) { |
| 41 | TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); | 59 | TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); |
| 42 | } else { | 60 | } else { |
| 43 | TouchReleased(0); | 61 | TouchReleased(0); |
| 44 | } | 62 | } |
| 45 | } else if (button == SDL_BUTTON_RIGHT) { | 63 | } else { |
| 46 | if (state == SDL_PRESSED) { | 64 | if (state == SDL_PRESSED) { |
| 47 | input_subsystem->GetMouse()->PressButton(x, y, button); | 65 | input_subsystem->GetMouse()->PressButton(x, y, mouse_button); |
| 48 | } else { | 66 | } else { |
| 49 | input_subsystem->GetMouse()->ReleaseButton(button); | 67 | input_subsystem->GetMouse()->ReleaseButton(mouse_button); |
| 50 | } | 68 | } |
| 51 | } | 69 | } |
| 52 | } | 70 | } |
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 { | |||
| 18 | class InputSubsystem; | 18 | class InputSubsystem; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | namespace MouseInput { | ||
| 22 | enum class MouseButton; | ||
| 23 | } | ||
| 24 | |||
| 21 | class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { | 25 | class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { |
| 22 | public: | 26 | public: |
| 23 | explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem); | 27 | explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem); |
| @@ -42,6 +46,9 @@ protected: | |||
| 42 | /// Called by WaitEvent when the mouse moves. | 46 | /// Called by WaitEvent when the mouse moves. |
| 43 | void OnMouseMotion(s32 x, s32 y); | 47 | void OnMouseMotion(s32 x, s32 y); |
| 44 | 48 | ||
| 49 | /// Converts a SDL mouse button into MouseInput mouse button | ||
| 50 | MouseInput::MouseButton SDLButtonToMouseButton(u32 button) const; | ||
| 51 | |||
| 45 | /// Called by WaitEvent when a mouse button is pressed or released | 52 | /// Called by WaitEvent when a mouse button is pressed or released |
| 46 | void OnMouseButton(u32 button, u8 state, s32 x, s32 y); | 53 | void OnMouseButton(u32 button, u8 state, s32 x, s32 y); |
| 47 | 54 | ||