summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/common/fiber.cpp23
-rw-r--r--src/common/fiber.h2
-rw-r--r--src/core/cpu_manager.cpp8
-rw-r--r--src/core/crypto/aes_util.cpp2
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp17
-rw-r--r--src/core/hle/kernel/k_thread.cpp50
-rw-r--r--src/core/hle/kernel/k_thread.h24
-rw-r--r--src/core/hle/kernel/kernel.cpp11
-rw-r--r--src/core/hle/kernel/process.cpp5
-rw-r--r--src/core/hle/kernel/svc.cpp5
-rw-r--r--src/input_common/mouse/mouse_input.cpp11
-rw-r--r--src/input_common/mouse/mouse_input.h12
-rw-r--r--src/tests/common/fibers.cpp28
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h45
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_command_pool.cpp2
-rw-r--r--src/yuzu/bootmanager.cpp25
-rw-r--r--src/yuzu/bootmanager.h7
-rw-r--r--src/yuzu/configuration/config.cpp5
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp4
-rw-r--r--src/yuzu/main.cpp19
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp24
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h7
24 files changed, 229 insertions, 112 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/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
119void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { 119void 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
131std::shared_ptr<Fiber> Fiber::ThreadToFiber() { 134std::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/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
112template <typename Key, std::size_t KeySize> 110template <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
998ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags, 998ResultVal<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
1008ResultVal<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
1022ResultVal<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
1037ResultVal<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
1036KThread* GetCurrentThreadPointer(KernelCore& kernel) { 1048KThread* 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 {
40void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { 40void 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/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp
index b864d26f2..d81e790ee 100644
--- a/src/input_common/mouse/mouse_input.cpp
+++ b/src/input_common/mouse/mouse_input.cpp
@@ -59,7 +59,7 @@ void Mouse::UpdateYuzuSettings() {
59 }); 59 });
60} 60}
61 61
62void Mouse::PressButton(int x, int y, int button_) { 62void 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
132void Mouse::ReleaseButton(int button_) { 132void 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,6 +152,11 @@ void Mouse::BeginConfiguration() {
152 152
153void Mouse::EndConfiguration() { 153void 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;
diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h
index 46aa676c1..3622fe080 100644
--- a/src/input_common/mouse/mouse_input.h
+++ b/src/input_common/mouse/mouse_input.h
@@ -18,10 +18,12 @@ namespace MouseInput {
18 18
19enum class MouseButton { 19enum 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,7 @@ 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_);
69 71
70 [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue(); 72 [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue();
71 [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const; 73 [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const;
@@ -94,7 +96,7 @@ private:
94 u16 buttons{}; 96 u16 buttons{};
95 std::thread update_thread; 97 std::thread update_thread;
96 MouseButton last_button{MouseButton::Undefined}; 98 MouseButton last_button{MouseButton::Undefined};
97 std::array<MouseInfo, 5> mouse_info; 99 std::array<MouseInfo, 7> mouse_info;
98 Common::SPSCQueue<MouseStatus> mouse_queue; 100 Common::SPSCQueue<MouseStatus> mouse_queue;
99 bool configuring{false}; 101 bool configuring{false};
100 bool update_thread_running{true}; 102 bool update_thread_running{true};
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
73void TestControl1::ExecuteThread(u32 id) { 73void 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/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
93public: 94public:
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
329template <class P> 335template <class P>
330void BufferCache<P>::TickFrame() { 336void 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
1108template <class P> 1132template <class P>
1109void BufferCache<P>::SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size) { 1133bool 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
1116template <class P> 1140template <class P>
1117void BufferCache<P>::SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 size) { 1141bool 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
1137template <class P> 1162template <class P>
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_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
11namespace Vulkan { 11namespace Vulkan {
12 12
13constexpr size_t COMMAND_BUFFER_POOL_SIZE = 0x1000; 13constexpr size_t COMMAND_BUFFER_POOL_SIZE = 4;
14 14
15struct CommandPool::Pool { 15struct CommandPool::Pool {
16 vk::CommandPool handle; 16 vk::CommandPool handle;
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 1c61d419d..ae49cbb45 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -383,6 +383,25 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
383 input_subsystem->GetKeyboard()->ReleaseKey(event->key()); 383 input_subsystem->GetKeyboard()->ReleaseKey(event->key());
384} 384}
385 385
386MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) {
387 switch (button) {
388 case Qt::LeftButton:
389 return MouseInput::MouseButton::Left;
390 case Qt::RightButton:
391 return MouseInput::MouseButton::Right;
392 case Qt::MiddleButton:
393 return MouseInput::MouseButton::Wheel;
394 case Qt::BackButton:
395 return MouseInput::MouseButton::Backward;
396 case Qt::ForwardButton:
397 return MouseInput::MouseButton::Forward;
398 case Qt::TaskButton:
399 return MouseInput::MouseButton::Task;
400 default:
401 return MouseInput::MouseButton::Extra;
402 }
403}
404
386void GRenderWindow::mousePressEvent(QMouseEvent* event) { 405void GRenderWindow::mousePressEvent(QMouseEvent* event) {
387 // Touch input is handled in TouchBeginEvent 406 // Touch input is handled in TouchBeginEvent
388 if (event->source() == Qt::MouseEventSynthesizedBySystem) { 407 if (event->source() == Qt::MouseEventSynthesizedBySystem) {
@@ -391,7 +410,8 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) {
391 410
392 auto pos = event->pos(); 411 auto pos = event->pos();
393 const auto [x, y] = ScaleTouch(pos); 412 const auto [x, y] = ScaleTouch(pos);
394 input_subsystem->GetMouse()->PressButton(x, y, event->button()); 413 const auto button = QtButtonToMouseButton(event->button());
414 input_subsystem->GetMouse()->PressButton(x, y, button);
395 415
396 if (event->button() == Qt::LeftButton) { 416 if (event->button() == Qt::LeftButton) {
397 this->TouchPressed(x, y, 0); 417 this->TouchPressed(x, y, 0);
@@ -425,7 +445,8 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
425 return; 445 return;
426 } 446 }
427 447
428 input_subsystem->GetMouse()->ReleaseButton(event->button()); 448 const auto button = QtButtonToMouseButton(event->button());
449 input_subsystem->GetMouse()->ReleaseButton(button);
429 450
430 if (event->button() == Qt::LeftButton) { 451 if (event->button() == Qt::LeftButton) {
431 this->TouchReleased(0); 452 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 {
28class InputSubsystem; 28class InputSubsystem;
29} 29}
30 30
31namespace MouseInput {
32enum class MouseButton;
33}
34
31namespace VideoCore { 35namespace VideoCore {
32enum class LoadCallbackStage; 36enum 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..bc572d319 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"
@@ -1345,7 +1346,8 @@ void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) {
1345 return; 1346 return;
1346 } 1347 }
1347 1348
1348 input_subsystem->GetMouse()->PressButton(0, 0, event->button()); 1349 const auto button = GRenderWindow::QtButtonToMouseButton(event->button());
1350 input_subsystem->GetMouse()->PressButton(0, 0, button);
1349} 1351}
1350 1352
1351void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) { 1353void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 0ba7c07cc..56d892a31 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -854,8 +854,7 @@ void GMainWindow::InitializeHotkeys() {
854 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this), 854 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this),
855 &QShortcut::activated, this, [&] { 855 &QShortcut::activated, this, [&] {
856 Settings::values.mouse_panning = !Settings::values.mouse_panning; 856 Settings::values.mouse_panning = !Settings::values.mouse_panning;
857 if (UISettings::values.hide_mouse || Settings::values.mouse_panning) { 857 if (Settings::values.mouse_panning) {
858 mouse_hide_timer.start();
859 render_window->installEventFilter(render_window); 858 render_window->installEventFilter(render_window);
860 render_window->setAttribute(Qt::WA_Hover, true); 859 render_window->setAttribute(Qt::WA_Hover, true);
861 } 860 }
@@ -1208,11 +1207,14 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
1208 renderer_status_button->setDisabled(true); 1207 renderer_status_button->setDisabled(true);
1209 1208
1210 if (UISettings::values.hide_mouse || Settings::values.mouse_panning) { 1209 if (UISettings::values.hide_mouse || Settings::values.mouse_panning) {
1211 mouse_hide_timer.start();
1212 render_window->installEventFilter(render_window); 1210 render_window->installEventFilter(render_window);
1213 render_window->setAttribute(Qt::WA_Hover, true); 1211 render_window->setAttribute(Qt::WA_Hover, true);
1214 } 1212 }
1215 1213
1214 if (UISettings::values.hide_mouse) {
1215 mouse_hide_timer.start();
1216 }
1217
1216 std::string title_name; 1218 std::string title_name;
1217 std::string title_version; 1219 std::string title_version;
1218 const auto res = system.GetGameName(title_name); 1220 const auto res = system.GetGameName(title_name);
@@ -2372,12 +2374,15 @@ void GMainWindow::OnConfigure() {
2372 if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) { 2374 if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) {
2373 render_window->installEventFilter(render_window); 2375 render_window->installEventFilter(render_window);
2374 render_window->setAttribute(Qt::WA_Hover, true); 2376 render_window->setAttribute(Qt::WA_Hover, true);
2375 mouse_hide_timer.start();
2376 } else { 2377 } else {
2377 render_window->removeEventFilter(render_window); 2378 render_window->removeEventFilter(render_window);
2378 render_window->setAttribute(Qt::WA_Hover, false); 2379 render_window->setAttribute(Qt::WA_Hover, false);
2379 } 2380 }
2380 2381
2382 if (UISettings::values.hide_mouse) {
2383 mouse_hide_timer.start();
2384 }
2385
2381 UpdateStatusButtons(); 2386 UpdateStatusButtons();
2382} 2387}
2383 2388
@@ -2615,8 +2620,7 @@ void GMainWindow::UpdateUISettings() {
2615} 2620}
2616 2621
2617void GMainWindow::HideMouseCursor() { 2622void GMainWindow::HideMouseCursor() {
2618 if (emu_thread == nullptr || 2623 if (emu_thread == nullptr && UISettings::values.hide_mouse) {
2619 (!UISettings::values.hide_mouse && !Settings::values.mouse_panning)) {
2620 mouse_hide_timer.stop(); 2624 mouse_hide_timer.stop();
2621 ShowMouseCursor(); 2625 ShowMouseCursor();
2622 return; 2626 return;
@@ -2626,8 +2630,7 @@ void GMainWindow::HideMouseCursor() {
2626 2630
2627void GMainWindow::ShowMouseCursor() { 2631void GMainWindow::ShowMouseCursor() {
2628 render_window->unsetCursor(); 2632 render_window->unsetCursor();
2629 if (emu_thread != nullptr && 2633 if (emu_thread != nullptr && UISettings::values.hide_mouse) {
2630 (UISettings::values.hide_mouse || Settings::values.mouse_panning)) {
2631 mouse_hide_timer.start(); 2634 mouse_hide_timer.start();
2632 } 2635 }
2633} 2636}
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
38MouseInput::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
38void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { 55void 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 {
18class InputSubsystem; 18class InputSubsystem;
19} 19}
20 20
21namespace MouseInput {
22enum class MouseButton;
23}
24
21class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { 25class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
22public: 26public:
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