summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/common/host_memory.cpp4
-rw-r--r--src/common/logging/filter.cpp1
-rw-r--r--src/common/logging/types.h1
-rw-r--r--src/common/thread.h2
-rw-r--r--src/common/threadsafe_queue.h4
-rw-r--r--src/common/x64/native_clock.cpp49
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/arm/arm_interface.h3
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp37
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp38
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h4
-rw-r--r--src/core/hid/emulated_console.cpp17
-rw-r--r--src/core/hid/emulated_console.h1
-rw-r--r--src/core/hid/emulated_controller.cpp377
-rw-r--r--src/core/hid/emulated_controller.h3
-rw-r--r--src/core/hid/emulated_devices.cpp33
-rw-r--r--src/core/hid/emulated_devices.h1
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp11
-rw-r--r--src/core/hle/kernel/hle_ipc.h8
-rw-r--r--src/core/hle/kernel/kernel.cpp30
-rw-r--r--src/core/hle/kernel/kernel.h16
-rw-r--r--src/core/hle/kernel/physical_core.cpp1
-rw-r--r--src/core/hle/kernel/time_manager.cpp4
-rw-r--r--src/core/hle/service/am/am.cpp9
-rw-r--r--src/core/hle/service/am/am.h1
-rw-r--r--src/core/hle/service/audio/audout_u.cpp7
-rw-r--r--src/core/hle/service/audio/audren_u.cpp3
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp13
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp2
-rw-r--r--src/core/hle/service/jit/jit.cpp53
-rw-r--r--src/core/hle/service/jit/jit.h20
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.cpp2
-rw-r--r--src/core/hle/service/nvflinger/buffer_item_consumer.cpp4
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_consumer.cpp8
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.cpp2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.cpp28
-rw-r--r--src/core/hle/service/nvflinger/consumer_base.cpp4
-rw-r--r--src/core/hle/service/nvflinger/graphic_buffer_producer.cpp2
-rw-r--r--src/core/hle/service/nvflinger/hos_binder_driver_server.cpp4
-rw-r--r--src/core/hle/service/service.cpp7
-rw-r--r--src/core/hle/service/service.h14
-rw-r--r--src/core/hle/service/sm/sm.cpp2
-rw-r--r--src/core/hle/service/sockets/bsd.cpp3
-rw-r--r--src/core/hle/service/vi/vi.cpp3
-rw-r--r--src/core/perf_stats.cpp10
-rw-r--r--src/core/tools/freezer.cpp18
-rw-r--r--src/input_common/drivers/sdl_driver.cpp12
-rw-r--r--src/input_common/input_engine.cpp46
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp25
-rw-r--r--src/shader_recompiler/backend/glsl/glsl_emit_context.cpp19
-rw-r--r--src/shader_recompiler/backend/glsl/glsl_emit_context.h1
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp21
-rw-r--r--src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp9
-rw-r--r--src/shader_recompiler/shader_info.h1
-rw-r--r--src/video_core/gpu.cpp6
-rw-r--r--src/video_core/gpu_thread.cpp2
-rw-r--r--src/video_core/host_shaders/CMakeLists.txt1
-rw-r--r--src/video_core/host_shaders/opengl_convert_s8d24.comp18
-rw-r--r--src/video_core/renderer_opengl/gl_graphics_pipeline.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h3
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp7
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h2
-rw-r--r--src/video_core/renderer_opengl/util_shaders.cpp24
-rw-r--r--src/video_core/renderer_opengl/util_shaders.h3
-rw-r--r--src/video_core/renderer_vulkan/pipeline_statistics.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_render_pass_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp6
-rw-r--r--src/video_core/shader_cache.cpp2
-rw-r--r--src/web_service/web_backend.cpp4
-rw-r--r--src/yuzu/util/controller_navigation.cpp2
79 files changed, 732 insertions, 403 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3ad2c0950..9182dbfd4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -65,12 +65,14 @@ if (MSVC)
65 /we4305 # 'context': truncation from 'type1' to 'type2' 65 /we4305 # 'context': truncation from 'type1' to 'type2'
66 /we4388 # 'expression': signed/unsigned mismatch 66 /we4388 # 'expression': signed/unsigned mismatch
67 /we4389 # 'operator': signed/unsigned mismatch 67 /we4389 # 'operator': signed/unsigned mismatch
68 /we4505 # 'function': unreferenced local function has been removed
68 /we4547 # 'operator': operator before comma has no effect; expected operator with side-effect 69 /we4547 # 'operator': operator before comma has no effect; expected operator with side-effect
69 /we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'? 70 /we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
70 /we4555 # Expression has no effect; expected expression with side-effect 71 /we4555 # Expression has no effect; expected expression with side-effect
71 /we4715 # 'function': not all control paths return a value 72 /we4715 # 'function': not all control paths return a value
72 /we4834 # Discarding return value of function with 'nodiscard' attribute 73 /we4834 # Discarding return value of function with 'nodiscard' attribute
73 /we5038 # data member 'member1' will be initialized after data member 'member2' 74 /we5038 # data member 'member1' will be initialized after data member 'member2'
75 /we5245 # 'function': unreferenced function with internal linkage has been removed
74 ) 76 )
75 77
76 if (ARCHITECTURE_x86_64) 78 if (ARCHITECTURE_x86_64)
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
index e829af1ac..802943eb7 100644
--- a/src/common/host_memory.cpp
+++ b/src/common/host_memory.cpp
@@ -149,7 +149,7 @@ public:
149 } 149 }
150 150
151 void Unmap(size_t virtual_offset, size_t length) { 151 void Unmap(size_t virtual_offset, size_t length) {
152 std::lock_guard lock{placeholder_mutex}; 152 std::scoped_lock lock{placeholder_mutex};
153 153
154 // Unmap until there are no more placeholders 154 // Unmap until there are no more placeholders
155 while (UnmapOnePlaceholder(virtual_offset, length)) { 155 while (UnmapOnePlaceholder(virtual_offset, length)) {
@@ -169,7 +169,7 @@ public:
169 } 169 }
170 const size_t virtual_end = virtual_offset + length; 170 const size_t virtual_end = virtual_offset + length;
171 171
172 std::lock_guard lock{placeholder_mutex}; 172 std::scoped_lock lock{placeholder_mutex};
173 auto [it, end] = placeholders.equal_range({virtual_offset, virtual_end}); 173 auto [it, end] = placeholders.equal_range({virtual_offset, virtual_end});
174 while (it != end) { 174 while (it != end) {
175 const size_t offset = std::max(it->lower(), virtual_offset); 175 const size_t offset = std::max(it->lower(), virtual_offset);
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 9120cc178..4acbff649 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -101,6 +101,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
101 SUB(Service, GRC) \ 101 SUB(Service, GRC) \
102 SUB(Service, HID) \ 102 SUB(Service, HID) \
103 SUB(Service, IRS) \ 103 SUB(Service, IRS) \
104 SUB(Service, JIT) \
104 SUB(Service, LBL) \ 105 SUB(Service, LBL) \
105 SUB(Service, LDN) \ 106 SUB(Service, LDN) \
106 SUB(Service, LDR) \ 107 SUB(Service, LDR) \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index f803ab796..99c15fa96 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -69,6 +69,7 @@ enum class Class : u8 {
69 Service_GRC, ///< The game recording service 69 Service_GRC, ///< The game recording service
70 Service_HID, ///< The HID (Human interface device) service 70 Service_HID, ///< The HID (Human interface device) service
71 Service_IRS, ///< The IRS service 71 Service_IRS, ///< The IRS service
72 Service_JIT, ///< The JIT service
72 Service_LBL, ///< The LBL (LCD backlight) service 73 Service_LBL, ///< The LBL (LCD backlight) service
73 Service_LDN, ///< The LDN (Local domain network) service 74 Service_LDN, ///< The LDN (Local domain network) service
74 Service_LDR, ///< The loader service 75 Service_LDR, ///< The loader service
diff --git a/src/common/thread.h b/src/common/thread.h
index a8c17c71a..626609372 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -17,7 +17,7 @@ namespace Common {
17class Event { 17class Event {
18public: 18public:
19 void Set() { 19 void Set() {
20 std::lock_guard lk{mutex}; 20 std::scoped_lock lk{mutex};
21 if (!is_set) { 21 if (!is_set) {
22 is_set = true; 22 is_set = true;
23 condvar.notify_one(); 23 condvar.notify_one();
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h
index 2c8c2b90e..7272ac6e8 100644
--- a/src/common/threadsafe_queue.h
+++ b/src/common/threadsafe_queue.h
@@ -52,7 +52,7 @@ public:
52 // line before cv.wait 52 // line before cv.wait
53 // TODO(bunnei): This can be replaced with C++20 waitable atomics when properly supported. 53 // TODO(bunnei): This can be replaced with C++20 waitable atomics when properly supported.
54 // See discussion on https://github.com/yuzu-emu/yuzu/pull/3173 for details. 54 // See discussion on https://github.com/yuzu-emu/yuzu/pull/3173 for details.
55 std::lock_guard lock{cv_mutex}; 55 std::scoped_lock lock{cv_mutex};
56 cv.notify_one(); 56 cv.notify_one();
57 } 57 }
58 58
@@ -159,7 +159,7 @@ public:
159 159
160 template <typename Arg> 160 template <typename Arg>
161 void Push(Arg&& t) { 161 void Push(Arg&& t) {
162 std::lock_guard lock{write_lock}; 162 std::scoped_lock lock{write_lock};
163 spsc_queue.Push(t); 163 spsc_queue.Push(t);
164 } 164 }
165 165
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp
index 7a3f21dcf..7fd9d22f8 100644
--- a/src/common/x64/native_clock.cpp
+++ b/src/common/x64/native_clock.cpp
@@ -10,25 +10,49 @@
10#include "common/uint128.h" 10#include "common/uint128.h"
11#include "common/x64/native_clock.h" 11#include "common/x64/native_clock.h"
12 12
13#ifdef _MSC_VER
14#include <intrin.h>
15#endif
16
13namespace Common { 17namespace Common {
14 18
19#ifdef _MSC_VER
20__forceinline static u64 FencedRDTSC() {
21 _mm_lfence();
22 _ReadWriteBarrier();
23 const u64 result = __rdtsc();
24 _mm_lfence();
25 _ReadWriteBarrier();
26 return result;
27}
28#else
29static u64 FencedRDTSC() {
30 u64 result;
31 asm volatile("lfence\n\t"
32 "rdtsc\n\t"
33 "shl $32, %%rdx\n\t"
34 "or %%rdx, %0\n\t"
35 "lfence"
36 : "=a"(result)
37 :
38 : "rdx", "memory", "cc");
39 return result;
40}
41#endif
42
15u64 EstimateRDTSCFrequency() { 43u64 EstimateRDTSCFrequency() {
16 // Discard the first result measuring the rdtsc. 44 // Discard the first result measuring the rdtsc.
17 _mm_mfence(); 45 FencedRDTSC();
18 __rdtsc();
19 std::this_thread::sleep_for(std::chrono::milliseconds{1}); 46 std::this_thread::sleep_for(std::chrono::milliseconds{1});
20 _mm_mfence(); 47 FencedRDTSC();
21 __rdtsc();
22 48
23 // Get the current time. 49 // Get the current time.
24 const auto start_time = std::chrono::steady_clock::now(); 50 const auto start_time = std::chrono::steady_clock::now();
25 _mm_mfence(); 51 const u64 tsc_start = FencedRDTSC();
26 const u64 tsc_start = __rdtsc();
27 // Wait for 200 milliseconds. 52 // Wait for 200 milliseconds.
28 std::this_thread::sleep_for(std::chrono::milliseconds{200}); 53 std::this_thread::sleep_for(std::chrono::milliseconds{200});
29 const auto end_time = std::chrono::steady_clock::now(); 54 const auto end_time = std::chrono::steady_clock::now();
30 _mm_mfence(); 55 const u64 tsc_end = FencedRDTSC();
31 const u64 tsc_end = __rdtsc();
32 // Calculate differences. 56 // Calculate differences.
33 const u64 timer_diff = static_cast<u64>( 57 const u64 timer_diff = static_cast<u64>(
34 std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count()); 58 std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());
@@ -42,8 +66,7 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen
42 u64 rtsc_frequency_) 66 u64 rtsc_frequency_)
43 : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ 67 : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{
44 rtsc_frequency_} { 68 rtsc_frequency_} {
45 _mm_mfence(); 69 time_point.inner.last_measure = FencedRDTSC();
46 time_point.inner.last_measure = __rdtsc();
47 time_point.inner.accumulated_ticks = 0U; 70 time_point.inner.accumulated_ticks = 0U;
48 ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency); 71 ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency);
49 us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency); 72 us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency);
@@ -58,8 +81,7 @@ u64 NativeClock::GetRTSC() {
58 81
59 current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); 82 current_time_point.pack = Common::AtomicLoad128(time_point.pack.data());
60 do { 83 do {
61 _mm_mfence(); 84 const u64 current_measure = FencedRDTSC();
62 const u64 current_measure = __rdtsc();
63 u64 diff = current_measure - current_time_point.inner.last_measure; 85 u64 diff = current_measure - current_time_point.inner.last_measure;
64 diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0) 86 diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0)
65 new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure 87 new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure
@@ -80,8 +102,7 @@ void NativeClock::Pause(bool is_paused) {
80 current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); 102 current_time_point.pack = Common::AtomicLoad128(time_point.pack.data());
81 do { 103 do {
82 new_time_point.pack = current_time_point.pack; 104 new_time_point.pack = current_time_point.pack;
83 _mm_mfence(); 105 new_time_point.inner.last_measure = FencedRDTSC();
84 new_time_point.inner.last_measure = __rdtsc();
85 } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, 106 } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack,
86 current_time_point.pack, current_time_point.pack)); 107 current_time_point.pack, current_time_point.pack));
87 } 108 }
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 6536d0544..81eaf0942 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -458,6 +458,8 @@ add_library(core STATIC
458 hle/service/hid/controllers/touchscreen.h 458 hle/service/hid/controllers/touchscreen.h
459 hle/service/hid/controllers/xpad.cpp 459 hle/service/hid/controllers/xpad.cpp
460 hle/service/hid/controllers/xpad.h 460 hle/service/hid/controllers/xpad.h
461 hle/service/jit/jit.cpp
462 hle/service/jit/jit.h
461 hle/service/lbl/lbl.cpp 463 hle/service/lbl/lbl.cpp
462 hle/service/lbl/lbl.h 464 hle/service/lbl/lbl.h
463 hle/service/ldn/errors.h 465 hle/service/ldn/errors.h
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index c60322442..dce2f4195 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -171,6 +171,9 @@ public:
171 /// Prepare core for thread reschedule (if needed to correctly handle state) 171 /// Prepare core for thread reschedule (if needed to correctly handle state)
172 virtual void PrepareReschedule() = 0; 172 virtual void PrepareReschedule() = 0;
173 173
174 /// Signal an interrupt and ask the core to halt as soon as possible.
175 virtual void SignalInterrupt() = 0;
176
174 struct BacktraceEntry { 177 struct BacktraceEntry {
175 std::string module; 178 std::string module;
176 u64 address; 179 u64 address;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 054572445..ab3210d84 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -25,6 +25,9 @@ namespace Core {
25 25
26using namespace Common::Literals; 26using namespace Common::Literals;
27 27
28constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2;
29constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;
30
28class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { 31class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
29public: 32public:
30 explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) 33 explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_)
@@ -84,15 +87,13 @@ public:
84 } 87 }
85 88
86 void CallSVC(u32 swi) override { 89 void CallSVC(u32 swi) override {
87 parent.svc_called = true;
88 parent.svc_swi = swi; 90 parent.svc_swi = swi;
89 parent.jit->HaltExecution(); 91 parent.jit->HaltExecution(svc_call);
90 } 92 }
91 93
92 void AddTicks(u64 ticks) override { 94 void AddTicks(u64 ticks) override {
93 if (parent.uses_wall_clock) { 95 ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
94 return; 96
95 }
96 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a 97 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
97 // rough approximation of the amount of executed ticks in the system, it may be thrown off 98 // rough approximation of the amount of executed ticks in the system, it may be thrown off
98 // if not all cores are doing a similar amount of work. Instead of doing this, we should 99 // if not all cores are doing a similar amount of work. Instead of doing this, we should
@@ -108,12 +109,8 @@ public:
108 } 109 }
109 110
110 u64 GetTicksRemaining() override { 111 u64 GetTicksRemaining() override {
111 if (parent.uses_wall_clock) { 112 ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
112 if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { 113
113 return minimum_run_cycles;
114 }
115 return 0U;
116 }
117 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); 114 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
118 } 115 }
119 116
@@ -148,6 +145,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
148 145
149 // Timing 146 // Timing
150 config.wall_clock_cntpct = uses_wall_clock; 147 config.wall_clock_cntpct = uses_wall_clock;
148 config.enable_cycle_counting = !uses_wall_clock;
151 149
152 // Code cache size 150 // Code cache size
153 config.code_cache_size = 512_MiB; 151 config.code_cache_size = 512_MiB;
@@ -230,13 +228,11 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
230 228
231void ARM_Dynarmic_32::Run() { 229void ARM_Dynarmic_32::Run() {
232 while (true) { 230 while (true) {
233 jit->Run(); 231 const auto hr = jit->Run();
234 if (!svc_called) { 232 if (Has(hr, svc_call)) {
235 break; 233 Kernel::Svc::Call(system, svc_swi);
236 } 234 }
237 svc_called = false; 235 if (Has(hr, break_loop)) {
238 Kernel::Svc::Call(system, svc_swi);
239 if (shutdown) {
240 break; 236 break;
241 } 237 }
242 } 238 }
@@ -322,8 +318,11 @@ void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
322} 318}
323 319
324void ARM_Dynarmic_32::PrepareReschedule() { 320void ARM_Dynarmic_32::PrepareReschedule() {
325 jit->HaltExecution(); 321 jit->HaltExecution(break_loop);
326 shutdown = true; 322}
323
324void ARM_Dynarmic_32::SignalInterrupt() {
325 jit->HaltExecution(break_loop);
327} 326}
328 327
329void ARM_Dynarmic_32::ClearInstructionCache() { 328void ARM_Dynarmic_32::ClearInstructionCache() {
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index 5d47b600d..3f68a4ff1 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -57,6 +57,7 @@ public:
57 void LoadContext(const ThreadContext64& ctx) override {} 57 void LoadContext(const ThreadContext64& ctx) override {}
58 58
59 void PrepareReschedule() override; 59 void PrepareReschedule() override;
60 void SignalInterrupt() override;
60 void ClearExclusiveState() override; 61 void ClearExclusiveState() override;
61 62
62 void ClearInstructionCache() override; 63 void ClearInstructionCache() override;
@@ -83,9 +84,6 @@ private:
83 84
84 // SVC callback 85 // SVC callback
85 u32 svc_swi{}; 86 u32 svc_swi{};
86 bool svc_called{};
87
88 bool shutdown{};
89}; 87};
90 88
91} // namespace Core 89} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 7ff8f9495..68822a1fc 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -26,6 +26,9 @@ namespace Core {
26using Vector = Dynarmic::A64::Vector; 26using Vector = Dynarmic::A64::Vector;
27using namespace Common::Literals; 27using namespace Common::Literals;
28 28
29constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2;
30constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;
31
29class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { 32class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
30public: 33public:
31 explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) 34 explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_)
@@ -106,7 +109,7 @@ public:
106 break; 109 break;
107 } 110 }
108 111
109 parent.jit->HaltExecution(); 112 parent.jit->HaltExecution(Dynarmic::HaltReason::CacheInvalidation);
110 } 113 }
111 114
112 void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { 115 void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
@@ -126,15 +129,12 @@ public:
126 } 129 }
127 130
128 void CallSVC(u32 swi) override { 131 void CallSVC(u32 swi) override {
129 parent.svc_called = true;
130 parent.svc_swi = swi; 132 parent.svc_swi = swi;
131 parent.jit->HaltExecution(); 133 parent.jit->HaltExecution(svc_call);
132 } 134 }
133 135
134 void AddTicks(u64 ticks) override { 136 void AddTicks(u64 ticks) override {
135 if (parent.uses_wall_clock) { 137 ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
136 return;
137 }
138 138
139 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a 139 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
140 // rough approximation of the amount of executed ticks in the system, it may be thrown off 140 // rough approximation of the amount of executed ticks in the system, it may be thrown off
@@ -149,12 +149,8 @@ public:
149 } 149 }
150 150
151 u64 GetTicksRemaining() override { 151 u64 GetTicksRemaining() override {
152 if (parent.uses_wall_clock) { 152 ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
153 if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { 153
154 return minimum_run_cycles;
155 }
156 return 0U;
157 }
158 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); 154 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
159 } 155 }
160 156
@@ -210,6 +206,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
210 206
211 // Timing 207 // Timing
212 config.wall_clock_cntpct = uses_wall_clock; 208 config.wall_clock_cntpct = uses_wall_clock;
209 config.enable_cycle_counting = !uses_wall_clock;
213 210
214 // Code cache size 211 // Code cache size
215 config.code_cache_size = 512_MiB; 212 config.code_cache_size = 512_MiB;
@@ -292,13 +289,11 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
292 289
293void ARM_Dynarmic_64::Run() { 290void ARM_Dynarmic_64::Run() {
294 while (true) { 291 while (true) {
295 jit->Run(); 292 const auto hr = jit->Run();
296 if (!svc_called) { 293 if (Has(hr, svc_call)) {
297 break; 294 Kernel::Svc::Call(system, svc_swi);
298 } 295 }
299 svc_called = false; 296 if (Has(hr, break_loop)) {
300 Kernel::Svc::Call(system, svc_swi);
301 if (shutdown) {
302 break; 297 break;
303 } 298 }
304 } 299 }
@@ -389,8 +384,11 @@ void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
389} 384}
390 385
391void ARM_Dynarmic_64::PrepareReschedule() { 386void ARM_Dynarmic_64::PrepareReschedule() {
392 jit->HaltExecution(); 387 jit->HaltExecution(break_loop);
393 shutdown = true; 388}
389
390void ARM_Dynarmic_64::SignalInterrupt() {
391 jit->HaltExecution(break_loop);
394} 392}
395 393
396void ARM_Dynarmic_64::ClearInstructionCache() { 394void ARM_Dynarmic_64::ClearInstructionCache() {
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index 0c4e46c64..58bc7fbec 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -51,6 +51,7 @@ public:
51 void LoadContext(const ThreadContext64& ctx) override; 51 void LoadContext(const ThreadContext64& ctx) override;
52 52
53 void PrepareReschedule() override; 53 void PrepareReschedule() override;
54 void SignalInterrupt() override;
54 void ClearExclusiveState() override; 55 void ClearExclusiveState() override;
55 56
56 void ClearInstructionCache() override; 57 void ClearInstructionCache() override;
@@ -77,9 +78,6 @@ private:
77 78
78 // SVC callback 79 // SVC callback
79 u32 svc_swi{}; 80 u32 svc_swi{};
80 bool svc_called{};
81
82 bool shutdown{};
83}; 81};
84 82
85} // namespace Core 83} // namespace Core
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp
index eef0ff493..de565048b 100644
--- a/src/core/hid/emulated_console.cpp
+++ b/src/core/hid/emulated_console.cpp
@@ -132,7 +132,7 @@ void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
132} 132}
133 133
134void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) { 134void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
135 std::lock_guard lock{mutex}; 135 std::unique_lock lock{mutex};
136 auto& raw_status = console.motion_values.raw_status; 136 auto& raw_status = console.motion_values.raw_status;
137 auto& emulated = console.motion_values.emulated; 137 auto& emulated = console.motion_values.emulated;
138 138
@@ -151,6 +151,7 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
151 emulated.UpdateOrientation(raw_status.delta_timestamp); 151 emulated.UpdateOrientation(raw_status.delta_timestamp);
152 152
153 if (is_configuring) { 153 if (is_configuring) {
154 lock.unlock();
154 TriggerOnChange(ConsoleTriggerType::Motion); 155 TriggerOnChange(ConsoleTriggerType::Motion);
155 return; 156 return;
156 } 157 }
@@ -166,6 +167,7 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
166 // Find what is this value 167 // Find what is this value
167 motion.verticalization_error = 0.0f; 168 motion.verticalization_error = 0.0f;
168 169
170 lock.unlock();
169 TriggerOnChange(ConsoleTriggerType::Motion); 171 TriggerOnChange(ConsoleTriggerType::Motion);
170} 172}
171 173
@@ -173,11 +175,12 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st
173 if (index >= console.touch_values.size()) { 175 if (index >= console.touch_values.size()) {
174 return; 176 return;
175 } 177 }
176 std::lock_guard lock{mutex}; 178 std::unique_lock lock{mutex};
177 179
178 console.touch_values[index] = TransformToTouch(callback); 180 console.touch_values[index] = TransformToTouch(callback);
179 181
180 if (is_configuring) { 182 if (is_configuring) {
183 lock.unlock();
181 TriggerOnChange(ConsoleTriggerType::Touch); 184 TriggerOnChange(ConsoleTriggerType::Touch);
182 return; 185 return;
183 } 186 }
@@ -189,26 +192,32 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st
189 .pressed = console.touch_values[index].pressed.value, 192 .pressed = console.touch_values[index].pressed.value,
190 }; 193 };
191 194
195 lock.unlock();
192 TriggerOnChange(ConsoleTriggerType::Touch); 196 TriggerOnChange(ConsoleTriggerType::Touch);
193} 197}
194 198
195ConsoleMotionValues EmulatedConsole::GetMotionValues() const { 199ConsoleMotionValues EmulatedConsole::GetMotionValues() const {
200 std::scoped_lock lock{mutex};
196 return console.motion_values; 201 return console.motion_values;
197} 202}
198 203
199TouchValues EmulatedConsole::GetTouchValues() const { 204TouchValues EmulatedConsole::GetTouchValues() const {
205 std::scoped_lock lock{mutex};
200 return console.touch_values; 206 return console.touch_values;
201} 207}
202 208
203ConsoleMotion EmulatedConsole::GetMotion() const { 209ConsoleMotion EmulatedConsole::GetMotion() const {
210 std::scoped_lock lock{mutex};
204 return console.motion_state; 211 return console.motion_state;
205} 212}
206 213
207TouchFingerState EmulatedConsole::GetTouch() const { 214TouchFingerState EmulatedConsole::GetTouch() const {
215 std::scoped_lock lock{mutex};
208 return console.touch_state; 216 return console.touch_state;
209} 217}
210 218
211void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { 219void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
220 std::scoped_lock lock{callback_mutex};
212 for (const auto& poller_pair : callback_list) { 221 for (const auto& poller_pair : callback_list) {
213 const ConsoleUpdateCallback& poller = poller_pair.second; 222 const ConsoleUpdateCallback& poller = poller_pair.second;
214 if (poller.on_change) { 223 if (poller.on_change) {
@@ -218,13 +227,13 @@ void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
218} 227}
219 228
220int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) { 229int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) {
221 std::lock_guard lock{mutex}; 230 std::scoped_lock lock{callback_mutex};
222 callback_list.insert_or_assign(last_callback_key, update_callback); 231 callback_list.insert_or_assign(last_callback_key, update_callback);
223 return last_callback_key++; 232 return last_callback_key++;
224} 233}
225 234
226void EmulatedConsole::DeleteCallback(int key) { 235void EmulatedConsole::DeleteCallback(int key) {
227 std::lock_guard lock{mutex}; 236 std::scoped_lock lock{callback_mutex};
228 const auto& iterator = callback_list.find(key); 237 const auto& iterator = callback_list.find(key);
229 if (iterator == callback_list.end()) { 238 if (iterator == callback_list.end()) {
230 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); 239 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h
index 5eb170823..53677bdc5 100644
--- a/src/core/hid/emulated_console.h
+++ b/src/core/hid/emulated_console.h
@@ -183,6 +183,7 @@ private:
183 TouchDevices touch_devices; 183 TouchDevices touch_devices;
184 184
185 mutable std::mutex mutex; 185 mutable std::mutex mutex;
186 mutable std::mutex callback_mutex;
186 std::unordered_map<int, ConsoleUpdateCallback> callback_list; 187 std::unordered_map<int, ConsoleUpdateCallback> callback_list;
187 int last_callback_key = 0; 188 int last_callback_key = 0;
188 189
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 7e05666d6..c3f21066c 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -353,14 +353,17 @@ void EmulatedController::DisableConfiguration() {
353} 353}
354 354
355void EmulatedController::EnableSystemButtons() { 355void EmulatedController::EnableSystemButtons() {
356 std::scoped_lock lock{mutex};
356 system_buttons_enabled = true; 357 system_buttons_enabled = true;
357} 358}
358 359
359void EmulatedController::DisableSystemButtons() { 360void EmulatedController::DisableSystemButtons() {
361 std::scoped_lock lock{mutex};
360 system_buttons_enabled = false; 362 system_buttons_enabled = false;
361} 363}
362 364
363void EmulatedController::ResetSystemButtons() { 365void EmulatedController::ResetSystemButtons() {
366 std::scoped_lock lock{mutex};
364 controller.home_button_state.home.Assign(false); 367 controller.home_button_state.home.Assign(false);
365 controller.capture_button_state.capture.Assign(false); 368 controller.capture_button_state.capture.Assign(false);
366} 369}
@@ -494,139 +497,141 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
494 if (index >= controller.button_values.size()) { 497 if (index >= controller.button_values.size()) {
495 return; 498 return;
496 } 499 }
497 { 500 std::unique_lock lock{mutex};
498 std::lock_guard lock{mutex}; 501 bool value_changed = false;
499 bool value_changed = false; 502 const auto new_status = TransformToButton(callback);
500 const auto new_status = TransformToButton(callback); 503 auto& current_status = controller.button_values[index];
501 auto& current_status = controller.button_values[index];
502 504
503 // Only read button values that have the same uuid or are pressed once 505 // Only read button values that have the same uuid or are pressed once
504 if (current_status.uuid != uuid) { 506 if (current_status.uuid != uuid) {
505 if (!new_status.value) { 507 if (!new_status.value) {
506 return; 508 return;
507 }
508 } 509 }
510 }
509 511
510 current_status.toggle = new_status.toggle; 512 current_status.toggle = new_status.toggle;
511 current_status.uuid = uuid; 513 current_status.uuid = uuid;
512
513 // Update button status with current
514 if (!current_status.toggle) {
515 current_status.locked = false;
516 if (current_status.value != new_status.value) {
517 current_status.value = new_status.value;
518 value_changed = true;
519 }
520 } else {
521 // Toggle button and lock status
522 if (new_status.value && !current_status.locked) {
523 current_status.locked = true;
524 current_status.value = !current_status.value;
525 value_changed = true;
526 }
527 514
528 // Unlock button ready for next press 515 // Update button status with current
529 if (!new_status.value && current_status.locked) { 516 if (!current_status.toggle) {
530 current_status.locked = false; 517 current_status.locked = false;
531 } 518 if (current_status.value != new_status.value) {
519 current_status.value = new_status.value;
520 value_changed = true;
532 } 521 }
533 522 } else {
534 if (!value_changed) { 523 // Toggle button and lock status
535 return; 524 if (new_status.value && !current_status.locked) {
525 current_status.locked = true;
526 current_status.value = !current_status.value;
527 value_changed = true;
536 } 528 }
537 529
538 if (is_configuring) { 530 // Unlock button ready for next press
539 controller.npad_button_state.raw = NpadButton::None; 531 if (!new_status.value && current_status.locked) {
540 controller.debug_pad_button_state.raw = 0; 532 current_status.locked = false;
541 TriggerOnChange(ControllerTriggerType::Button, false);
542 return;
543 } 533 }
534 }
544 535
545 switch (index) { 536 if (!value_changed) {
546 case Settings::NativeButton::A: 537 return;
547 controller.npad_button_state.a.Assign(current_status.value); 538 }
548 controller.debug_pad_button_state.a.Assign(current_status.value); 539
549 break; 540 if (is_configuring) {
550 case Settings::NativeButton::B: 541 controller.npad_button_state.raw = NpadButton::None;
551 controller.npad_button_state.b.Assign(current_status.value); 542 controller.debug_pad_button_state.raw = 0;
552 controller.debug_pad_button_state.b.Assign(current_status.value); 543 lock.unlock();
553 break; 544 TriggerOnChange(ControllerTriggerType::Button, false);
554 case Settings::NativeButton::X: 545 return;
555 controller.npad_button_state.x.Assign(current_status.value); 546 }
556 controller.debug_pad_button_state.x.Assign(current_status.value); 547
557 break; 548 switch (index) {
558 case Settings::NativeButton::Y: 549 case Settings::NativeButton::A:
559 controller.npad_button_state.y.Assign(current_status.value); 550 controller.npad_button_state.a.Assign(current_status.value);
560 controller.debug_pad_button_state.y.Assign(current_status.value); 551 controller.debug_pad_button_state.a.Assign(current_status.value);
561 break; 552 break;
562 case Settings::NativeButton::LStick: 553 case Settings::NativeButton::B:
563 controller.npad_button_state.stick_l.Assign(current_status.value); 554 controller.npad_button_state.b.Assign(current_status.value);
564 break; 555 controller.debug_pad_button_state.b.Assign(current_status.value);
565 case Settings::NativeButton::RStick: 556 break;
566 controller.npad_button_state.stick_r.Assign(current_status.value); 557 case Settings::NativeButton::X:
567 break; 558 controller.npad_button_state.x.Assign(current_status.value);
568 case Settings::NativeButton::L: 559 controller.debug_pad_button_state.x.Assign(current_status.value);
569 controller.npad_button_state.l.Assign(current_status.value); 560 break;
570 controller.debug_pad_button_state.l.Assign(current_status.value); 561 case Settings::NativeButton::Y:
571 break; 562 controller.npad_button_state.y.Assign(current_status.value);
572 case Settings::NativeButton::R: 563 controller.debug_pad_button_state.y.Assign(current_status.value);
573 controller.npad_button_state.r.Assign(current_status.value); 564 break;
574 controller.debug_pad_button_state.r.Assign(current_status.value); 565 case Settings::NativeButton::LStick:
575 break; 566 controller.npad_button_state.stick_l.Assign(current_status.value);
576 case Settings::NativeButton::ZL: 567 break;
577 controller.npad_button_state.zl.Assign(current_status.value); 568 case Settings::NativeButton::RStick:
578 controller.debug_pad_button_state.zl.Assign(current_status.value); 569 controller.npad_button_state.stick_r.Assign(current_status.value);
579 break; 570 break;
580 case Settings::NativeButton::ZR: 571 case Settings::NativeButton::L:
581 controller.npad_button_state.zr.Assign(current_status.value); 572 controller.npad_button_state.l.Assign(current_status.value);
582 controller.debug_pad_button_state.zr.Assign(current_status.value); 573 controller.debug_pad_button_state.l.Assign(current_status.value);
583 break; 574 break;
584 case Settings::NativeButton::Plus: 575 case Settings::NativeButton::R:
585 controller.npad_button_state.plus.Assign(current_status.value); 576 controller.npad_button_state.r.Assign(current_status.value);
586 controller.debug_pad_button_state.plus.Assign(current_status.value); 577 controller.debug_pad_button_state.r.Assign(current_status.value);
587 break; 578 break;
588 case Settings::NativeButton::Minus: 579 case Settings::NativeButton::ZL:
589 controller.npad_button_state.minus.Assign(current_status.value); 580 controller.npad_button_state.zl.Assign(current_status.value);
590 controller.debug_pad_button_state.minus.Assign(current_status.value); 581 controller.debug_pad_button_state.zl.Assign(current_status.value);
591 break; 582 break;
592 case Settings::NativeButton::DLeft: 583 case Settings::NativeButton::ZR:
593 controller.npad_button_state.left.Assign(current_status.value); 584 controller.npad_button_state.zr.Assign(current_status.value);
594 controller.debug_pad_button_state.d_left.Assign(current_status.value); 585 controller.debug_pad_button_state.zr.Assign(current_status.value);
595 break; 586 break;
596 case Settings::NativeButton::DUp: 587 case Settings::NativeButton::Plus:
597 controller.npad_button_state.up.Assign(current_status.value); 588 controller.npad_button_state.plus.Assign(current_status.value);
598 controller.debug_pad_button_state.d_up.Assign(current_status.value); 589 controller.debug_pad_button_state.plus.Assign(current_status.value);
599 break; 590 break;
600 case Settings::NativeButton::DRight: 591 case Settings::NativeButton::Minus:
601 controller.npad_button_state.right.Assign(current_status.value); 592 controller.npad_button_state.minus.Assign(current_status.value);
602 controller.debug_pad_button_state.d_right.Assign(current_status.value); 593 controller.debug_pad_button_state.minus.Assign(current_status.value);
603 break; 594 break;
604 case Settings::NativeButton::DDown: 595 case Settings::NativeButton::DLeft:
605 controller.npad_button_state.down.Assign(current_status.value); 596 controller.npad_button_state.left.Assign(current_status.value);
606 controller.debug_pad_button_state.d_down.Assign(current_status.value); 597 controller.debug_pad_button_state.d_left.Assign(current_status.value);
607 break; 598 break;
608 case Settings::NativeButton::SL: 599 case Settings::NativeButton::DUp:
609 controller.npad_button_state.left_sl.Assign(current_status.value); 600 controller.npad_button_state.up.Assign(current_status.value);
610 controller.npad_button_state.right_sl.Assign(current_status.value); 601 controller.debug_pad_button_state.d_up.Assign(current_status.value);
611 break; 602 break;
612 case Settings::NativeButton::SR: 603 case Settings::NativeButton::DRight:
613 controller.npad_button_state.left_sr.Assign(current_status.value); 604 controller.npad_button_state.right.Assign(current_status.value);
614 controller.npad_button_state.right_sr.Assign(current_status.value); 605 controller.debug_pad_button_state.d_right.Assign(current_status.value);
615 break; 606 break;
616 case Settings::NativeButton::Home: 607 case Settings::NativeButton::DDown:
617 if (!system_buttons_enabled) { 608 controller.npad_button_state.down.Assign(current_status.value);
618 break; 609 controller.debug_pad_button_state.d_down.Assign(current_status.value);
619 } 610 break;
620 controller.home_button_state.home.Assign(current_status.value); 611 case Settings::NativeButton::SL:
612 controller.npad_button_state.left_sl.Assign(current_status.value);
613 controller.npad_button_state.right_sl.Assign(current_status.value);
614 break;
615 case Settings::NativeButton::SR:
616 controller.npad_button_state.left_sr.Assign(current_status.value);
617 controller.npad_button_state.right_sr.Assign(current_status.value);
618 break;
619 case Settings::NativeButton::Home:
620 if (!system_buttons_enabled) {
621 break; 621 break;
622 case Settings::NativeButton::Screenshot: 622 }
623 if (!system_buttons_enabled) { 623 controller.home_button_state.home.Assign(current_status.value);
624 break; 624 break;
625 } 625 case Settings::NativeButton::Screenshot:
626 controller.capture_button_state.capture.Assign(current_status.value); 626 if (!system_buttons_enabled) {
627 break; 627 break;
628 } 628 }
629 controller.capture_button_state.capture.Assign(current_status.value);
630 break;
629 } 631 }
632
633 lock.unlock();
634
630 if (!is_connected) { 635 if (!is_connected) {
631 if (npad_id_type == NpadIdType::Player1 && npad_type != NpadStyleIndex::Handheld) { 636 if (npad_id_type == NpadIdType::Player1 && npad_type != NpadStyleIndex::Handheld) {
632 Connect(); 637 Connect();
@@ -643,7 +648,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
643 if (index >= controller.stick_values.size()) { 648 if (index >= controller.stick_values.size()) {
644 return; 649 return;
645 } 650 }
646 std::lock_guard lock{mutex}; 651 std::unique_lock lock{mutex};
647 const auto stick_value = TransformToStick(callback); 652 const auto stick_value = TransformToStick(callback);
648 653
649 // Only read stick values that have the same uuid or are over the threshold to avoid flapping 654 // Only read stick values that have the same uuid or are over the threshold to avoid flapping
@@ -659,6 +664,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
659 if (is_configuring) { 664 if (is_configuring) {
660 controller.analog_stick_state.left = {}; 665 controller.analog_stick_state.left = {};
661 controller.analog_stick_state.right = {}; 666 controller.analog_stick_state.right = {};
667 lock.unlock();
662 TriggerOnChange(ControllerTriggerType::Stick, false); 668 TriggerOnChange(ControllerTriggerType::Stick, false);
663 return; 669 return;
664 } 670 }
@@ -685,6 +691,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
685 break; 691 break;
686 } 692 }
687 693
694 lock.unlock();
688 TriggerOnChange(ControllerTriggerType::Stick, true); 695 TriggerOnChange(ControllerTriggerType::Stick, true);
689} 696}
690 697
@@ -693,7 +700,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
693 if (index >= controller.trigger_values.size()) { 700 if (index >= controller.trigger_values.size()) {
694 return; 701 return;
695 } 702 }
696 std::lock_guard lock{mutex}; 703 std::unique_lock lock{mutex};
697 const auto trigger_value = TransformToTrigger(callback); 704 const auto trigger_value = TransformToTrigger(callback);
698 705
699 // Only read trigger values that have the same uuid or are pressed once 706 // Only read trigger values that have the same uuid or are pressed once
@@ -709,6 +716,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
709 if (is_configuring) { 716 if (is_configuring) {
710 controller.gc_trigger_state.left = 0; 717 controller.gc_trigger_state.left = 0;
711 controller.gc_trigger_state.right = 0; 718 controller.gc_trigger_state.right = 0;
719 lock.unlock();
712 TriggerOnChange(ControllerTriggerType::Trigger, false); 720 TriggerOnChange(ControllerTriggerType::Trigger, false);
713 return; 721 return;
714 } 722 }
@@ -727,6 +735,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
727 break; 735 break;
728 } 736 }
729 737
738 lock.unlock();
730 TriggerOnChange(ControllerTriggerType::Trigger, true); 739 TriggerOnChange(ControllerTriggerType::Trigger, true);
731} 740}
732 741
@@ -735,7 +744,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
735 if (index >= controller.motion_values.size()) { 744 if (index >= controller.motion_values.size()) {
736 return; 745 return;
737 } 746 }
738 std::lock_guard lock{mutex}; 747 std::unique_lock lock{mutex};
739 auto& raw_status = controller.motion_values[index].raw_status; 748 auto& raw_status = controller.motion_values[index].raw_status;
740 auto& emulated = controller.motion_values[index].emulated; 749 auto& emulated = controller.motion_values[index].emulated;
741 750
@@ -756,6 +765,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
756 force_update_motion = raw_status.force_update; 765 force_update_motion = raw_status.force_update;
757 766
758 if (is_configuring) { 767 if (is_configuring) {
768 lock.unlock();
759 TriggerOnChange(ControllerTriggerType::Motion, false); 769 TriggerOnChange(ControllerTriggerType::Motion, false);
760 return; 770 return;
761 } 771 }
@@ -767,6 +777,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
767 motion.orientation = emulated.GetOrientation(); 777 motion.orientation = emulated.GetOrientation();
768 motion.is_at_rest = !emulated.IsMoving(motion_sensitivity); 778 motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
769 779
780 lock.unlock();
770 TriggerOnChange(ControllerTriggerType::Motion, true); 781 TriggerOnChange(ControllerTriggerType::Motion, true);
771} 782}
772 783
@@ -775,10 +786,11 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
775 if (index >= controller.battery_values.size()) { 786 if (index >= controller.battery_values.size()) {
776 return; 787 return;
777 } 788 }
778 std::lock_guard lock{mutex}; 789 std::unique_lock lock{mutex};
779 controller.battery_values[index] = TransformToBattery(callback); 790 controller.battery_values[index] = TransformToBattery(callback);
780 791
781 if (is_configuring) { 792 if (is_configuring) {
793 lock.unlock();
782 TriggerOnChange(ControllerTriggerType::Battery, false); 794 TriggerOnChange(ControllerTriggerType::Battery, false);
783 return; 795 return;
784 } 796 }
@@ -835,6 +847,8 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
835 }; 847 };
836 break; 848 break;
837 } 849 }
850
851 lock.unlock();
838 TriggerOnChange(ControllerTriggerType::Battery, true); 852 TriggerOnChange(ControllerTriggerType::Battery, true);
839} 853}
840 854
@@ -932,6 +946,7 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
932} 946}
933 947
934bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const { 948bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
949 std::scoped_lock lock{mutex};
935 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; 950 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
936 switch (type) { 951 switch (type) {
937 case NpadStyleIndex::ProController: 952 case NpadStyleIndex::ProController:
@@ -947,6 +962,7 @@ bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
947} 962}
948 963
949bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { 964bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
965 std::scoped_lock lock{mutex};
950 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; 966 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
951 switch (type) { 967 switch (type) {
952 case NpadStyleIndex::ProController: 968 case NpadStyleIndex::ProController:
@@ -982,40 +998,44 @@ void EmulatedController::Connect(bool use_temporary_value) {
982 LOG_ERROR(Service_HID, "Controller type {} is not supported", type); 998 LOG_ERROR(Service_HID, "Controller type {} is not supported", type);
983 return; 999 return;
984 } 1000 }
985 {
986 std::lock_guard lock{mutex};
987 if (is_configuring) {
988 tmp_is_connected = true;
989 TriggerOnChange(ControllerTriggerType::Connected, false);
990 return;
991 }
992 1001
993 if (is_connected) { 1002 std::unique_lock lock{mutex};
994 return; 1003 if (is_configuring) {
995 } 1004 tmp_is_connected = true;
996 is_connected = true; 1005 lock.unlock();
1006 TriggerOnChange(ControllerTriggerType::Connected, false);
1007 return;
1008 }
1009
1010 if (is_connected) {
1011 return;
997 } 1012 }
1013 is_connected = true;
1014
1015 lock.unlock();
998 TriggerOnChange(ControllerTriggerType::Connected, true); 1016 TriggerOnChange(ControllerTriggerType::Connected, true);
999} 1017}
1000 1018
1001void EmulatedController::Disconnect() { 1019void EmulatedController::Disconnect() {
1002 { 1020 std::unique_lock lock{mutex};
1003 std::lock_guard lock{mutex}; 1021 if (is_configuring) {
1004 if (is_configuring) { 1022 tmp_is_connected = false;
1005 tmp_is_connected = false; 1023 lock.unlock();
1006 TriggerOnChange(ControllerTriggerType::Disconnected, false); 1024 TriggerOnChange(ControllerTriggerType::Disconnected, false);
1007 return; 1025 return;
1008 } 1026 }
1009 1027
1010 if (!is_connected) { 1028 if (!is_connected) {
1011 return; 1029 return;
1012 }
1013 is_connected = false;
1014 } 1030 }
1031 is_connected = false;
1032
1033 lock.unlock();
1015 TriggerOnChange(ControllerTriggerType::Disconnected, true); 1034 TriggerOnChange(ControllerTriggerType::Disconnected, true);
1016} 1035}
1017 1036
1018bool EmulatedController::IsConnected(bool get_temporary_value) const { 1037bool EmulatedController::IsConnected(bool get_temporary_value) const {
1038 std::scoped_lock lock{mutex};
1019 if (get_temporary_value && is_configuring) { 1039 if (get_temporary_value && is_configuring) {
1020 return tmp_is_connected; 1040 return tmp_is_connected;
1021 } 1041 }
@@ -1029,10 +1049,12 @@ bool EmulatedController::IsVibrationEnabled() const {
1029} 1049}
1030 1050
1031NpadIdType EmulatedController::GetNpadIdType() const { 1051NpadIdType EmulatedController::GetNpadIdType() const {
1052 std::scoped_lock lock{mutex};
1032 return npad_id_type; 1053 return npad_id_type;
1033} 1054}
1034 1055
1035NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const { 1056NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const {
1057 std::scoped_lock lock{mutex};
1036 if (get_temporary_value && is_configuring) { 1058 if (get_temporary_value && is_configuring) {
1037 return tmp_npad_type; 1059 return tmp_npad_type;
1038 } 1060 }
@@ -1040,27 +1062,28 @@ NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) c
1040} 1062}
1041 1063
1042void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { 1064void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
1043 { 1065 std::unique_lock lock{mutex};
1044 std::lock_guard lock{mutex};
1045 1066
1046 if (is_configuring) { 1067 if (is_configuring) {
1047 if (tmp_npad_type == npad_type_) { 1068 if (tmp_npad_type == npad_type_) {
1048 return;
1049 }
1050 tmp_npad_type = npad_type_;
1051 TriggerOnChange(ControllerTriggerType::Type, false);
1052 return; 1069 return;
1053 } 1070 }
1071 tmp_npad_type = npad_type_;
1072 lock.unlock();
1073 TriggerOnChange(ControllerTriggerType::Type, false);
1074 return;
1075 }
1054 1076
1055 if (npad_type == npad_type_) { 1077 if (npad_type == npad_type_) {
1056 return; 1078 return;
1057 } 1079 }
1058 if (is_connected) { 1080 if (is_connected) {
1059 LOG_WARNING(Service_HID, "Controller {} type changed while it's connected", 1081 LOG_WARNING(Service_HID, "Controller {} type changed while it's connected",
1060 NpadIdTypeToIndex(npad_id_type)); 1082 NpadIdTypeToIndex(npad_id_type));
1061 }
1062 npad_type = npad_type_;
1063 } 1083 }
1084 npad_type = npad_type_;
1085
1086 lock.unlock();
1064 TriggerOnChange(ControllerTriggerType::Type, true); 1087 TriggerOnChange(ControllerTriggerType::Type, true);
1065} 1088}
1066 1089
@@ -1088,30 +1111,37 @@ LedPattern EmulatedController::GetLedPattern() const {
1088} 1111}
1089 1112
1090ButtonValues EmulatedController::GetButtonsValues() const { 1113ButtonValues EmulatedController::GetButtonsValues() const {
1114 std::scoped_lock lock{mutex};
1091 return controller.button_values; 1115 return controller.button_values;
1092} 1116}
1093 1117
1094SticksValues EmulatedController::GetSticksValues() const { 1118SticksValues EmulatedController::GetSticksValues() const {
1119 std::scoped_lock lock{mutex};
1095 return controller.stick_values; 1120 return controller.stick_values;
1096} 1121}
1097 1122
1098TriggerValues EmulatedController::GetTriggersValues() const { 1123TriggerValues EmulatedController::GetTriggersValues() const {
1124 std::scoped_lock lock{mutex};
1099 return controller.trigger_values; 1125 return controller.trigger_values;
1100} 1126}
1101 1127
1102ControllerMotionValues EmulatedController::GetMotionValues() const { 1128ControllerMotionValues EmulatedController::GetMotionValues() const {
1129 std::scoped_lock lock{mutex};
1103 return controller.motion_values; 1130 return controller.motion_values;
1104} 1131}
1105 1132
1106ColorValues EmulatedController::GetColorsValues() const { 1133ColorValues EmulatedController::GetColorsValues() const {
1134 std::scoped_lock lock{mutex};
1107 return controller.color_values; 1135 return controller.color_values;
1108} 1136}
1109 1137
1110BatteryValues EmulatedController::GetBatteryValues() const { 1138BatteryValues EmulatedController::GetBatteryValues() const {
1139 std::scoped_lock lock{mutex};
1111 return controller.battery_values; 1140 return controller.battery_values;
1112} 1141}
1113 1142
1114HomeButtonState EmulatedController::GetHomeButtons() const { 1143HomeButtonState EmulatedController::GetHomeButtons() const {
1144 std::scoped_lock lock{mutex};
1115 if (is_configuring) { 1145 if (is_configuring) {
1116 return {}; 1146 return {};
1117 } 1147 }
@@ -1119,6 +1149,7 @@ HomeButtonState EmulatedController::GetHomeButtons() const {
1119} 1149}
1120 1150
1121CaptureButtonState EmulatedController::GetCaptureButtons() const { 1151CaptureButtonState EmulatedController::GetCaptureButtons() const {
1152 std::scoped_lock lock{mutex};
1122 if (is_configuring) { 1153 if (is_configuring) {
1123 return {}; 1154 return {};
1124 } 1155 }
@@ -1126,6 +1157,7 @@ CaptureButtonState EmulatedController::GetCaptureButtons() const {
1126} 1157}
1127 1158
1128NpadButtonState EmulatedController::GetNpadButtons() const { 1159NpadButtonState EmulatedController::GetNpadButtons() const {
1160 std::scoped_lock lock{mutex};
1129 if (is_configuring) { 1161 if (is_configuring) {
1130 return {}; 1162 return {};
1131 } 1163 }
@@ -1133,6 +1165,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const {
1133} 1165}
1134 1166
1135DebugPadButton EmulatedController::GetDebugPadButtons() const { 1167DebugPadButton EmulatedController::GetDebugPadButtons() const {
1168 std::scoped_lock lock{mutex};
1136 if (is_configuring) { 1169 if (is_configuring) {
1137 return {}; 1170 return {};
1138 } 1171 }
@@ -1140,20 +1173,27 @@ DebugPadButton EmulatedController::GetDebugPadButtons() const {
1140} 1173}
1141 1174
1142AnalogSticks EmulatedController::GetSticks() const { 1175AnalogSticks EmulatedController::GetSticks() const {
1176 std::unique_lock lock{mutex};
1177
1143 if (is_configuring) { 1178 if (is_configuring) {
1144 return {}; 1179 return {};
1145 } 1180 }
1181
1146 // Some drivers like stick from buttons need constant refreshing 1182 // Some drivers like stick from buttons need constant refreshing
1147 for (auto& device : stick_devices) { 1183 for (auto& device : stick_devices) {
1148 if (!device) { 1184 if (!device) {
1149 continue; 1185 continue;
1150 } 1186 }
1187 lock.unlock();
1151 device->SoftUpdate(); 1188 device->SoftUpdate();
1189 lock.lock();
1152 } 1190 }
1191
1153 return controller.analog_stick_state; 1192 return controller.analog_stick_state;
1154} 1193}
1155 1194
1156NpadGcTriggerState EmulatedController::GetTriggers() const { 1195NpadGcTriggerState EmulatedController::GetTriggers() const {
1196 std::scoped_lock lock{mutex};
1157 if (is_configuring) { 1197 if (is_configuring) {
1158 return {}; 1198 return {};
1159 } 1199 }
@@ -1161,26 +1201,35 @@ NpadGcTriggerState EmulatedController::GetTriggers() const {
1161} 1201}
1162 1202
1163MotionState EmulatedController::GetMotions() const { 1203MotionState EmulatedController::GetMotions() const {
1204 std::unique_lock lock{mutex};
1205
1206 // Some drivers like mouse motion need constant refreshing
1164 if (force_update_motion) { 1207 if (force_update_motion) {
1165 for (auto& device : motion_devices) { 1208 for (auto& device : motion_devices) {
1166 if (!device) { 1209 if (!device) {
1167 continue; 1210 continue;
1168 } 1211 }
1212 lock.unlock();
1169 device->ForceUpdate(); 1213 device->ForceUpdate();
1214 lock.lock();
1170 } 1215 }
1171 } 1216 }
1217
1172 return controller.motion_state; 1218 return controller.motion_state;
1173} 1219}
1174 1220
1175ControllerColors EmulatedController::GetColors() const { 1221ControllerColors EmulatedController::GetColors() const {
1222 std::scoped_lock lock{mutex};
1176 return controller.colors_state; 1223 return controller.colors_state;
1177} 1224}
1178 1225
1179BatteryLevelState EmulatedController::GetBattery() const { 1226BatteryLevelState EmulatedController::GetBattery() const {
1227 std::scoped_lock lock{mutex};
1180 return controller.battery_state; 1228 return controller.battery_state;
1181} 1229}
1182 1230
1183void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { 1231void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) {
1232 std::scoped_lock lock{callback_mutex};
1184 for (const auto& poller_pair : callback_list) { 1233 for (const auto& poller_pair : callback_list) {
1185 const ControllerUpdateCallback& poller = poller_pair.second; 1234 const ControllerUpdateCallback& poller = poller_pair.second;
1186 if (!is_npad_service_update && poller.is_npad_service) { 1235 if (!is_npad_service_update && poller.is_npad_service) {
@@ -1193,13 +1242,13 @@ void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npa
1193} 1242}
1194 1243
1195int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) { 1244int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) {
1196 std::lock_guard lock{mutex}; 1245 std::scoped_lock lock{callback_mutex};
1197 callback_list.insert_or_assign(last_callback_key, std::move(update_callback)); 1246 callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
1198 return last_callback_key++; 1247 return last_callback_key++;
1199} 1248}
1200 1249
1201void EmulatedController::DeleteCallback(int key) { 1250void EmulatedController::DeleteCallback(int key) {
1202 std::lock_guard lock{mutex}; 1251 std::scoped_lock lock{callback_mutex};
1203 const auto& iterator = callback_list.find(key); 1252 const auto& iterator = callback_list.find(key);
1204 if (iterator == callback_list.end()) { 1253 if (iterator == callback_list.end()) {
1205 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); 1254 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index aa52f9572..1e224685d 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -400,7 +400,7 @@ private:
400 */ 400 */
401 void TriggerOnChange(ControllerTriggerType type, bool is_service_update); 401 void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
402 402
403 NpadIdType npad_id_type; 403 const NpadIdType npad_id_type;
404 NpadStyleIndex npad_type{NpadStyleIndex::None}; 404 NpadStyleIndex npad_type{NpadStyleIndex::None};
405 NpadStyleTag supported_style_tag{NpadStyleSet::All}; 405 NpadStyleTag supported_style_tag{NpadStyleSet::All};
406 bool is_connected{false}; 406 bool is_connected{false};
@@ -434,6 +434,7 @@ private:
434 StickDevices tas_stick_devices; 434 StickDevices tas_stick_devices;
435 435
436 mutable std::mutex mutex; 436 mutable std::mutex mutex;
437 mutable std::mutex callback_mutex;
437 std::unordered_map<int, ControllerUpdateCallback> callback_list; 438 std::unordered_map<int, ControllerUpdateCallback> callback_list;
438 int last_callback_key = 0; 439 int last_callback_key = 0;
439 440
diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp
index 708480f2d..cc0dcd931 100644
--- a/src/core/hid/emulated_devices.cpp
+++ b/src/core/hid/emulated_devices.cpp
@@ -169,7 +169,7 @@ void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& cal
169 if (index >= device_status.keyboard_values.size()) { 169 if (index >= device_status.keyboard_values.size()) {
170 return; 170 return;
171 } 171 }
172 std::lock_guard lock{mutex}; 172 std::unique_lock lock{mutex};
173 bool value_changed = false; 173 bool value_changed = false;
174 const auto new_status = TransformToButton(callback); 174 const auto new_status = TransformToButton(callback);
175 auto& current_status = device_status.keyboard_values[index]; 175 auto& current_status = device_status.keyboard_values[index];
@@ -201,6 +201,7 @@ void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& cal
201 } 201 }
202 202
203 if (is_configuring) { 203 if (is_configuring) {
204 lock.unlock();
204 TriggerOnChange(DeviceTriggerType::Keyboard); 205 TriggerOnChange(DeviceTriggerType::Keyboard);
205 return; 206 return;
206 } 207 }
@@ -208,6 +209,7 @@ void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& cal
208 // Index should be converted from NativeKeyboard to KeyboardKeyIndex 209 // Index should be converted from NativeKeyboard to KeyboardKeyIndex
209 UpdateKey(index, current_status.value); 210 UpdateKey(index, current_status.value);
210 211
212 lock.unlock();
211 TriggerOnChange(DeviceTriggerType::Keyboard); 213 TriggerOnChange(DeviceTriggerType::Keyboard);
212} 214}
213 215
@@ -227,7 +229,7 @@ void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& c
227 if (index >= device_status.keyboard_moddifier_values.size()) { 229 if (index >= device_status.keyboard_moddifier_values.size()) {
228 return; 230 return;
229 } 231 }
230 std::lock_guard lock{mutex}; 232 std::unique_lock lock{mutex};
231 bool value_changed = false; 233 bool value_changed = false;
232 const auto new_status = TransformToButton(callback); 234 const auto new_status = TransformToButton(callback);
233 auto& current_status = device_status.keyboard_moddifier_values[index]; 235 auto& current_status = device_status.keyboard_moddifier_values[index];
@@ -259,6 +261,7 @@ void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& c
259 } 261 }
260 262
261 if (is_configuring) { 263 if (is_configuring) {
264 lock.unlock();
262 TriggerOnChange(DeviceTriggerType::KeyboardModdifier); 265 TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
263 return; 266 return;
264 } 267 }
@@ -289,6 +292,7 @@ void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& c
289 break; 292 break;
290 } 293 }
291 294
295 lock.unlock();
292 TriggerOnChange(DeviceTriggerType::KeyboardModdifier); 296 TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
293} 297}
294 298
@@ -297,7 +301,7 @@ void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callba
297 if (index >= device_status.mouse_button_values.size()) { 301 if (index >= device_status.mouse_button_values.size()) {
298 return; 302 return;
299 } 303 }
300 std::lock_guard lock{mutex}; 304 std::unique_lock lock{mutex};
301 bool value_changed = false; 305 bool value_changed = false;
302 const auto new_status = TransformToButton(callback); 306 const auto new_status = TransformToButton(callback);
303 auto& current_status = device_status.mouse_button_values[index]; 307 auto& current_status = device_status.mouse_button_values[index];
@@ -329,6 +333,7 @@ void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callba
329 } 333 }
330 334
331 if (is_configuring) { 335 if (is_configuring) {
336 lock.unlock();
332 TriggerOnChange(DeviceTriggerType::Mouse); 337 TriggerOnChange(DeviceTriggerType::Mouse);
333 return; 338 return;
334 } 339 }
@@ -351,6 +356,7 @@ void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callba
351 break; 356 break;
352 } 357 }
353 358
359 lock.unlock();
354 TriggerOnChange(DeviceTriggerType::Mouse); 360 TriggerOnChange(DeviceTriggerType::Mouse);
355} 361}
356 362
@@ -359,13 +365,14 @@ void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callba
359 if (index >= device_status.mouse_analog_values.size()) { 365 if (index >= device_status.mouse_analog_values.size()) {
360 return; 366 return;
361 } 367 }
362 std::lock_guard lock{mutex}; 368 std::unique_lock lock{mutex};
363 const auto analog_value = TransformToAnalog(callback); 369 const auto analog_value = TransformToAnalog(callback);
364 370
365 device_status.mouse_analog_values[index] = analog_value; 371 device_status.mouse_analog_values[index] = analog_value;
366 372
367 if (is_configuring) { 373 if (is_configuring) {
368 device_status.mouse_position_state = {}; 374 device_status.mouse_position_state = {};
375 lock.unlock();
369 TriggerOnChange(DeviceTriggerType::Mouse); 376 TriggerOnChange(DeviceTriggerType::Mouse);
370 return; 377 return;
371 } 378 }
@@ -379,17 +386,19 @@ void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callba
379 break; 386 break;
380 } 387 }
381 388
389 lock.unlock();
382 TriggerOnChange(DeviceTriggerType::Mouse); 390 TriggerOnChange(DeviceTriggerType::Mouse);
383} 391}
384 392
385void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) { 393void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) {
386 std::lock_guard lock{mutex}; 394 std::unique_lock lock{mutex};
387 const auto touch_value = TransformToTouch(callback); 395 const auto touch_value = TransformToTouch(callback);
388 396
389 device_status.mouse_stick_value = touch_value; 397 device_status.mouse_stick_value = touch_value;
390 398
391 if (is_configuring) { 399 if (is_configuring) {
392 device_status.mouse_position_state = {}; 400 device_status.mouse_position_state = {};
401 lock.unlock();
393 TriggerOnChange(DeviceTriggerType::Mouse); 402 TriggerOnChange(DeviceTriggerType::Mouse);
394 return; 403 return;
395 } 404 }
@@ -397,42 +406,52 @@ void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callbac
397 device_status.mouse_position_state.x = touch_value.x.value; 406 device_status.mouse_position_state.x = touch_value.x.value;
398 device_status.mouse_position_state.y = touch_value.y.value; 407 device_status.mouse_position_state.y = touch_value.y.value;
399 408
409 lock.unlock();
400 TriggerOnChange(DeviceTriggerType::Mouse); 410 TriggerOnChange(DeviceTriggerType::Mouse);
401} 411}
402 412
403KeyboardValues EmulatedDevices::GetKeyboardValues() const { 413KeyboardValues EmulatedDevices::GetKeyboardValues() const {
414 std::scoped_lock lock{mutex};
404 return device_status.keyboard_values; 415 return device_status.keyboard_values;
405} 416}
406 417
407KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const { 418KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const {
419 std::scoped_lock lock{mutex};
408 return device_status.keyboard_moddifier_values; 420 return device_status.keyboard_moddifier_values;
409} 421}
410 422
411MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const { 423MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
424 std::scoped_lock lock{mutex};
412 return device_status.mouse_button_values; 425 return device_status.mouse_button_values;
413} 426}
414 427
415KeyboardKey EmulatedDevices::GetKeyboard() const { 428KeyboardKey EmulatedDevices::GetKeyboard() const {
429 std::scoped_lock lock{mutex};
416 return device_status.keyboard_state; 430 return device_status.keyboard_state;
417} 431}
418 432
419KeyboardModifier EmulatedDevices::GetKeyboardModifier() const { 433KeyboardModifier EmulatedDevices::GetKeyboardModifier() const {
434 std::scoped_lock lock{mutex};
420 return device_status.keyboard_moddifier_state; 435 return device_status.keyboard_moddifier_state;
421} 436}
422 437
423MouseButton EmulatedDevices::GetMouseButtons() const { 438MouseButton EmulatedDevices::GetMouseButtons() const {
439 std::scoped_lock lock{mutex};
424 return device_status.mouse_button_state; 440 return device_status.mouse_button_state;
425} 441}
426 442
427MousePosition EmulatedDevices::GetMousePosition() const { 443MousePosition EmulatedDevices::GetMousePosition() const {
444 std::scoped_lock lock{mutex};
428 return device_status.mouse_position_state; 445 return device_status.mouse_position_state;
429} 446}
430 447
431AnalogStickState EmulatedDevices::GetMouseWheel() const { 448AnalogStickState EmulatedDevices::GetMouseWheel() const {
449 std::scoped_lock lock{mutex};
432 return device_status.mouse_wheel_state; 450 return device_status.mouse_wheel_state;
433} 451}
434 452
435void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { 453void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
454 std::scoped_lock lock{callback_mutex};
436 for (const auto& poller_pair : callback_list) { 455 for (const auto& poller_pair : callback_list) {
437 const InterfaceUpdateCallback& poller = poller_pair.second; 456 const InterfaceUpdateCallback& poller = poller_pair.second;
438 if (poller.on_change) { 457 if (poller.on_change) {
@@ -442,13 +461,13 @@ void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
442} 461}
443 462
444int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) { 463int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {
445 std::lock_guard lock{mutex}; 464 std::scoped_lock lock{callback_mutex};
446 callback_list.insert_or_assign(last_callback_key, std::move(update_callback)); 465 callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
447 return last_callback_key++; 466 return last_callback_key++;
448} 467}
449 468
450void EmulatedDevices::DeleteCallback(int key) { 469void EmulatedDevices::DeleteCallback(int key) {
451 std::lock_guard lock{mutex}; 470 std::scoped_lock lock{callback_mutex};
452 const auto& iterator = callback_list.find(key); 471 const auto& iterator = callback_list.find(key);
453 if (iterator == callback_list.end()) { 472 if (iterator == callback_list.end()) {
454 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); 473 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h
index 790d3b411..73e9f0293 100644
--- a/src/core/hid/emulated_devices.h
+++ b/src/core/hid/emulated_devices.h
@@ -200,6 +200,7 @@ private:
200 MouseStickDevice mouse_stick_device; 200 MouseStickDevice mouse_stick_device;
201 201
202 mutable std::mutex mutex; 202 mutable std::mutex mutex;
203 mutable std::mutex callback_mutex;
203 std::unordered_map<int, InterfaceUpdateCallback> callback_list; 204 std::unordered_map<int, InterfaceUpdateCallback> callback_list;
204 int last_callback_key = 0; 205 int last_callback_key = 0;
205 206
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 42d1b0e31..b547a3463 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -24,8 +24,15 @@
24 24
25namespace Kernel { 25namespace Kernel {
26 26
27SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_) 27SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
28 : kernel{kernel_}, service_thread{kernel.CreateServiceThread(service_name_)} {} 28 ServiceThreadType thread_type)
29 : kernel{kernel_} {
30 if (thread_type == ServiceThreadType::CreateNew) {
31 service_thread = kernel.CreateServiceThread(service_name_);
32 } else {
33 service_thread = kernel.GetDefaultServiceThread();
34 }
35}
29 36
30SessionRequestHandler::~SessionRequestHandler() { 37SessionRequestHandler::~SessionRequestHandler() {
31 kernel.ReleaseServiceThread(service_thread); 38 kernel.ReleaseServiceThread(service_thread);
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 670cc741c..640146137 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -33,6 +33,11 @@ namespace Service {
33class ServiceFrameworkBase; 33class ServiceFrameworkBase;
34} 34}
35 35
36enum class ServiceThreadType {
37 Default,
38 CreateNew,
39};
40
36namespace Kernel { 41namespace Kernel {
37 42
38class Domain; 43class Domain;
@@ -57,7 +62,8 @@ enum class ThreadWakeupReason;
57 */ 62 */
58class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> { 63class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
59public: 64public:
60 SessionRequestHandler(KernelCore& kernel, const char* service_name_); 65 SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
66 ServiceThreadType thread_type);
61 virtual ~SessionRequestHandler(); 67 virtual ~SessionRequestHandler();
62 68
63 /** 69 /**
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 34da7c23b..134a0b8e9 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -61,6 +61,7 @@ struct KernelCore::Impl {
61 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); 61 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
62 global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); 62 global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
63 global_handle_table->Initialize(KHandleTable::MaxTableSize); 63 global_handle_table->Initialize(KHandleTable::MaxTableSize);
64 default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
64 65
65 is_phantom_mode_for_singlecore = false; 66 is_phantom_mode_for_singlecore = false;
66 67
@@ -98,7 +99,7 @@ struct KernelCore::Impl {
98 // Close all open server ports. 99 // Close all open server ports.
99 std::unordered_set<KServerPort*> server_ports_; 100 std::unordered_set<KServerPort*> server_ports_;
100 { 101 {
101 std::lock_guard lk(server_ports_lock); 102 std::scoped_lock lk{server_ports_lock};
102 server_ports_ = server_ports; 103 server_ports_ = server_ports;
103 server_ports.clear(); 104 server_ports.clear();
104 } 105 }
@@ -156,7 +157,7 @@ struct KernelCore::Impl {
156 157
157 // Close kernel objects that were not freed on shutdown 158 // Close kernel objects that were not freed on shutdown
158 { 159 {
159 std::lock_guard lk(registered_in_use_objects_lock); 160 std::scoped_lock lk{registered_in_use_objects_lock};
160 if (registered_in_use_objects.size()) { 161 if (registered_in_use_objects.size()) {
161 for (auto& object : registered_in_use_objects) { 162 for (auto& object : registered_in_use_objects) {
162 object->Close(); 163 object->Close();
@@ -177,7 +178,7 @@ struct KernelCore::Impl {
177 178
178 // Track kernel objects that were not freed on shutdown 179 // Track kernel objects that were not freed on shutdown
179 { 180 {
180 std::lock_guard lk(registered_objects_lock); 181 std::scoped_lock lk{registered_objects_lock};
181 if (registered_objects.size()) { 182 if (registered_objects.size()) {
182 LOG_DEBUG(Kernel, "{} kernel objects were dangling on shutdown!", 183 LOG_DEBUG(Kernel, "{} kernel objects were dangling on shutdown!",
183 registered_objects.size()); 184 registered_objects.size());
@@ -659,7 +660,7 @@ struct KernelCore::Impl {
659 660
660 KClientPort* port = &search->second(system.ServiceManager(), system); 661 KClientPort* port = &search->second(system.ServiceManager(), system);
661 { 662 {
662 std::lock_guard lk(server_ports_lock); 663 std::scoped_lock lk{server_ports_lock};
663 server_ports.insert(&port->GetParent()->GetServerPort()); 664 server_ports.insert(&port->GetParent()->GetServerPort());
664 } 665 }
665 return port; 666 return port;
@@ -677,6 +678,12 @@ struct KernelCore::Impl {
677 678
678 void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) { 679 void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
679 if (auto strong_ptr = service_thread.lock()) { 680 if (auto strong_ptr = service_thread.lock()) {
681 if (strong_ptr == default_service_thread.lock()) {
682 // Nothing to do here, the service is using default_service_thread, which will be
683 // released on shutdown.
684 return;
685 }
686
680 service_threads_manager.QueueWork( 687 service_threads_manager.QueueWork(
681 [this, strong_ptr{std::move(strong_ptr)}]() { service_threads.erase(strong_ptr); }); 688 [this, strong_ptr{std::move(strong_ptr)}]() { service_threads.erase(strong_ptr); });
682 } 689 }
@@ -739,7 +746,8 @@ struct KernelCore::Impl {
739 std::unique_ptr<KMemoryLayout> memory_layout; 746 std::unique_ptr<KMemoryLayout> memory_layout;
740 747
741 // Threads used for services 748 // Threads used for services
742 std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads; 749 std::unordered_set<std::shared_ptr<ServiceThread>> service_threads;
750 std::weak_ptr<ServiceThread> default_service_thread;
743 Common::ThreadWorker service_threads_manager; 751 Common::ThreadWorker service_threads_manager;
744 752
745 std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads; 753 std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads;
@@ -921,22 +929,22 @@ KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
921} 929}
922 930
923void KernelCore::RegisterKernelObject(KAutoObject* object) { 931void KernelCore::RegisterKernelObject(KAutoObject* object) {
924 std::lock_guard lk(impl->registered_objects_lock); 932 std::scoped_lock lk{impl->registered_objects_lock};
925 impl->registered_objects.insert(object); 933 impl->registered_objects.insert(object);
926} 934}
927 935
928void KernelCore::UnregisterKernelObject(KAutoObject* object) { 936void KernelCore::UnregisterKernelObject(KAutoObject* object) {
929 std::lock_guard lk(impl->registered_objects_lock); 937 std::scoped_lock lk{impl->registered_objects_lock};
930 impl->registered_objects.erase(object); 938 impl->registered_objects.erase(object);
931} 939}
932 940
933void KernelCore::RegisterInUseObject(KAutoObject* object) { 941void KernelCore::RegisterInUseObject(KAutoObject* object) {
934 std::lock_guard lk(impl->registered_in_use_objects_lock); 942 std::scoped_lock lk{impl->registered_in_use_objects_lock};
935 impl->registered_in_use_objects.insert(object); 943 impl->registered_in_use_objects.insert(object);
936} 944}
937 945
938void KernelCore::UnregisterInUseObject(KAutoObject* object) { 946void KernelCore::UnregisterInUseObject(KAutoObject* object) {
939 std::lock_guard lk(impl->registered_in_use_objects_lock); 947 std::scoped_lock lk{impl->registered_in_use_objects_lock};
940 impl->registered_in_use_objects.erase(object); 948 impl->registered_in_use_objects.erase(object);
941} 949}
942 950
@@ -1065,6 +1073,10 @@ std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::
1065 return impl->CreateServiceThread(*this, name); 1073 return impl->CreateServiceThread(*this, name);
1066} 1074}
1067 1075
1076std::weak_ptr<Kernel::ServiceThread> KernelCore::GetDefaultServiceThread() const {
1077 return impl->default_service_thread;
1078}
1079
1068void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) { 1080void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
1069 impl->ReleaseServiceThread(service_thread); 1081 impl->ReleaseServiceThread(service_thread);
1070} 1082}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 4c68e96df..24e26fa44 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -271,9 +271,11 @@ public:
271 void ExitSVCProfile(); 271 void ExitSVCProfile();
272 272
273 /** 273 /**
274 * Creates an HLE service thread, which are used to execute service routines asynchronously. 274 * Creates a host thread to execute HLE service requests, which are used to execute service
275 * While these are allocated per ServerSession, these need to be owned and managed outside 275 * routines asynchronously. While these are allocated per ServerSession, these need to be owned
276 * of ServerSession to avoid a circular dependency. 276 * and managed outside of ServerSession to avoid a circular dependency. In general, most
277 * services can just use the default service thread, and not need their own host service thread.
278 * See GetDefaultServiceThread.
277 * @param name String name for the ServerSession creating this thread, used for debug 279 * @param name String name for the ServerSession creating this thread, used for debug
278 * purposes. 280 * purposes.
279 * @returns The a weak pointer newly created service thread. 281 * @returns The a weak pointer newly created service thread.
@@ -281,6 +283,14 @@ public:
281 std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name); 283 std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name);
282 284
283 /** 285 /**
286 * Gets the default host service thread, which executes HLE service requests. Unless service
287 * requests need to block on the host, the default service thread should be used in favor of
288 * creating a new service thread.
289 * @returns The a weak pointer for the default service thread.
290 */
291 std::weak_ptr<Kernel::ServiceThread> GetDefaultServiceThread() const;
292
293 /**
284 * Releases a HLE service thread, instructing KernelCore to free it. This should be called when 294 * Releases a HLE service thread, instructing KernelCore to free it. This should be called when
285 * the ServerSession associated with the thread is destroyed. 295 * the ServerSession associated with the thread is destroyed.
286 * @param service_thread Service thread to release. 296 * @param service_thread Service thread to release.
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp
index 7477668e4..18a5f40f8 100644
--- a/src/core/hle/kernel/physical_core.cpp
+++ b/src/core/hle/kernel/physical_core.cpp
@@ -58,6 +58,7 @@ bool PhysicalCore::IsInterrupted() const {
58void PhysicalCore::Interrupt() { 58void PhysicalCore::Interrupt() {
59 guard->lock(); 59 guard->lock();
60 interrupts[core_index].SetInterrupt(true); 60 interrupts[core_index].SetInterrupt(true);
61 arm_interface->SignalInterrupt();
61 guard->unlock(); 62 guard->unlock();
62} 63}
63 64
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index aa985d820..5b8fe8eae 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -24,7 +24,7 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} {
24} 24}
25 25
26void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { 26void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) {
27 std::lock_guard lock{mutex}; 27 std::scoped_lock lock{mutex};
28 if (nanoseconds > 0) { 28 if (nanoseconds > 0) {
29 ASSERT(thread); 29 ASSERT(thread);
30 ASSERT(thread->GetState() != ThreadState::Runnable); 30 ASSERT(thread->GetState() != ThreadState::Runnable);
@@ -35,7 +35,7 @@ void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) {
35} 35}
36 36
37void TimeManager::UnscheduleTimeEvent(KThread* thread) { 37void TimeManager::UnscheduleTimeEvent(KThread* thread) {
38 std::lock_guard lock{mutex}; 38 std::scoped_lock lock{mutex};
39 system.CoreTiming().UnscheduleEvent(time_manager_event_type, 39 system.CoreTiming().UnscheduleEvent(time_manager_event_type,
40 reinterpret_cast<uintptr_t>(thread)); 40 reinterpret_cast<uintptr_t>(thread));
41} 41}
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 420de3c54..4d7e5ecd3 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1337,7 +1337,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1337 {200, nullptr, "GetLastApplicationExitReason"}, 1337 {200, nullptr, "GetLastApplicationExitReason"},
1338 {500, nullptr, "StartContinuousRecordingFlushForDebug"}, 1338 {500, nullptr, "StartContinuousRecordingFlushForDebug"},
1339 {1000, nullptr, "CreateMovieMaker"}, 1339 {1000, nullptr, "CreateMovieMaker"},
1340 {1001, nullptr, "PrepareForJit"}, 1340 {1001, &IApplicationFunctions::PrepareForJit, "PrepareForJit"},
1341 }; 1341 };
1342 // clang-format on 1342 // clang-format on
1343 1343
@@ -1787,6 +1787,13 @@ void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERe
1787 rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent()); 1787 rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent());
1788} 1788}
1789 1789
1790void IApplicationFunctions::PrepareForJit(Kernel::HLERequestContext& ctx) {
1791 LOG_WARNING(Service_AM, "(STUBBED) called");
1792
1793 IPC::ResponseBuilder rb{ctx, 2};
1794 rb.Push(ResultSuccess);
1795}
1796
1790void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, 1797void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
1791 Core::System& system) { 1798 Core::System& system) {
1792 auto message_queue = std::make_shared<AppletMessageQueue>(system); 1799 auto message_queue = std::make_shared<AppletMessageQueue>(system);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index fdd937b82..11a3c0459 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -336,6 +336,7 @@ private:
336 void TryPopFromFriendInvitationStorageChannel(Kernel::HLERequestContext& ctx); 336 void TryPopFromFriendInvitationStorageChannel(Kernel::HLERequestContext& ctx);
337 void GetNotificationStorageChannelEvent(Kernel::HLERequestContext& ctx); 337 void GetNotificationStorageChannelEvent(Kernel::HLERequestContext& ctx);
338 void GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx); 338 void GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx);
339 void PrepareForJit(Kernel::HLERequestContext& ctx);
339 340
340 KernelHelpers::ServiceContext service_context; 341 KernelHelpers::ServiceContext service_context;
341 342
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index affa7971c..a72956a28 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -41,9 +41,10 @@ public:
41 explicit IAudioOut(Core::System& system_, AudoutParams audio_params_, 41 explicit IAudioOut(Core::System& system_, AudoutParams audio_params_,
42 AudioCore::AudioOut& audio_core_, std::string&& device_name_, 42 AudioCore::AudioOut& audio_core_, std::string&& device_name_,
43 std::string&& unique_name) 43 std::string&& unique_name)
44 : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_}, 44 : ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew},
45 device_name{std::move(device_name_)}, audio_params{audio_params_}, 45 audio_core{audio_core_}, device_name{std::move(device_name_)},
46 main_memory{system.Memory()}, service_context{system_, "IAudioOut"} { 46 audio_params{audio_params_}, main_memory{system.Memory()}, service_context{system_,
47 "IAudioOut"} {
47 // clang-format off 48 // clang-format off
48 static const FunctionInfo functions[] = { 49 static const FunctionInfo functions[] = {
49 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, 50 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index f45e5cecc..d4ffeb21d 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -24,7 +24,8 @@ public:
24 explicit IAudioRenderer(Core::System& system_, 24 explicit IAudioRenderer(Core::System& system_,
25 const AudioCommon::AudioRendererParameter& audren_params, 25 const AudioCommon::AudioRendererParameter& audren_params,
26 const std::size_t instance_number) 26 const std::size_t instance_number)
27 : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"} { 27 : ServiceFramework{system_, "IAudioRenderer", ServiceThreadType::CreateNew},
28 service_context{system_, "IAudioRenderer"} {
28 // clang-format off 29 // clang-format off
29 static const FunctionInfo functions[] = { 30 static const FunctionInfo functions[] = {
30 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, 31 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index b087e7bba..c07929ab8 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -58,7 +58,8 @@ enum class FileSystemType : u8 {
58class IStorage final : public ServiceFramework<IStorage> { 58class IStorage final : public ServiceFramework<IStorage> {
59public: 59public:
60 explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_) 60 explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_)
61 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { 61 : ServiceFramework{system_, "IStorage", ServiceThreadType::CreateNew},
62 backend(std::move(backend_)) {
62 static const FunctionInfo functions[] = { 63 static const FunctionInfo functions[] = {
63 {0, &IStorage::Read, "Read"}, 64 {0, &IStorage::Read, "Read"},
64 {1, nullptr, "Write"}, 65 {1, nullptr, "Write"},
@@ -116,7 +117,8 @@ private:
116class IFile final : public ServiceFramework<IFile> { 117class IFile final : public ServiceFramework<IFile> {
117public: 118public:
118 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_) 119 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
119 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { 120 : ServiceFramework{system_, "IFile", ServiceThreadType::CreateNew},
121 backend(std::move(backend_)) {
120 static const FunctionInfo functions[] = { 122 static const FunctionInfo functions[] = {
121 {0, &IFile::Read, "Read"}, 123 {0, &IFile::Read, "Read"},
122 {1, &IFile::Write, "Write"}, 124 {1, &IFile::Write, "Write"},
@@ -252,7 +254,8 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec
252class IDirectory final : public ServiceFramework<IDirectory> { 254class IDirectory final : public ServiceFramework<IDirectory> {
253public: 255public:
254 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_) 256 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_)
255 : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { 257 : ServiceFramework{system_, "IDirectory", ServiceThreadType::CreateNew},
258 backend(std::move(backend_)) {
256 static const FunctionInfo functions[] = { 259 static const FunctionInfo functions[] = {
257 {0, &IDirectory::Read, "Read"}, 260 {0, &IDirectory::Read, "Read"},
258 {1, &IDirectory::GetEntryCount, "GetEntryCount"}, 261 {1, &IDirectory::GetEntryCount, "GetEntryCount"},
@@ -308,8 +311,8 @@ private:
308class IFileSystem final : public ServiceFramework<IFileSystem> { 311class IFileSystem final : public ServiceFramework<IFileSystem> {
309public: 312public:
310 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) 313 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
311 : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( 314 : ServiceFramework{system_, "IFileSystem", ServiceThreadType::CreateNew},
312 size_)} { 315 backend{std::move(backend_)}, size{std::move(size_)} {
313 static const FunctionInfo functions[] = { 316 static const FunctionInfo functions[] = {
314 {0, &IFileSystem::CreateFile, "CreateFile"}, 317 {0, &IFileSystem::CreateFile, "CreateFile"},
315 {1, &IFileSystem::DeleteFile, "DeleteFile"}, 318 {1, &IFileSystem::DeleteFile, "DeleteFile"},
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index aa6cb34b7..4e17a952e 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -318,7 +318,7 @@ void Controller_NPad::OnRelease() {
318} 318}
319 319
320void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { 320void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
321 std::lock_guard lock{mutex}; 321 std::scoped_lock lock{mutex};
322 auto& controller = GetControllerFromNpadIdType(npad_id); 322 auto& controller = GetControllerFromNpadIdType(npad_id);
323 const auto controller_type = controller.device->GetNpadStyleIndex(); 323 const auto controller_type = controller.device->GetNpadStyleIndex();
324 if (!controller.device->IsConnected()) { 324 if (!controller.device->IsConnected()) {
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp
new file mode 100644
index 000000000..c8ebd2e3f
--- /dev/null
+++ b/src/core/hle/service/jit/jit.cpp
@@ -0,0 +1,53 @@
1// Copyright 2022 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/ipc_helpers.h"
6#include "core/hle/result.h"
7#include "core/hle/service/jit/jit.h"
8#include "core/hle/service/service.h"
9
10namespace Service::JIT {
11
12class IJitEnvironment final : public ServiceFramework<IJitEnvironment> {
13public:
14 explicit IJitEnvironment(Core::System& system_) : ServiceFramework{system_, "IJitEnvironment"} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, nullptr, "GenerateCode"},
18 {1, nullptr, "Control"},
19 {1000, nullptr, "LoadPlugin"},
20 {1001, nullptr, "GetCodeAddress"},
21 };
22 // clang-format on
23
24 RegisterHandlers(functions);
25 }
26};
27
28class JITU final : public ServiceFramework<JITU> {
29public:
30 explicit JITU(Core::System& system_) : ServiceFramework{system_, "jit:u"} {
31 // clang-format off
32 static const FunctionInfo functions[] = {
33 {0, &JITU::CreateJitEnvironment, "CreateJitEnvironment"},
34 };
35 // clang-format on
36
37 RegisterHandlers(functions);
38 }
39
40 void CreateJitEnvironment(Kernel::HLERequestContext& ctx) {
41 LOG_DEBUG(Service_JIT, "called");
42
43 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
44 rb.Push(ResultSuccess);
45 rb.PushIpcInterface<IJitEnvironment>(system);
46 }
47};
48
49void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
50 std::make_shared<JITU>(system)->InstallAsService(sm);
51}
52
53} // namespace Service::JIT
diff --git a/src/core/hle/service/jit/jit.h b/src/core/hle/service/jit/jit.h
new file mode 100644
index 000000000..8fbf504a1
--- /dev/null
+++ b/src/core/hle/service/jit/jit.h
@@ -0,0 +1,20 @@
1// Copyright 2022 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7namespace Core {
8class System;
9}
10
11namespace Service::SM {
12class ServiceManager;
13}
14
15namespace Service::JIT {
16
17/// Registers all JIT services with the specified service manager.
18void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
19
20} // namespace Service::JIT
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
index 1ce2a856b..8467b50e4 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
@@ -230,7 +230,7 @@ void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
230} 230}
231 231
232NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name) 232NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name)
233 : ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} { 233 : ServiceFramework{system_, name, ServiceThreadType::CreateNew}, nvdrv{std::move(nvdrv_)} {
234 static const FunctionInfo functions[] = { 234 static const FunctionInfo functions[] = {
235 {0, &NVDRV::Open, "Open"}, 235 {0, &NVDRV::Open, "Open"},
236 {1, &NVDRV::Ioctl1, "Ioctl"}, 236 {1, &NVDRV::Ioctl1, "Ioctl"},
diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp
index 93fa1ec10..d7ee5362b 100644
--- a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp
+++ b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp
@@ -21,7 +21,7 @@ Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseco
21 return Status::BadValue; 21 return Status::BadValue;
22 } 22 }
23 23
24 std::scoped_lock lock(mutex); 24 std::scoped_lock lock{mutex};
25 25
26 if (const auto status = AcquireBufferLocked(item, present_when); status != Status::NoError) { 26 if (const auto status = AcquireBufferLocked(item, present_when); status != Status::NoError) {
27 if (status != Status::NoBufferAvailable) { 27 if (status != Status::NoBufferAvailable) {
@@ -40,7 +40,7 @@ Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseco
40} 40}
41 41
42Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, Fence& release_fence) { 42Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, Fence& release_fence) {
43 std::scoped_lock lock(mutex); 43 std::scoped_lock lock{mutex};
44 44
45 if (const auto status = AddReleaseFenceLocked(item.buf, item.graphic_buffer, release_fence); 45 if (const auto status = AddReleaseFenceLocked(item.buf, item.graphic_buffer, release_fence);
46 status != Status::NoError) { 46 status != Status::NoError) {
diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
index c527c577e..3ab9a8c05 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
@@ -19,7 +19,7 @@ BufferQueueConsumer::~BufferQueueConsumer() = default;
19 19
20Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, 20Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
21 std::chrono::nanoseconds expected_present) { 21 std::chrono::nanoseconds expected_present) {
22 std::scoped_lock lock(core->mutex); 22 std::scoped_lock lock{core->mutex};
23 23
24 // Check that the consumer doesn't currently have the maximum number of buffers acquired. 24 // Check that the consumer doesn't currently have the maximum number of buffers acquired.
25 const s32 num_acquired_buffers{ 25 const s32 num_acquired_buffers{
@@ -120,7 +120,7 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc
120 120
121 std::shared_ptr<IProducerListener> listener; 121 std::shared_ptr<IProducerListener> listener;
122 { 122 {
123 std::scoped_lock lock(core->mutex); 123 std::scoped_lock lock{core->mutex};
124 124
125 // If the frame number has changed because the buffer has been reallocated, we can ignore 125 // If the frame number has changed because the buffer has been reallocated, we can ignore
126 // this ReleaseBuffer for the old buffer. 126 // this ReleaseBuffer for the old buffer.
@@ -180,7 +180,7 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_
180 180
181 LOG_DEBUG(Service_NVFlinger, "controlled_by_app={}", controlled_by_app); 181 LOG_DEBUG(Service_NVFlinger, "controlled_by_app={}", controlled_by_app);
182 182
183 std::scoped_lock lock(core->mutex); 183 std::scoped_lock lock{core->mutex};
184 184
185 if (core->is_abandoned) { 185 if (core->is_abandoned) {
186 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); 186 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
@@ -199,7 +199,7 @@ Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {
199 return Status::BadValue; 199 return Status::BadValue;
200 } 200 }
201 201
202 std::scoped_lock lock(core->mutex); 202 std::scoped_lock lock{core->mutex};
203 203
204 if (core->is_abandoned) { 204 if (core->is_abandoned) {
205 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); 205 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
index 3a0481786..ec5aabaeb 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
@@ -15,7 +15,7 @@ BufferQueueCore::BufferQueueCore() = default;
15BufferQueueCore::~BufferQueueCore() = default; 15BufferQueueCore::~BufferQueueCore() = default;
16 16
17void BufferQueueCore::NotifyShutdown() { 17void BufferQueueCore::NotifyShutdown() {
18 std::scoped_lock lock(mutex); 18 std::scoped_lock lock{mutex};
19 19
20 is_shutting_down = true; 20 is_shutting_down = true;
21 21
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
index 3d6e990c3..6f604a88e 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
@@ -38,7 +38,7 @@ BufferQueueProducer::~BufferQueueProducer() {
38Status BufferQueueProducer::RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf) { 38Status BufferQueueProducer::RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf) {
39 LOG_DEBUG(Service_NVFlinger, "slot {}", slot); 39 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
40 40
41 std::scoped_lock lock(core->mutex); 41 std::scoped_lock lock{core->mutex};
42 42
43 if (core->is_abandoned) { 43 if (core->is_abandoned) {
44 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); 44 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
@@ -65,7 +65,7 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
65 65
66 std::shared_ptr<IConsumerListener> listener; 66 std::shared_ptr<IConsumerListener> listener;
67 { 67 {
68 std::scoped_lock lock(core->mutex); 68 std::scoped_lock lock{core->mutex};
69 core->WaitWhileAllocatingLocked(); 69 core->WaitWhileAllocatingLocked();
70 70
71 if (core->is_abandoned) { 71 if (core->is_abandoned) {
@@ -236,7 +236,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
236 Status return_flags = Status::NoError; 236 Status return_flags = Status::NoError;
237 bool attached_by_consumer = false; 237 bool attached_by_consumer = false;
238 { 238 {
239 std::scoped_lock lock(core->mutex); 239 std::scoped_lock lock{core->mutex};
240 core->WaitWhileAllocatingLocked(); 240 core->WaitWhileAllocatingLocked();
241 241
242 if (format == PixelFormat::NoFormat) { 242 if (format == PixelFormat::NoFormat) {
@@ -295,7 +295,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
295 } 295 }
296 296
297 { 297 {
298 std::scoped_lock lock(core->mutex); 298 std::scoped_lock lock{core->mutex};
299 299
300 if (core->is_abandoned) { 300 if (core->is_abandoned) {
301 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); 301 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
@@ -320,7 +320,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
320Status BufferQueueProducer::DetachBuffer(s32 slot) { 320Status BufferQueueProducer::DetachBuffer(s32 slot) {
321 LOG_DEBUG(Service_NVFlinger, "slot {}", slot); 321 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
322 322
323 std::scoped_lock lock(core->mutex); 323 std::scoped_lock lock{core->mutex};
324 324
325 if (core->is_abandoned) { 325 if (core->is_abandoned) {
326 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); 326 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
@@ -356,7 +356,7 @@ Status BufferQueueProducer::DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out
356 return Status::BadValue; 356 return Status::BadValue;
357 } 357 }
358 358
359 std::scoped_lock lock(core->mutex); 359 std::scoped_lock lock{core->mutex};
360 core->WaitWhileAllocatingLocked(); 360 core->WaitWhileAllocatingLocked();
361 361
362 if (core->is_abandoned) { 362 if (core->is_abandoned) {
@@ -399,7 +399,7 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot,
399 return Status::BadValue; 399 return Status::BadValue;
400 } 400 }
401 401
402 std::scoped_lock lock(core->mutex); 402 std::scoped_lock lock{core->mutex};
403 core->WaitWhileAllocatingLocked(); 403 core->WaitWhileAllocatingLocked();
404 404
405 Status return_flags = Status::NoError; 405 Status return_flags = Status::NoError;
@@ -460,7 +460,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
460 BufferItem item; 460 BufferItem item;
461 461
462 { 462 {
463 std::scoped_lock lock(core->mutex); 463 std::scoped_lock lock{core->mutex};
464 464
465 if (core->is_abandoned) { 465 if (core->is_abandoned) {
466 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); 466 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
@@ -576,7 +576,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
576 // Call back without the main BufferQueue lock held, but with the callback lock held so we can 576 // Call back without the main BufferQueue lock held, but with the callback lock held so we can
577 // ensure that callbacks occur in order 577 // ensure that callbacks occur in order
578 { 578 {
579 std::scoped_lock lock(callback_mutex); 579 std::scoped_lock lock{callback_mutex};
580 while (callback_ticket != current_callback_ticket) { 580 while (callback_ticket != current_callback_ticket) {
581 callback_condition.wait(callback_mutex); 581 callback_condition.wait(callback_mutex);
582 } 582 }
@@ -597,7 +597,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
597void BufferQueueProducer::CancelBuffer(s32 slot, const Fence& fence) { 597void BufferQueueProducer::CancelBuffer(s32 slot, const Fence& fence) {
598 LOG_DEBUG(Service_NVFlinger, "slot {}", slot); 598 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
599 599
600 std::scoped_lock lock(core->mutex); 600 std::scoped_lock lock{core->mutex};
601 601
602 if (core->is_abandoned) { 602 if (core->is_abandoned) {
603 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); 603 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
@@ -623,7 +623,7 @@ void BufferQueueProducer::CancelBuffer(s32 slot, const Fence& fence) {
623} 623}
624 624
625Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) { 625Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) {
626 std::scoped_lock lock(core->mutex); 626 std::scoped_lock lock{core->mutex};
627 627
628 if (out_value == nullptr) { 628 if (out_value == nullptr) {
629 LOG_ERROR(Service_NVFlinger, "outValue was nullptr"); 629 LOG_ERROR(Service_NVFlinger, "outValue was nullptr");
@@ -673,7 +673,7 @@ Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) {
673Status BufferQueueProducer::Connect(const std::shared_ptr<IProducerListener>& listener, 673Status BufferQueueProducer::Connect(const std::shared_ptr<IProducerListener>& listener,
674 NativeWindowApi api, bool producer_controlled_by_app, 674 NativeWindowApi api, bool producer_controlled_by_app,
675 QueueBufferOutput* output) { 675 QueueBufferOutput* output) {
676 std::scoped_lock lock(core->mutex); 676 std::scoped_lock lock{core->mutex};
677 677
678 LOG_DEBUG(Service_NVFlinger, "api = {} producer_controlled_by_app = {}", api, 678 LOG_DEBUG(Service_NVFlinger, "api = {} producer_controlled_by_app = {}", api,
679 producer_controlled_by_app); 679 producer_controlled_by_app);
@@ -730,7 +730,7 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
730 std::shared_ptr<IConsumerListener> listener; 730 std::shared_ptr<IConsumerListener> listener;
731 731
732 { 732 {
733 std::scoped_lock lock(core->mutex); 733 std::scoped_lock lock{core->mutex};
734 734
735 core->WaitWhileAllocatingLocked(); 735 core->WaitWhileAllocatingLocked();
736 736
@@ -780,7 +780,7 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
780 return Status::BadValue; 780 return Status::BadValue;
781 } 781 }
782 782
783 std::scoped_lock lock(core->mutex); 783 std::scoped_lock lock{core->mutex};
784 784
785 slots[slot] = {}; 785 slots[slot] = {};
786 slots[slot].graphic_buffer = buffer; 786 slots[slot].graphic_buffer = buffer;
diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp
index c2c80832c..30fc21acc 100644
--- a/src/core/hle/service/nvflinger/consumer_base.cpp
+++ b/src/core/hle/service/nvflinger/consumer_base.cpp
@@ -18,7 +18,7 @@ ConsumerBase::ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_)
18 : consumer{std::move(consumer_)} {} 18 : consumer{std::move(consumer_)} {}
19 19
20ConsumerBase::~ConsumerBase() { 20ConsumerBase::~ConsumerBase() {
21 std::scoped_lock lock(mutex); 21 std::scoped_lock lock{mutex};
22 22
23 ASSERT_MSG(is_abandoned, "consumer is not abandoned!"); 23 ASSERT_MSG(is_abandoned, "consumer is not abandoned!");
24} 24}
@@ -44,7 +44,7 @@ void ConsumerBase::OnFrameReplaced(const BufferItem& item) {
44} 44}
45 45
46void ConsumerBase::OnBuffersReleased() { 46void ConsumerBase::OnBuffersReleased() {
47 std::scoped_lock lock(mutex); 47 std::scoped_lock lock{mutex};
48 48
49 LOG_DEBUG(Service_NVFlinger, "called"); 49 LOG_DEBUG(Service_NVFlinger, "called");
50 50
diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
index d4da98ddb..04068827e 100644
--- a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
+++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
@@ -4,8 +4,6 @@
4// Parts of this implementation were base on: 4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/IGraphicBufferProducer.cpp 5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/IGraphicBufferProducer.cpp
6 6
7#pragma once
8
9#include "core/hle/service/nvflinger/graphic_buffer_producer.h" 7#include "core/hle/service/nvflinger/graphic_buffer_producer.h"
10#include "core/hle/service/nvflinger/parcel.h" 8#include "core/hle/service/nvflinger/parcel.h"
11 9
diff --git a/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp b/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp
index 0c937d682..094ba2542 100644
--- a/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp
+++ b/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp
@@ -14,7 +14,7 @@ HosBinderDriverServer::HosBinderDriverServer(Core::System& system_)
14HosBinderDriverServer::~HosBinderDriverServer() {} 14HosBinderDriverServer::~HosBinderDriverServer() {}
15 15
16u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr<android::IBinder>&& binder) { 16u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr<android::IBinder>&& binder) {
17 std::lock_guard lk{lock}; 17 std::scoped_lock lk{lock};
18 18
19 last_id++; 19 last_id++;
20 20
@@ -24,7 +24,7 @@ u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr<android::IBinder>&&
24} 24}
25 25
26android::IBinder* HosBinderDriverServer::TryGetProducer(u64 id) { 26android::IBinder* HosBinderDriverServer::TryGetProducer(u64 id) {
27 std::lock_guard lk{lock}; 27 std::scoped_lock lk{lock};
28 28
29 if (auto search = producers.find(id); search != producers.end()) { 29 if (auto search = producers.find(id); search != producers.end()) {
30 return search->second.get(); 30 return search->second.get();
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index ab3286db9..0f59a03c5 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -32,6 +32,7 @@
32#include "core/hle/service/glue/glue.h" 32#include "core/hle/service/glue/glue.h"
33#include "core/hle/service/grc/grc.h" 33#include "core/hle/service/grc/grc.h"
34#include "core/hle/service/hid/hid.h" 34#include "core/hle/service/hid/hid.h"
35#include "core/hle/service/jit/jit.h"
35#include "core/hle/service/lbl/lbl.h" 36#include "core/hle/service/lbl/lbl.h"
36#include "core/hle/service/ldn/ldn.h" 37#include "core/hle/service/ldn/ldn.h"
37#include "core/hle/service/ldr/ldr.h" 38#include "core/hle/service/ldr/ldr.h"
@@ -91,8 +92,9 @@ namespace Service {
91} 92}
92 93
93ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_, 94ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_,
94 u32 max_sessions_, InvokerFn* handler_invoker_) 95 ServiceThreadType thread_type, u32 max_sessions_,
95 : SessionRequestHandler(system_.Kernel(), service_name_), system{system_}, 96 InvokerFn* handler_invoker_)
97 : SessionRequestHandler(system_.Kernel(), service_name_, thread_type), system{system_},
96 service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {} 98 service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {}
97 99
98ServiceFrameworkBase::~ServiceFrameworkBase() { 100ServiceFrameworkBase::~ServiceFrameworkBase() {
@@ -261,6 +263,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
261 Glue::InstallInterfaces(system); 263 Glue::InstallInterfaces(system);
262 GRC::InstallInterfaces(*sm, system); 264 GRC::InstallInterfaces(*sm, system);
263 HID::InstallInterfaces(*sm, system); 265 HID::InstallInterfaces(*sm, system);
266 JIT::InstallInterfaces(*sm, system);
264 LBL::InstallInterfaces(*sm, system); 267 LBL::InstallInterfaces(*sm, system);
265 LDN::InstallInterfaces(*sm, system); 268 LDN::InstallInterfaces(*sm, system);
266 LDR::InstallInterfaces(*sm, system); 269 LDR::InstallInterfaces(*sm, system);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index b9ab2c465..c78b2baeb 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -114,7 +114,8 @@ private:
114 Kernel::HLERequestContext& ctx); 114 Kernel::HLERequestContext& ctx);
115 115
116 explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_, 116 explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_,
117 u32 max_sessions_, InvokerFn* handler_invoker_); 117 ServiceThreadType thread_type, u32 max_sessions_,
118 InvokerFn* handler_invoker_);
118 ~ServiceFrameworkBase() override; 119 ~ServiceFrameworkBase() override;
119 120
120 void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); 121 void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
@@ -176,14 +177,17 @@ protected:
176 /** 177 /**
177 * Initializes the handler with no functions installed. 178 * Initializes the handler with no functions installed.
178 * 179 *
179 * @param system_ The system context to construct this service under. 180 * @param system_ The system context to construct this service under.
180 * @param service_name_ Name of the service. 181 * @param service_name_ Name of the service.
181 * @param max_sessions_ Maximum number of sessions that can be 182 * @param thread_type Specifies the thread type for this service. If this is set to CreateNew,
182 * connected to this service at the same time. 183 * it creates a new thread for it, otherwise this uses the default thread.
184 * @param max_sessions_ Maximum number of sessions that can be connected to this service at the
185 * same time.
183 */ 186 */
184 explicit ServiceFramework(Core::System& system_, const char* service_name_, 187 explicit ServiceFramework(Core::System& system_, const char* service_name_,
188 ServiceThreadType thread_type = ServiceThreadType::Default,
185 u32 max_sessions_ = ServerSessionCountMax) 189 u32 max_sessions_ = ServerSessionCountMax)
186 : ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {} 190 : ServiceFrameworkBase(system_, service_name_, thread_type, max_sessions_, Invoker) {}
187 191
188 /// Registers handlers in the service. 192 /// Registers handlers in the service.
189 template <std::size_t N> 193 template <std::size_t N>
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 695a1faa6..97f895852 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -206,7 +206,7 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
206} 206}
207 207
208SM::SM(ServiceManager& service_manager_, Core::System& system_) 208SM::SM(ServiceManager& service_manager_, Core::System& system_)
209 : ServiceFramework{system_, "sm:", 4}, 209 : ServiceFramework{system_, "sm:", ServiceThreadType::Default, 4},
210 service_manager{service_manager_}, kernel{system_.Kernel()} { 210 service_manager{service_manager_}, kernel{system_.Kernel()} {
211 RegisterHandlers({ 211 RegisterHandlers({
212 {0, &SM::Initialize, "Initialize"}, 212 {0, &SM::Initialize, "Initialize"},
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index e5631c27e..d25b050e2 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -840,7 +840,8 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co
840 rb.PushEnum(bsd_errno); 840 rb.PushEnum(bsd_errno);
841} 841}
842 842
843BSD::BSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} { 843BSD::BSD(Core::System& system_, const char* name)
844 : ServiceFramework{system_, name, ServiceThreadType::CreateNew} {
844 // clang-format off 845 // clang-format off
845 static const FunctionInfo functions[] = { 846 static const FunctionInfo functions[] = {
846 {0, &BSD::RegisterClient, "RegisterClient"}, 847 {0, &BSD::RegisterClient, "RegisterClient"},
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 430cbc546..a3436c8ea 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -77,7 +77,8 @@ static_assert(sizeof(NativeWindow) == 0x28, "NativeWindow has wrong size");
77class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { 77class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
78public: 78public:
79 explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_) 79 explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_)
80 : ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) { 80 : ServiceFramework{system_, "IHOSBinderDriver", ServiceThreadType::CreateNew},
81 server(server_) {
81 static const FunctionInfo functions[] = { 82 static const FunctionInfo functions[] = {
82 {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, 83 {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
83 {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, 84 {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index 52c43c857..6ef459b7a 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -53,13 +53,13 @@ PerfStats::~PerfStats() {
53} 53}
54 54
55void PerfStats::BeginSystemFrame() { 55void PerfStats::BeginSystemFrame() {
56 std::lock_guard lock{object_mutex}; 56 std::scoped_lock lock{object_mutex};
57 57
58 frame_begin = Clock::now(); 58 frame_begin = Clock::now();
59} 59}
60 60
61void PerfStats::EndSystemFrame() { 61void PerfStats::EndSystemFrame() {
62 std::lock_guard lock{object_mutex}; 62 std::scoped_lock lock{object_mutex};
63 63
64 auto frame_end = Clock::now(); 64 auto frame_end = Clock::now();
65 const auto frame_time = frame_end - frame_begin; 65 const auto frame_time = frame_end - frame_begin;
@@ -79,7 +79,7 @@ void PerfStats::EndGameFrame() {
79} 79}
80 80
81double PerfStats::GetMeanFrametime() const { 81double PerfStats::GetMeanFrametime() const {
82 std::lock_guard lock{object_mutex}; 82 std::scoped_lock lock{object_mutex};
83 83
84 if (current_index <= IgnoreFrames) { 84 if (current_index <= IgnoreFrames) {
85 return 0; 85 return 0;
@@ -91,7 +91,7 @@ double PerfStats::GetMeanFrametime() const {
91} 91}
92 92
93PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us) { 93PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us) {
94 std::lock_guard lock{object_mutex}; 94 std::scoped_lock lock{object_mutex};
95 95
96 const auto now = Clock::now(); 96 const auto now = Clock::now();
97 // Walltime elapsed since stats were reset 97 // Walltime elapsed since stats were reset
@@ -120,7 +120,7 @@ PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us
120} 120}
121 121
122double PerfStats::GetLastFrameTimeScale() const { 122double PerfStats::GetLastFrameTimeScale() const {
123 std::lock_guard lock{object_mutex}; 123 std::scoped_lock lock{object_mutex};
124 124
125 constexpr double FRAME_LENGTH = 1.0 / 60; 125 constexpr double FRAME_LENGTH = 1.0 / 60;
126 return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH; 126 return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH;
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 032c71aff..c81dc0e52 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -80,7 +80,7 @@ bool Freezer::IsActive() const {
80} 80}
81 81
82void Freezer::Clear() { 82void Freezer::Clear() {
83 std::lock_guard lock{entries_mutex}; 83 std::scoped_lock lock{entries_mutex};
84 84
85 LOG_DEBUG(Common_Memory, "Clearing all frozen memory values."); 85 LOG_DEBUG(Common_Memory, "Clearing all frozen memory values.");
86 86
@@ -88,7 +88,7 @@ void Freezer::Clear() {
88} 88}
89 89
90u64 Freezer::Freeze(VAddr address, u32 width) { 90u64 Freezer::Freeze(VAddr address, u32 width) {
91 std::lock_guard lock{entries_mutex}; 91 std::scoped_lock lock{entries_mutex};
92 92
93 const auto current_value = MemoryReadWidth(memory, width, address); 93 const auto current_value = MemoryReadWidth(memory, width, address);
94 entries.push_back({address, width, current_value}); 94 entries.push_back({address, width, current_value});
@@ -101,7 +101,7 @@ u64 Freezer::Freeze(VAddr address, u32 width) {
101} 101}
102 102
103void Freezer::Unfreeze(VAddr address) { 103void Freezer::Unfreeze(VAddr address) {
104 std::lock_guard lock{entries_mutex}; 104 std::scoped_lock lock{entries_mutex};
105 105
106 LOG_DEBUG(Common_Memory, "Unfreezing memory for address={:016X}", address); 106 LOG_DEBUG(Common_Memory, "Unfreezing memory for address={:016X}", address);
107 107
@@ -109,13 +109,13 @@ void Freezer::Unfreeze(VAddr address) {
109} 109}
110 110
111bool Freezer::IsFrozen(VAddr address) const { 111bool Freezer::IsFrozen(VAddr address) const {
112 std::lock_guard lock{entries_mutex}; 112 std::scoped_lock lock{entries_mutex};
113 113
114 return FindEntry(address) != entries.cend(); 114 return FindEntry(address) != entries.cend();
115} 115}
116 116
117void Freezer::SetFrozenValue(VAddr address, u64 value) { 117void Freezer::SetFrozenValue(VAddr address, u64 value) {
118 std::lock_guard lock{entries_mutex}; 118 std::scoped_lock lock{entries_mutex};
119 119
120 const auto iter = FindEntry(address); 120 const auto iter = FindEntry(address);
121 121
@@ -132,7 +132,7 @@ void Freezer::SetFrozenValue(VAddr address, u64 value) {
132} 132}
133 133
134std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) const { 134std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) const {
135 std::lock_guard lock{entries_mutex}; 135 std::scoped_lock lock{entries_mutex};
136 136
137 const auto iter = FindEntry(address); 137 const auto iter = FindEntry(address);
138 138
@@ -144,7 +144,7 @@ std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) const {
144} 144}
145 145
146std::vector<Freezer::Entry> Freezer::GetEntries() const { 146std::vector<Freezer::Entry> Freezer::GetEntries() const {
147 std::lock_guard lock{entries_mutex}; 147 std::scoped_lock lock{entries_mutex};
148 148
149 return entries; 149 return entries;
150} 150}
@@ -165,7 +165,7 @@ void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) {
165 return; 165 return;
166 } 166 }
167 167
168 std::lock_guard lock{entries_mutex}; 168 std::scoped_lock lock{entries_mutex};
169 169
170 for (const auto& entry : entries) { 170 for (const auto& entry : entries) {
171 LOG_DEBUG(Common_Memory, 171 LOG_DEBUG(Common_Memory,
@@ -178,7 +178,7 @@ void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) {
178} 178}
179 179
180void Freezer::FillEntryReads() { 180void Freezer::FillEntryReads() {
181 std::lock_guard lock{entries_mutex}; 181 std::scoped_lock lock{entries_mutex};
182 182
183 LOG_DEBUG(Common_Memory, "Updating memory freeze entries to current values."); 183 LOG_DEBUG(Common_Memory, "Updating memory freeze entries to current values.");
184 184
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index c17ea305e..b3e4c3f64 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -62,7 +62,7 @@ public:
62 62
63 bool UpdateMotion(SDL_ControllerSensorEvent event) { 63 bool UpdateMotion(SDL_ControllerSensorEvent event) {
64 constexpr float gravity_constant = 9.80665f; 64 constexpr float gravity_constant = 9.80665f;
65 std::lock_guard lock{mutex}; 65 std::scoped_lock lock{mutex};
66 const u64 time_difference = event.timestamp - last_motion_update; 66 const u64 time_difference = event.timestamp - last_motion_update;
67 last_motion_update = event.timestamp; 67 last_motion_update = event.timestamp;
68 switch (event.sensor) { 68 switch (event.sensor) {
@@ -241,7 +241,7 @@ private:
241}; 241};
242 242
243std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) { 243std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) {
244 std::lock_guard lock{joystick_map_mutex}; 244 std::scoped_lock lock{joystick_map_mutex};
245 const auto it = joystick_map.find(guid); 245 const auto it = joystick_map.find(guid);
246 246
247 if (it != joystick_map.end()) { 247 if (it != joystick_map.end()) {
@@ -263,7 +263,7 @@ std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl
263 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); 263 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
264 const std::string guid = GetGUID(sdl_joystick); 264 const std::string guid = GetGUID(sdl_joystick);
265 265
266 std::lock_guard lock{joystick_map_mutex}; 266 std::scoped_lock lock{joystick_map_mutex};
267 const auto map_it = joystick_map.find(guid); 267 const auto map_it = joystick_map.find(guid);
268 268
269 if (map_it == joystick_map.end()) { 269 if (map_it == joystick_map.end()) {
@@ -297,7 +297,7 @@ void SDLDriver::InitJoystick(int joystick_index) {
297 297
298 const std::string guid = GetGUID(sdl_joystick); 298 const std::string guid = GetGUID(sdl_joystick);
299 299
300 std::lock_guard lock{joystick_map_mutex}; 300 std::scoped_lock lock{joystick_map_mutex};
301 if (joystick_map.find(guid) == joystick_map.end()) { 301 if (joystick_map.find(guid) == joystick_map.end()) {
302 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); 302 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
303 PreSetController(joystick->GetPadIdentifier()); 303 PreSetController(joystick->GetPadIdentifier());
@@ -326,7 +326,7 @@ void SDLDriver::InitJoystick(int joystick_index) {
326void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) { 326void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) {
327 const std::string guid = GetGUID(sdl_joystick); 327 const std::string guid = GetGUID(sdl_joystick);
328 328
329 std::lock_guard lock{joystick_map_mutex}; 329 std::scoped_lock lock{joystick_map_mutex};
330 // This call to guid is safe since the joystick is guaranteed to be in the map 330 // This call to guid is safe since the joystick is guaranteed to be in the map
331 const auto& joystick_guid_list = joystick_map[guid]; 331 const auto& joystick_guid_list = joystick_map[guid];
332 const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), 332 const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
@@ -392,7 +392,7 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
392} 392}
393 393
394void SDLDriver::CloseJoysticks() { 394void SDLDriver::CloseJoysticks() {
395 std::lock_guard lock{joystick_map_mutex}; 395 std::scoped_lock lock{joystick_map_mutex};
396 joystick_map.clear(); 396 joystick_map.clear();
397} 397}
398 398
diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp
index 738022ece..a16cca33d 100644
--- a/src/input_common/input_engine.cpp
+++ b/src/input_common/input_engine.cpp
@@ -8,37 +8,37 @@
8namespace InputCommon { 8namespace InputCommon {
9 9
10void InputEngine::PreSetController(const PadIdentifier& identifier) { 10void InputEngine::PreSetController(const PadIdentifier& identifier) {
11 std::lock_guard lock{mutex}; 11 std::scoped_lock lock{mutex};
12 controller_list.try_emplace(identifier); 12 controller_list.try_emplace(identifier);
13} 13}
14 14
15void InputEngine::PreSetButton(const PadIdentifier& identifier, int button) { 15void InputEngine::PreSetButton(const PadIdentifier& identifier, int button) {
16 std::lock_guard lock{mutex}; 16 std::scoped_lock lock{mutex};
17 ControllerData& controller = controller_list.at(identifier); 17 ControllerData& controller = controller_list.at(identifier);
18 controller.buttons.try_emplace(button, false); 18 controller.buttons.try_emplace(button, false);
19} 19}
20 20
21void InputEngine::PreSetHatButton(const PadIdentifier& identifier, int button) { 21void InputEngine::PreSetHatButton(const PadIdentifier& identifier, int button) {
22 std::lock_guard lock{mutex}; 22 std::scoped_lock lock{mutex};
23 ControllerData& controller = controller_list.at(identifier); 23 ControllerData& controller = controller_list.at(identifier);
24 controller.hat_buttons.try_emplace(button, u8{0}); 24 controller.hat_buttons.try_emplace(button, u8{0});
25} 25}
26 26
27void InputEngine::PreSetAxis(const PadIdentifier& identifier, int axis) { 27void InputEngine::PreSetAxis(const PadIdentifier& identifier, int axis) {
28 std::lock_guard lock{mutex}; 28 std::scoped_lock lock{mutex};
29 ControllerData& controller = controller_list.at(identifier); 29 ControllerData& controller = controller_list.at(identifier);
30 controller.axes.try_emplace(axis, 0.0f); 30 controller.axes.try_emplace(axis, 0.0f);
31} 31}
32 32
33void InputEngine::PreSetMotion(const PadIdentifier& identifier, int motion) { 33void InputEngine::PreSetMotion(const PadIdentifier& identifier, int motion) {
34 std::lock_guard lock{mutex}; 34 std::scoped_lock lock{mutex};
35 ControllerData& controller = controller_list.at(identifier); 35 ControllerData& controller = controller_list.at(identifier);
36 controller.motions.try_emplace(motion); 36 controller.motions.try_emplace(motion);
37} 37}
38 38
39void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool value) { 39void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool value) {
40 { 40 {
41 std::lock_guard lock{mutex}; 41 std::scoped_lock lock{mutex};
42 ControllerData& controller = controller_list.at(identifier); 42 ControllerData& controller = controller_list.at(identifier);
43 if (!configuring) { 43 if (!configuring) {
44 controller.buttons.insert_or_assign(button, value); 44 controller.buttons.insert_or_assign(button, value);
@@ -49,7 +49,7 @@ void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool va
49 49
50void InputEngine::SetHatButton(const PadIdentifier& identifier, int button, u8 value) { 50void InputEngine::SetHatButton(const PadIdentifier& identifier, int button, u8 value) {
51 { 51 {
52 std::lock_guard lock{mutex}; 52 std::scoped_lock lock{mutex};
53 ControllerData& controller = controller_list.at(identifier); 53 ControllerData& controller = controller_list.at(identifier);
54 if (!configuring) { 54 if (!configuring) {
55 controller.hat_buttons.insert_or_assign(button, value); 55 controller.hat_buttons.insert_or_assign(button, value);
@@ -60,7 +60,7 @@ void InputEngine::SetHatButton(const PadIdentifier& identifier, int button, u8 v
60 60
61void InputEngine::SetAxis(const PadIdentifier& identifier, int axis, f32 value) { 61void InputEngine::SetAxis(const PadIdentifier& identifier, int axis, f32 value) {
62 { 62 {
63 std::lock_guard lock{mutex}; 63 std::scoped_lock lock{mutex};
64 ControllerData& controller = controller_list.at(identifier); 64 ControllerData& controller = controller_list.at(identifier);
65 if (!configuring) { 65 if (!configuring) {
66 controller.axes.insert_or_assign(axis, value); 66 controller.axes.insert_or_assign(axis, value);
@@ -71,7 +71,7 @@ void InputEngine::SetAxis(const PadIdentifier& identifier, int axis, f32 value)
71 71
72void InputEngine::SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value) { 72void InputEngine::SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value) {
73 { 73 {
74 std::lock_guard lock{mutex}; 74 std::scoped_lock lock{mutex};
75 ControllerData& controller = controller_list.at(identifier); 75 ControllerData& controller = controller_list.at(identifier);
76 if (!configuring) { 76 if (!configuring) {
77 controller.battery = value; 77 controller.battery = value;
@@ -82,7 +82,7 @@ void InputEngine::SetBattery(const PadIdentifier& identifier, Common::Input::Bat
82 82
83void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value) { 83void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value) {
84 { 84 {
85 std::lock_guard lock{mutex}; 85 std::scoped_lock lock{mutex};
86 ControllerData& controller = controller_list.at(identifier); 86 ControllerData& controller = controller_list.at(identifier);
87 if (!configuring) { 87 if (!configuring) {
88 controller.motions.insert_or_assign(motion, value); 88 controller.motions.insert_or_assign(motion, value);
@@ -92,7 +92,7 @@ void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const B
92} 92}
93 93
94bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const { 94bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const {
95 std::lock_guard lock{mutex}; 95 std::scoped_lock lock{mutex};
96 const auto controller_iter = controller_list.find(identifier); 96 const auto controller_iter = controller_list.find(identifier);
97 if (controller_iter == controller_list.cend()) { 97 if (controller_iter == controller_list.cend()) {
98 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(), 98 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(),
@@ -109,7 +109,7 @@ bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const {
109} 109}
110 110
111bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const { 111bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const {
112 std::lock_guard lock{mutex}; 112 std::scoped_lock lock{mutex};
113 const auto controller_iter = controller_list.find(identifier); 113 const auto controller_iter = controller_list.find(identifier);
114 if (controller_iter == controller_list.cend()) { 114 if (controller_iter == controller_list.cend()) {
115 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(), 115 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(),
@@ -126,7 +126,7 @@ bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 d
126} 126}
127 127
128f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const { 128f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const {
129 std::lock_guard lock{mutex}; 129 std::scoped_lock lock{mutex};
130 const auto controller_iter = controller_list.find(identifier); 130 const auto controller_iter = controller_list.find(identifier);
131 if (controller_iter == controller_list.cend()) { 131 if (controller_iter == controller_list.cend()) {
132 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(), 132 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(),
@@ -143,7 +143,7 @@ f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const {
143} 143}
144 144
145Common::Input::BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const { 145Common::Input::BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const {
146 std::lock_guard lock{mutex}; 146 std::scoped_lock lock{mutex};
147 const auto controller_iter = controller_list.find(identifier); 147 const auto controller_iter = controller_list.find(identifier);
148 if (controller_iter == controller_list.cend()) { 148 if (controller_iter == controller_list.cend()) {
149 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(), 149 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(),
@@ -155,7 +155,7 @@ Common::Input::BatteryLevel InputEngine::GetBattery(const PadIdentifier& identif
155} 155}
156 156
157BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const { 157BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const {
158 std::lock_guard lock{mutex}; 158 std::scoped_lock lock{mutex};
159 const auto controller_iter = controller_list.find(identifier); 159 const auto controller_iter = controller_list.find(identifier);
160 if (controller_iter == controller_list.cend()) { 160 if (controller_iter == controller_list.cend()) {
161 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(), 161 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(),
@@ -186,7 +186,7 @@ void InputEngine::ResetAnalogState() {
186} 186}
187 187
188void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value) { 188void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value) {
189 std::lock_guard lock{mutex_callback}; 189 std::scoped_lock lock{mutex_callback};
190 for (const auto& poller_pair : callback_list) { 190 for (const auto& poller_pair : callback_list) {
191 const InputIdentifier& poller = poller_pair.second; 191 const InputIdentifier& poller = poller_pair.second;
192 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Button, button)) { 192 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Button, button)) {
@@ -214,7 +214,7 @@ void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int but
214} 214}
215 215
216void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value) { 216void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value) {
217 std::lock_guard lock{mutex_callback}; 217 std::scoped_lock lock{mutex_callback};
218 for (const auto& poller_pair : callback_list) { 218 for (const auto& poller_pair : callback_list) {
219 const InputIdentifier& poller = poller_pair.second; 219 const InputIdentifier& poller = poller_pair.second;
220 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::HatButton, button)) { 220 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::HatButton, button)) {
@@ -243,7 +243,7 @@ void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int
243} 243}
244 244
245void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value) { 245void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value) {
246 std::lock_guard lock{mutex_callback}; 246 std::scoped_lock lock{mutex_callback};
247 for (const auto& poller_pair : callback_list) { 247 for (const auto& poller_pair : callback_list) {
248 const InputIdentifier& poller = poller_pair.second; 248 const InputIdentifier& poller = poller_pair.second;
249 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Analog, axis)) { 249 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Analog, axis)) {
@@ -270,7 +270,7 @@ void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis,
270 270
271void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier, 271void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,
272 [[maybe_unused]] Common::Input::BatteryLevel value) { 272 [[maybe_unused]] Common::Input::BatteryLevel value) {
273 std::lock_guard lock{mutex_callback}; 273 std::scoped_lock lock{mutex_callback};
274 for (const auto& poller_pair : callback_list) { 274 for (const auto& poller_pair : callback_list) {
275 const InputIdentifier& poller = poller_pair.second; 275 const InputIdentifier& poller = poller_pair.second;
276 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Battery, 0)) { 276 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Battery, 0)) {
@@ -284,7 +284,7 @@ void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,
284 284
285void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion, 285void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion,
286 const BasicMotion& value) { 286 const BasicMotion& value) {
287 std::lock_guard lock{mutex_callback}; 287 std::scoped_lock lock{mutex_callback};
288 for (const auto& poller_pair : callback_list) { 288 for (const auto& poller_pair : callback_list) {
289 const InputIdentifier& poller = poller_pair.second; 289 const InputIdentifier& poller = poller_pair.second;
290 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Motion, motion)) { 290 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Motion, motion)) {
@@ -346,18 +346,18 @@ const std::string& InputEngine::GetEngineName() const {
346} 346}
347 347
348int InputEngine::SetCallback(InputIdentifier input_identifier) { 348int InputEngine::SetCallback(InputIdentifier input_identifier) {
349 std::lock_guard lock{mutex_callback}; 349 std::scoped_lock lock{mutex_callback};
350 callback_list.insert_or_assign(last_callback_key, std::move(input_identifier)); 350 callback_list.insert_or_assign(last_callback_key, std::move(input_identifier));
351 return last_callback_key++; 351 return last_callback_key++;
352} 352}
353 353
354void InputEngine::SetMappingCallback(MappingCallback callback) { 354void InputEngine::SetMappingCallback(MappingCallback callback) {
355 std::lock_guard lock{mutex_callback}; 355 std::scoped_lock lock{mutex_callback};
356 mapping_callback = std::move(callback); 356 mapping_callback = std::move(callback);
357} 357}
358 358
359void InputEngine::DeleteCallback(int key) { 359void InputEngine::DeleteCallback(int key) {
360 std::lock_guard lock{mutex_callback}; 360 std::scoped_lock lock{mutex_callback};
361 const auto& iterator = callback_list.find(key); 361 const auto& iterator = callback_list.find(key);
362 if (iterator == callback_list.end()) { 362 if (iterator == callback_list.end()) {
363 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); 363 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
index 0c1fbc7b1..282668b36 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
@@ -35,6 +35,15 @@ std::string_view OutputVertexIndex(EmitContext& ctx) {
35 return ctx.stage == Stage::TessellationControl ? "[gl_InvocationID]" : ""; 35 return ctx.stage == Stage::TessellationControl ? "[gl_InvocationID]" : "";
36} 36}
37 37
38std::string ChooseCbuf(EmitContext& ctx, const IR::Value& binding, std::string_view index) {
39 if (binding.IsImmediate()) {
40 return fmt::format("{}_cbuf{}[{}]", ctx.stage_name, binding.U32(), index);
41 } else {
42 const auto binding_var{ctx.var_alloc.Consume(binding)};
43 return fmt::format("GetCbufIndirect({},{})", binding_var, index);
44 }
45}
46
38void GetCbuf(EmitContext& ctx, std::string_view ret, const IR::Value& binding, 47void GetCbuf(EmitContext& ctx, std::string_view ret, const IR::Value& binding,
39 const IR::Value& offset, u32 num_bits, std::string_view cast = {}, 48 const IR::Value& offset, u32 num_bits, std::string_view cast = {},
40 std::string_view bit_offset = {}) { 49 std::string_view bit_offset = {}) {
@@ -55,8 +64,8 @@ void GetCbuf(EmitContext& ctx, std::string_view ret, const IR::Value& binding,
55 const auto swizzle{is_immediate ? fmt::format(".{}", OffsetSwizzle(offset.U32())) 64 const auto swizzle{is_immediate ? fmt::format(".{}", OffsetSwizzle(offset.U32()))
56 : fmt::format("[({}>>2)%4]", offset_var)}; 65 : fmt::format("[({}>>2)%4]", offset_var)};
57 66
58 const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())}; 67 const auto cbuf{ChooseCbuf(ctx, binding, index)};
59 const auto cbuf_cast{fmt::format("{}({}[{}]{{}})", cast, cbuf, index)}; 68 const auto cbuf_cast{fmt::format("{}({}{{}})", cast, cbuf)};
60 const auto extraction{num_bits == 32 ? cbuf_cast 69 const auto extraction{num_bits == 32 ? cbuf_cast
61 : fmt::format("bitfieldExtract({},int({}),{})", cbuf_cast, 70 : fmt::format("bitfieldExtract({},int({}),{})", cbuf_cast,
62 bit_offset, num_bits)}; 71 bit_offset, num_bits)};
@@ -140,9 +149,9 @@ void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
140 149
141void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, 150void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
142 const IR::Value& offset) { 151 const IR::Value& offset) {
143 const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())};
144 const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"}; 152 const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
145 if (offset.IsImmediate()) { 153 if (offset.IsImmediate()) {
154 const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())};
146 static constexpr u32 cbuf_size{0x10000}; 155 static constexpr u32 cbuf_size{0x10000};
147 const u32 u32_offset{offset.U32()}; 156 const u32 u32_offset{offset.U32()};
148 const s32 signed_offset{static_cast<s32>(offset.U32())}; 157 const s32 signed_offset{static_cast<s32>(offset.U32())};
@@ -162,17 +171,17 @@ void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding
162 return; 171 return;
163 } 172 }
164 const auto offset_var{ctx.var_alloc.Consume(offset)}; 173 const auto offset_var{ctx.var_alloc.Consume(offset)};
174 const auto cbuf{ChooseCbuf(ctx, binding, fmt::format("{}>>4", offset_var))};
165 if (!ctx.profile.has_gl_component_indexing_bug) { 175 if (!ctx.profile.has_gl_component_indexing_bug) {
166 ctx.AddU32x2("{}=uvec2({}({}[{}>>4][({}>>2)%4]),{}({}[({}+4)>>4][(({}+4)>>2)%4]));", inst, 176 ctx.AddU32x2("{}=uvec2({}({}[({}>>2)%4]),{}({}[(({}+4)>>2)%4]));", inst, cast, cbuf,
167 cast, cbuf, offset_var, offset_var, cast, cbuf, offset_var, offset_var); 177 offset_var, cast, cbuf, offset_var);
168 return; 178 return;
169 } 179 }
170 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x2)}; 180 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x2)};
171 const auto cbuf_offset{fmt::format("{}>>2", offset_var)}; 181 const auto cbuf_offset{fmt::format("{}>>2", offset_var)};
172 for (u32 swizzle = 0; swizzle < 4; ++swizzle) { 182 for (u32 swizzle = 0; swizzle < 4; ++swizzle) {
173 ctx.Add("if(({}&3)=={}){}=uvec2({}({}[{}>>4].{}),{}({}[({}+4)>>4].{}));", cbuf_offset, 183 ctx.Add("if(({}&3)=={}){}=uvec2({}({}.{}),{}({}.{}));", cbuf_offset, swizzle, ret, cast,
174 swizzle, ret, cast, cbuf, offset_var, "xyzw"[swizzle], cast, cbuf, offset_var, 184 cbuf, "xyzw"[swizzle], cast, cbuf, "xyzw"[(swizzle + 1) % 4]);
175 "xyzw"[(swizzle + 1) % 4]);
176 } 185 }
177} 186}
178 187
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
index e816a93ec..17266f40d 100644
--- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
+++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
@@ -359,6 +359,7 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
359 header += "layout(location=0) uniform vec4 scaling;"; 359 header += "layout(location=0) uniform vec4 scaling;";
360 } 360 }
361 DefineConstantBuffers(bindings); 361 DefineConstantBuffers(bindings);
362 DefineConstantBufferIndirect();
362 DefineStorageBuffers(bindings); 363 DefineStorageBuffers(bindings);
363 SetupImages(bindings); 364 SetupImages(bindings);
364 SetupTextures(bindings); 365 SetupTextures(bindings);
@@ -436,6 +437,24 @@ void EmitContext::DefineConstantBuffers(Bindings& bindings) {
436 } 437 }
437} 438}
438 439
440void EmitContext::DefineConstantBufferIndirect() {
441 if (!info.uses_cbuf_indirect) {
442 return;
443 }
444
445 header += profile.has_gl_cbuf_ftou_bug ? "uvec4 " : "vec4 ";
446 header += "GetCbufIndirect(uint binding, uint offset){"
447 "switch(binding){"
448 "default:";
449
450 for (const auto& desc : info.constant_buffer_descriptors) {
451 header +=
452 fmt::format("case {}:return {}_cbuf{}[offset];", desc.index, stage_name, desc.index);
453 }
454
455 header += "}}";
456}
457
439void EmitContext::DefineStorageBuffers(Bindings& bindings) { 458void EmitContext::DefineStorageBuffers(Bindings& bindings) {
440 if (info.storage_buffers_descriptors.empty()) { 459 if (info.storage_buffers_descriptors.empty()) {
441 return; 460 return;
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.h b/src/shader_recompiler/backend/glsl/glsl_emit_context.h
index d9b639d29..2b13db6e6 100644
--- a/src/shader_recompiler/backend/glsl/glsl_emit_context.h
+++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.h
@@ -162,6 +162,7 @@ public:
162private: 162private:
163 void SetupExtensions(); 163 void SetupExtensions();
164 void DefineConstantBuffers(Bindings& bindings); 164 void DefineConstantBuffers(Bindings& bindings);
165 void DefineConstantBufferIndirect();
165 void DefineStorageBuffers(Bindings& bindings); 166 void DefineStorageBuffers(Bindings& bindings);
166 void DefineGenericOutput(size_t index, u32 invocations); 167 void DefineGenericOutput(size_t index, u32 invocations);
167 void DefineHelperFunctions(); 168 void DefineHelperFunctions();
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index 28f6a6184..9c83cd2e4 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -1043,15 +1043,15 @@ void EmitContext::DefineConstantBufferIndirectFunctions(const Info& info) {
1043 const Id merge_label{OpLabel()}; 1043 const Id merge_label{OpLabel()};
1044 const Id uniform_type{uniform_types.*member_ptr}; 1044 const Id uniform_type{uniform_types.*member_ptr};
1045 1045
1046 std::array<Id, Info::MAX_CBUFS> buf_labels; 1046 std::array<Id, Info::MAX_INDIRECT_CBUFS> buf_labels;
1047 std::array<Sirit::Literal, Info::MAX_CBUFS> buf_literals; 1047 std::array<Sirit::Literal, Info::MAX_INDIRECT_CBUFS> buf_literals;
1048 for (u32 i = 0; i < Info::MAX_CBUFS; i++) { 1048 for (u32 i = 0; i < Info::MAX_INDIRECT_CBUFS; i++) {
1049 buf_labels[i] = OpLabel(); 1049 buf_labels[i] = OpLabel();
1050 buf_literals[i] = Sirit::Literal{i}; 1050 buf_literals[i] = Sirit::Literal{i};
1051 } 1051 }
1052 OpSelectionMerge(merge_label, spv::SelectionControlMask::MaskNone); 1052 OpSelectionMerge(merge_label, spv::SelectionControlMask::MaskNone);
1053 OpSwitch(binding, buf_labels[0], buf_literals, buf_labels); 1053 OpSwitch(binding, buf_labels[0], buf_literals, buf_labels);
1054 for (u32 i = 0; i < Info::MAX_CBUFS; i++) { 1054 for (u32 i = 0; i < Info::MAX_INDIRECT_CBUFS; i++) {
1055 AddLabel(buf_labels[i]); 1055 AddLabel(buf_labels[i]);
1056 const Id cbuf{cbufs[i].*member_ptr}; 1056 const Id cbuf{cbufs[i].*member_ptr};
1057 const Id access_chain{OpAccessChain(uniform_type, cbuf, u32_zero_value, offset)}; 1057 const Id access_chain{OpAccessChain(uniform_type, cbuf, u32_zero_value, offset)};
@@ -1064,22 +1064,23 @@ void EmitContext::DefineConstantBufferIndirectFunctions(const Info& info) {
1064 return func; 1064 return func;
1065 }}; 1065 }};
1066 IR::Type types{info.used_indirect_cbuf_types}; 1066 IR::Type types{info.used_indirect_cbuf_types};
1067 if (True(types & IR::Type::U8)) { 1067 bool supports_aliasing = profile.support_descriptor_aliasing;
1068 if (supports_aliasing && True(types & IR::Type::U8)) {
1068 load_const_func_u8 = make_accessor(U8, &UniformDefinitions::U8); 1069 load_const_func_u8 = make_accessor(U8, &UniformDefinitions::U8);
1069 } 1070 }
1070 if (True(types & IR::Type::U16)) { 1071 if (supports_aliasing && True(types & IR::Type::U16)) {
1071 load_const_func_u16 = make_accessor(U16, &UniformDefinitions::U16); 1072 load_const_func_u16 = make_accessor(U16, &UniformDefinitions::U16);
1072 } 1073 }
1073 if (True(types & IR::Type::F32)) { 1074 if (supports_aliasing && True(types & IR::Type::F32)) {
1074 load_const_func_f32 = make_accessor(F32[1], &UniformDefinitions::F32); 1075 load_const_func_f32 = make_accessor(F32[1], &UniformDefinitions::F32);
1075 } 1076 }
1076 if (True(types & IR::Type::U32)) { 1077 if (supports_aliasing && True(types & IR::Type::U32)) {
1077 load_const_func_u32 = make_accessor(U32[1], &UniformDefinitions::U32); 1078 load_const_func_u32 = make_accessor(U32[1], &UniformDefinitions::U32);
1078 } 1079 }
1079 if (True(types & IR::Type::U32x2)) { 1080 if (supports_aliasing && True(types & IR::Type::U32x2)) {
1080 load_const_func_u32x2 = make_accessor(U32[2], &UniformDefinitions::U32x2); 1081 load_const_func_u32x2 = make_accessor(U32[2], &UniformDefinitions::U32x2);
1081 } 1082 }
1082 if (True(types & IR::Type::U32x4)) { 1083 if (!supports_aliasing || True(types & IR::Type::U32x4)) {
1083 load_const_func_u32x4 = make_accessor(U32[4], &UniformDefinitions::U32x4); 1084 load_const_func_u32x4 = make_accessor(U32[4], &UniformDefinitions::U32x4);
1084 } 1085 }
1085} 1086}
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
index 0b2c60842..16278faab 100644
--- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
+++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
@@ -32,13 +32,8 @@ void AddConstantBufferDescriptor(Info& info, u32 index, u32 count) {
32void AddRegisterIndexedLdc(Info& info) { 32void AddRegisterIndexedLdc(Info& info) {
33 info.uses_cbuf_indirect = true; 33 info.uses_cbuf_indirect = true;
34 34
35 // The shader can use any possible constant buffer 35 for (u32 i = 0; i < Info::MAX_INDIRECT_CBUFS; i++) {
36 info.constant_buffer_mask = (1 << Info::MAX_CBUFS) - 1; 36 AddConstantBufferDescriptor(info, i, 1);
37
38 auto& cbufs{info.constant_buffer_descriptors};
39 cbufs.clear();
40 for (u32 i = 0; i < Info::MAX_CBUFS; i++) {
41 cbufs.push_back(ConstantBufferDescriptor{.index = i, .count = 1});
42 37
43 // The shader can use any possible access size 38 // The shader can use any possible access size
44 info.constant_buffer_used_sizes[i] = 0x10'000; 39 info.constant_buffer_used_sizes[i] = 0x10'000;
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h
index 9d36bd9eb..a3a09c71c 100644
--- a/src/shader_recompiler/shader_info.h
+++ b/src/shader_recompiler/shader_info.h
@@ -105,6 +105,7 @@ struct ImageDescriptor {
105using ImageDescriptors = boost::container::small_vector<ImageDescriptor, 4>; 105using ImageDescriptors = boost::container::small_vector<ImageDescriptor, 4>;
106 106
107struct Info { 107struct Info {
108 static constexpr size_t MAX_INDIRECT_CBUFS{14};
108 static constexpr size_t MAX_CBUFS{18}; 109 static constexpr size_t MAX_CBUFS{18};
109 static constexpr size_t MAX_SSBOS{32}; 110 static constexpr size_t MAX_SSBOS{32};
110 111
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index ba9ba082f..789af452d 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -230,7 +230,7 @@ struct GPU::Impl {
230 void IncrementSyncPoint(u32 syncpoint_id) { 230 void IncrementSyncPoint(u32 syncpoint_id) {
231 auto& syncpoint = syncpoints.at(syncpoint_id); 231 auto& syncpoint = syncpoints.at(syncpoint_id);
232 syncpoint++; 232 syncpoint++;
233 std::lock_guard lock{sync_mutex}; 233 std::scoped_lock lock{sync_mutex};
234 sync_cv.notify_all(); 234 sync_cv.notify_all();
235 auto& interrupt = syncpt_interrupts.at(syncpoint_id); 235 auto& interrupt = syncpt_interrupts.at(syncpoint_id);
236 if (!interrupt.empty()) { 236 if (!interrupt.empty()) {
@@ -252,7 +252,7 @@ struct GPU::Impl {
252 } 252 }
253 253
254 void RegisterSyncptInterrupt(u32 syncpoint_id, u32 value) { 254 void RegisterSyncptInterrupt(u32 syncpoint_id, u32 value) {
255 std::lock_guard lock{sync_mutex}; 255 std::scoped_lock lock{sync_mutex};
256 auto& interrupt = syncpt_interrupts.at(syncpoint_id); 256 auto& interrupt = syncpt_interrupts.at(syncpoint_id);
257 bool contains = std::any_of(interrupt.begin(), interrupt.end(), 257 bool contains = std::any_of(interrupt.begin(), interrupt.end(),
258 [value](u32 in_value) { return in_value == value; }); 258 [value](u32 in_value) { return in_value == value; });
@@ -263,7 +263,7 @@ struct GPU::Impl {
263 } 263 }
264 264
265 [[nodiscard]] bool CancelSyncptInterrupt(u32 syncpoint_id, u32 value) { 265 [[nodiscard]] bool CancelSyncptInterrupt(u32 syncpoint_id, u32 value) {
266 std::lock_guard lock{sync_mutex}; 266 std::scoped_lock lock{sync_mutex};
267 auto& interrupt = syncpt_interrupts.at(syncpoint_id); 267 auto& interrupt = syncpt_interrupts.at(syncpoint_id);
268 const auto iter = 268 const auto iter =
269 std::find_if(interrupt.begin(), interrupt.end(), 269 std::find_if(interrupt.begin(), interrupt.end(),
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 9547f277a..4e8999915 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -56,7 +56,7 @@ static void RunThread(std::stop_token stop_token, Core::System& system,
56 if (next.block) { 56 if (next.block) {
57 // We have to lock the write_lock to ensure that the condition_variable wait not get a 57 // We have to lock the write_lock to ensure that the condition_variable wait not get a
58 // race between the check and the lock itself. 58 // race between the check and the lock itself.
59 std::lock_guard lk(state.write_lock); 59 std::scoped_lock lk{state.write_lock};
60 state.cv.notify_all(); 60 state.cv.notify_all();
61 } 61 }
62 } 62 }
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
index af05d47d1..190fc6aea 100644
--- a/src/video_core/host_shaders/CMakeLists.txt
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -18,6 +18,7 @@ set(SHADER_FILES
18 full_screen_triangle.vert 18 full_screen_triangle.vert
19 fxaa.frag 19 fxaa.frag
20 fxaa.vert 20 fxaa.vert
21 opengl_convert_s8d24.comp
21 opengl_copy_bc4.comp 22 opengl_copy_bc4.comp
22 opengl_present.frag 23 opengl_present.frag
23 opengl_present.vert 24 opengl_present.vert
diff --git a/src/video_core/host_shaders/opengl_convert_s8d24.comp b/src/video_core/host_shaders/opengl_convert_s8d24.comp
new file mode 100644
index 000000000..83e1ab176
--- /dev/null
+++ b/src/video_core/host_shaders/opengl_convert_s8d24.comp
@@ -0,0 +1,18 @@
1// Copyright 2022 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
7layout(local_size_x = 16, local_size_y = 8) in;
8
9layout(binding = 0, rgba8ui) restrict uniform uimage2D destination;
10layout(location = 0) uniform uvec3 size;
11
12void main() {
13 if (any(greaterThanEqual(gl_GlobalInvocationID, size))) {
14 return;
15 }
16 uvec4 components = imageLoad(destination, ivec2(gl_GlobalInvocationID.xy));
17 imageStore(destination, ivec2(gl_GlobalInvocationID.xy), components.wxyz);
18}
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
index 9e6732abd..fd40966d5 100644
--- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
+++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
@@ -253,7 +253,7 @@ GraphicsPipeline::GraphicsPipeline(
253 } 253 }
254 } 254 }
255 if (in_parallel) { 255 if (in_parallel) {
256 std::lock_guard lock{built_mutex}; 256 std::scoped_lock lock{built_mutex};
257 built_fence.Create(); 257 built_fence.Create();
258 // Flush this context to ensure compilation commands and fence are in the GPU pipe. 258 // Flush this context to ensure compilation commands and fence are in the GPU pipe.
259 glFlush(); 259 glFlush();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index e6f9ece8b..8ef79753f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -520,6 +520,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
520 // ASSERT_MSG(image_view->size.width == config.width, "Framebuffer width is different"); 520 // ASSERT_MSG(image_view->size.width == config.width, "Framebuffer width is different");
521 // ASSERT_MSG(image_view->size.height == config.height, "Framebuffer height is different"); 521 // ASSERT_MSG(image_view->size.height == config.height, "Framebuffer height is different");
522 522
523 screen_info.texture.width = image_view->size.width;
524 screen_info.texture.height = image_view->size.height;
523 screen_info.display_texture = image_view->Handle(Shader::TextureType::Color2D); 525 screen_info.display_texture = image_view->Handle(Shader::TextureType::Color2D);
524 screen_info.display_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format); 526 screen_info.display_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format);
525 return true; 527 return true;
@@ -557,12 +559,19 @@ void RasterizerOpenGL::SyncViewport() {
557 const bool dirty_viewport = flags[Dirty::Viewports] || rescale_viewports; 559 const bool dirty_viewport = flags[Dirty::Viewports] || rescale_viewports;
558 const bool dirty_clip_control = flags[Dirty::ClipControl]; 560 const bool dirty_clip_control = flags[Dirty::ClipControl];
559 561
560 if (dirty_clip_control || flags[Dirty::FrontFace]) { 562 if (dirty_viewport || dirty_clip_control || flags[Dirty::FrontFace]) {
561 flags[Dirty::FrontFace] = false; 563 flags[Dirty::FrontFace] = false;
562 564
563 GLenum mode = MaxwellToGL::FrontFace(regs.front_face); 565 GLenum mode = MaxwellToGL::FrontFace(regs.front_face);
566 bool flip_faces = false;
564 if (regs.screen_y_control.triangle_rast_flip != 0 && 567 if (regs.screen_y_control.triangle_rast_flip != 0 &&
565 regs.viewport_transform[0].scale_y < 0.0f) { 568 regs.viewport_transform[0].scale_y < 0.0f) {
569 flip_faces = !flip_faces;
570 }
571 if (regs.viewport_transform[0].scale_z < 0.0f) {
572 flip_faces = !flip_faces;
573 }
574 if (flip_faces) {
566 switch (mode) { 575 switch (mode) {
567 case GL_CW: 576 case GL_CW:
568 mode = GL_CCW; 577 mode = GL_CCW;
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 6423992c3..05c5e702c 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -258,7 +258,7 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
258 [this, key, env = std::move(env), &state, &callback](Context* ctx) mutable { 258 [this, key, env = std::move(env), &state, &callback](Context* ctx) mutable {
259 ctx->pools.ReleaseContents(); 259 ctx->pools.ReleaseContents();
260 auto pipeline{CreateComputePipeline(ctx->pools, key, env)}; 260 auto pipeline{CreateComputePipeline(ctx->pools, key, env)};
261 std::lock_guard lock{state.mutex}; 261 std::scoped_lock lock{state.mutex};
262 if (pipeline) { 262 if (pipeline) {
263 compute_cache.emplace(key, std::move(pipeline)); 263 compute_cache.emplace(key, std::move(pipeline));
264 } 264 }
@@ -280,7 +280,7 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
280 } 280 }
281 ctx->pools.ReleaseContents(); 281 ctx->pools.ReleaseContents();
282 auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)}; 282 auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)};
283 std::lock_guard lock{state.mutex}; 283 std::scoped_lock lock{state.mutex};
284 if (pipeline) { 284 if (pipeline) {
285 graphics_cache.emplace(key, std::move(pipeline)); 285 graphics_cache.emplace(key, std::move(pipeline));
286 } 286 }
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 8f9a65beb..d12076358 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -409,8 +409,8 @@ ImageBufferMap::~ImageBufferMap() {
409 409
410TextureCacheRuntime::TextureCacheRuntime(const Device& device_, ProgramManager& program_manager, 410TextureCacheRuntime::TextureCacheRuntime(const Device& device_, ProgramManager& program_manager,
411 StateTracker& state_tracker_) 411 StateTracker& state_tracker_)
412 : device{device_}, state_tracker{state_tracker_}, 412 : device{device_}, state_tracker{state_tracker_}, util_shaders(program_manager),
413 util_shaders(program_manager), resolution{Settings::values.resolution_info} { 413 format_conversion_pass{util_shaders}, resolution{Settings::values.resolution_info} {
414 static constexpr std::array TARGETS{GL_TEXTURE_1D_ARRAY, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D}; 414 static constexpr std::array TARGETS{GL_TEXTURE_1D_ARRAY, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D};
415 for (size_t i = 0; i < TARGETS.size(); ++i) { 415 for (size_t i = 0; i < TARGETS.size(); ++i) {
416 const GLenum target = TARGETS[i]; 416 const GLenum target = TARGETS[i];
@@ -1325,6 +1325,9 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
1325 1325
1326Framebuffer::~Framebuffer() = default; 1326Framebuffer::~Framebuffer() = default;
1327 1327
1328FormatConversionPass::FormatConversionPass(UtilShaders& util_shaders_)
1329 : util_shaders{util_shaders_} {}
1330
1328void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image, 1331void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image,
1329 std::span<const VideoCommon::ImageCopy> copies) { 1332 std::span<const VideoCommon::ImageCopy> copies) {
1330 const GLenum dst_target = ImageTarget(dst_image.info); 1333 const GLenum dst_target = ImageTarget(dst_image.info);
@@ -1357,6 +1360,12 @@ void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image,
1357 dst_origin.z, region.width, region.height, region.depth, 1360 dst_origin.z, region.width, region.height, region.depth,
1358 dst_image.GlFormat(), dst_image.GlType(), nullptr); 1361 dst_image.GlFormat(), dst_image.GlType(), nullptr);
1359 } 1362 }
1363
1364 // Swap component order of S8D24 to ABGR8 reinterprets
1365 if (src_image.info.format == PixelFormat::D24_UNORM_S8_UINT &&
1366 dst_image.info.format == PixelFormat::A8B8G8R8_UNORM) {
1367 util_shaders.ConvertS8D24(dst_image, copies);
1368 }
1360} 1369}
1361 1370
1362} // namespace OpenGL 1371} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 53088b66e..672fa8dde 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -55,13 +55,14 @@ struct FormatProperties {
55 55
56class FormatConversionPass { 56class FormatConversionPass {
57public: 57public:
58 FormatConversionPass() = default; 58 explicit FormatConversionPass(UtilShaders& util_shaders);
59 ~FormatConversionPass() = default; 59 ~FormatConversionPass() = default;
60 60
61 void ConvertImage(Image& dst_image, Image& src_image, 61 void ConvertImage(Image& dst_image, Image& src_image,
62 std::span<const VideoCommon::ImageCopy> copies); 62 std::span<const VideoCommon::ImageCopy> copies);
63 63
64private: 64private:
65 UtilShaders& util_shaders;
65 OGLBuffer intermediate_pbo; 66 OGLBuffer intermediate_pbo;
66 size_t pbo_size{}; 67 size_t pbo_size{};
67}; 68};
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index f8f29013a..3a3c213bb 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -208,6 +208,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
208 // Framebuffer orientation handling 208 // Framebuffer orientation handling
209 framebuffer_transform_flags = framebuffer.transform_flags; 209 framebuffer_transform_flags = framebuffer.transform_flags;
210 framebuffer_crop_rect = framebuffer.crop_rect; 210 framebuffer_crop_rect = framebuffer.crop_rect;
211 framebuffer_width = framebuffer.width;
212 framebuffer_height = framebuffer.height;
211 213
212 const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset}; 214 const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset};
213 screen_info.was_accelerated = 215 screen_info.was_accelerated =
@@ -480,9 +482,12 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
480 ASSERT_MSG(framebuffer_crop_rect.top == 0, "Unimplemented"); 482 ASSERT_MSG(framebuffer_crop_rect.top == 0, "Unimplemented");
481 ASSERT_MSG(framebuffer_crop_rect.left == 0, "Unimplemented"); 483 ASSERT_MSG(framebuffer_crop_rect.left == 0, "Unimplemented");
482 484
485 f32 scale_u = static_cast<f32>(framebuffer_width) / static_cast<f32>(screen_info.texture.width);
486 f32 scale_v =
487 static_cast<f32>(framebuffer_height) / static_cast<f32>(screen_info.texture.height);
488
483 // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering 489 // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering
484 // (e.g. handheld mode) on a 1920x1080 framebuffer. 490 // (e.g. handheld mode) on a 1920x1080 framebuffer.
485 f32 scale_u = 1.f, scale_v = 1.f;
486 if (framebuffer_crop_rect.GetWidth() > 0) { 491 if (framebuffer_crop_rect.GetWidth() > 0) {
487 scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) / 492 scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) /
488 static_cast<f32>(screen_info.texture.width); 493 static_cast<f32>(screen_info.texture.width);
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index aa206878b..ae9558a33 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -137,6 +137,8 @@ private:
137 /// Used for transforming the framebuffer orientation 137 /// Used for transforming the framebuffer orientation
138 Service::android::BufferTransformFlags framebuffer_transform_flags{}; 138 Service::android::BufferTransformFlags framebuffer_transform_flags{};
139 Common::Rectangle<int> framebuffer_crop_rect; 139 Common::Rectangle<int> framebuffer_crop_rect;
140 u32 framebuffer_width;
141 u32 framebuffer_height;
140}; 142};
141 143
142} // namespace OpenGL 144} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/util_shaders.cpp b/src/video_core/renderer_opengl/util_shaders.cpp
index 897c380b3..04c482a09 100644
--- a/src/video_core/renderer_opengl/util_shaders.cpp
+++ b/src/video_core/renderer_opengl/util_shaders.cpp
@@ -13,6 +13,7 @@
13#include "video_core/host_shaders/astc_decoder_comp.h" 13#include "video_core/host_shaders/astc_decoder_comp.h"
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_convert_s8d24_comp.h"
16#include "video_core/host_shaders/opengl_copy_bc4_comp.h" 17#include "video_core/host_shaders/opengl_copy_bc4_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_shader_manager.h" 19#include "video_core/renderer_opengl/gl_shader_manager.h"
@@ -50,7 +51,8 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_)
50 block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)), 51 block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)),
51 block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)), 52 block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)),
52 pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)), 53 pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)),
53 copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) { 54 copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)),
55 convert_s8d24_program(MakeProgram(OPENGL_CONVERT_S8D24_COMP)) {
54 const auto swizzle_table = Tegra::Texture::MakeSwizzleTable(); 56 const auto swizzle_table = Tegra::Texture::MakeSwizzleTable();
55 swizzle_table_buffer.Create(); 57 swizzle_table_buffer.Create();
56 glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0); 58 glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0);
@@ -248,6 +250,26 @@ void UtilShaders::CopyBC4(Image& dst_image, Image& src_image, std::span<const Im
248 program_manager.RestoreGuestCompute(); 250 program_manager.RestoreGuestCompute();
249} 251}
250 252
253void UtilShaders::ConvertS8D24(Image& dst_image, std::span<const ImageCopy> copies) {
254 static constexpr GLuint BINDING_DESTINATION = 0;
255 static constexpr GLuint LOC_SIZE = 0;
256
257 program_manager.BindComputeProgram(convert_s8d24_program.handle);
258 for (const ImageCopy& copy : copies) {
259 ASSERT(copy.src_subresource.base_layer == 0);
260 ASSERT(copy.src_subresource.num_layers == 1);
261 ASSERT(copy.dst_subresource.base_layer == 0);
262 ASSERT(copy.dst_subresource.num_layers == 1);
263
264 glUniform3ui(LOC_SIZE, copy.extent.width, copy.extent.height, copy.extent.depth);
265 glBindImageTexture(BINDING_DESTINATION, dst_image.StorageHandle(),
266 copy.dst_subresource.base_level, GL_TRUE, 0, GL_READ_WRITE, GL_RGBA8UI);
267 glDispatchCompute(Common::DivCeil(copy.extent.width, 16u),
268 Common::DivCeil(copy.extent.height, 8u), copy.extent.depth);
269 }
270 program_manager.RestoreGuestCompute();
271}
272
251GLenum StoreFormat(u32 bytes_per_block) { 273GLenum StoreFormat(u32 bytes_per_block) {
252 switch (bytes_per_block) { 274 switch (bytes_per_block) {
253 case 1: 275 case 1:
diff --git a/src/video_core/renderer_opengl/util_shaders.h b/src/video_core/renderer_opengl/util_shaders.h
index 5de95ea7a..5c132e67f 100644
--- a/src/video_core/renderer_opengl/util_shaders.h
+++ b/src/video_core/renderer_opengl/util_shaders.h
@@ -39,6 +39,8 @@ public:
39 void CopyBC4(Image& dst_image, Image& src_image, 39 void CopyBC4(Image& dst_image, Image& src_image,
40 std::span<const VideoCommon::ImageCopy> copies); 40 std::span<const VideoCommon::ImageCopy> copies);
41 41
42 void ConvertS8D24(Image& dst_image, std::span<const VideoCommon::ImageCopy> copies);
43
42private: 44private:
43 ProgramManager& program_manager; 45 ProgramManager& program_manager;
44 46
@@ -49,6 +51,7 @@ private:
49 OGLProgram block_linear_unswizzle_3d_program; 51 OGLProgram block_linear_unswizzle_3d_program;
50 OGLProgram pitch_unswizzle_program; 52 OGLProgram pitch_unswizzle_program;
51 OGLProgram copy_bc4_program; 53 OGLProgram copy_bc4_program;
54 OGLProgram convert_s8d24_program;
52}; 55};
53 56
54GLenum StoreFormat(u32 bytes_per_block); 57GLenum StoreFormat(u32 bytes_per_block);
diff --git a/src/video_core/renderer_vulkan/pipeline_statistics.cpp b/src/video_core/renderer_vulkan/pipeline_statistics.cpp
index bfec931a6..7ccadf084 100644
--- a/src/video_core/renderer_vulkan/pipeline_statistics.cpp
+++ b/src/video_core/renderer_vulkan/pipeline_statistics.cpp
@@ -57,7 +57,7 @@ void PipelineStatistics::Collect(VkPipeline pipeline) {
57 stage_stats.basic_block_count = GetUint64(statistic); 57 stage_stats.basic_block_count = GetUint64(statistic);
58 } 58 }
59 } 59 }
60 std::lock_guard lock{mutex}; 60 std::scoped_lock lock{mutex};
61 collected_stats.push_back(stage_stats); 61 collected_stats.push_back(stage_stats);
62 } 62 }
63} 63}
@@ -66,7 +66,7 @@ void PipelineStatistics::Report() const {
66 double num{}; 66 double num{};
67 Stats total; 67 Stats total;
68 { 68 {
69 std::lock_guard lock{mutex}; 69 std::scoped_lock lock{mutex};
70 for (const Stats& stats : collected_stats) { 70 for (const Stats& stats : collected_stats) {
71 total.code_size += stats.code_size; 71 total.code_size += stats.code_size;
72 total.register_count += stats.register_count; 72 total.register_count += stats.register_count;
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index d893c1952..b866e9103 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -1406,8 +1406,9 @@ void VKBlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfi
1406 UNIMPLEMENTED_IF(framebuffer_crop_rect.top != 0); 1406 UNIMPLEMENTED_IF(framebuffer_crop_rect.top != 0);
1407 UNIMPLEMENTED_IF(framebuffer_crop_rect.left != 0); 1407 UNIMPLEMENTED_IF(framebuffer_crop_rect.left != 0);
1408 1408
1409 f32 scale_u = 1.0f; 1409 f32 scale_u = static_cast<f32>(framebuffer.width) / static_cast<f32>(screen_info.width);
1410 f32 scale_v = 1.0f; 1410 f32 scale_v = static_cast<f32>(framebuffer.height) / static_cast<f32>(screen_info.height);
1411
1411 // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering 1412 // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering
1412 // (e.g. handheld mode) on a 1920x1080 framebuffer. 1413 // (e.g. handheld mode) on a 1920x1080 framebuffer.
1413 if (!fsr) { 1414 if (!fsr) {
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index de36bcdb7..97b3594c2 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -77,7 +77,7 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript
77 if (pipeline_statistics) { 77 if (pipeline_statistics) {
78 pipeline_statistics->Collect(*pipeline); 78 pipeline_statistics->Collect(*pipeline);
79 } 79 }
80 std::lock_guard lock{build_mutex}; 80 std::scoped_lock lock{build_mutex};
81 is_built = true; 81 is_built = true;
82 build_condvar.notify_one(); 82 build_condvar.notify_one();
83 if (shader_notify) { 83 if (shader_notify) {
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index d514b71d0..8959d6059 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -258,7 +258,7 @@ GraphicsPipeline::GraphicsPipeline(
258 pipeline_statistics->Collect(*pipeline); 258 pipeline_statistics->Collect(*pipeline);
259 } 259 }
260 260
261 std::lock_guard lock{build_mutex}; 261 std::scoped_lock lock{build_mutex};
262 is_built = true; 262 is_built = true;
263 build_condvar.notify_one(); 263 build_condvar.notify_one();
264 if (shader_notify) { 264 if (shader_notify) {
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 27e59df73..336d1e9dc 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -404,7 +404,7 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
404 workers.QueueWork([this, key, env = std::move(env), &state, &callback]() mutable { 404 workers.QueueWork([this, key, env = std::move(env), &state, &callback]() mutable {
405 ShaderPools pools; 405 ShaderPools pools;
406 auto pipeline{CreateComputePipeline(pools, key, env, state.statistics.get(), false)}; 406 auto pipeline{CreateComputePipeline(pools, key, env, state.statistics.get(), false)};
407 std::lock_guard lock{state.mutex}; 407 std::scoped_lock lock{state.mutex};
408 if (pipeline) { 408 if (pipeline) {
409 compute_cache.emplace(key, std::move(pipeline)); 409 compute_cache.emplace(key, std::move(pipeline));
410 } 410 }
@@ -434,7 +434,7 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
434 auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs), 434 auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs),
435 state.statistics.get(), false)}; 435 state.statistics.get(), false)};
436 436
437 std::lock_guard lock{state.mutex}; 437 std::scoped_lock lock{state.mutex};
438 graphics_cache.emplace(key, std::move(pipeline)); 438 graphics_cache.emplace(key, std::move(pipeline));
439 ++state.built; 439 ++state.built;
440 if (state.has_loaded) { 440 if (state.has_loaded) {
diff --git a/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp b/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp
index 451ffe019..d22bb6694 100644
--- a/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp
@@ -36,7 +36,7 @@ VkAttachmentDescription AttachmentDescription(const Device& device, PixelFormat
36RenderPassCache::RenderPassCache(const Device& device_) : device{&device_} {} 36RenderPassCache::RenderPassCache(const Device& device_) : device{&device_} {}
37 37
38VkRenderPass RenderPassCache::Get(const RenderPassKey& key) { 38VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
39 std::lock_guard lock{mutex}; 39 std::scoped_lock lock{mutex};
40 const auto [pair, is_new] = cache.try_emplace(key); 40 const auto [pair, is_new] = cache.try_emplace(key);
41 if (!is_new) { 41 if (!is_new) {
42 return *pair->second; 42 return *pair->second;
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index ad320991b..6a9416457 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -73,7 +73,7 @@ void VKScheduler::DispatchWork() {
73 return; 73 return;
74 } 74 }
75 { 75 {
76 std::lock_guard lock{work_mutex}; 76 std::scoped_lock lock{work_mutex};
77 work_queue.push(std::move(chunk)); 77 work_queue.push(std::move(chunk));
78 } 78 }
79 work_cv.notify_one(); 79 work_cv.notify_one();
@@ -157,7 +157,7 @@ void VKScheduler::WorkerThread(std::stop_token stop_token) {
157 if (has_submit) { 157 if (has_submit) {
158 AllocateWorkerCommandBuffer(); 158 AllocateWorkerCommandBuffer();
159 } 159 }
160 std::lock_guard reserve_lock{reserve_mutex}; 160 std::scoped_lock reserve_lock{reserve_mutex};
161 chunk_reserve.push_back(std::move(work)); 161 chunk_reserve.push_back(std::move(work));
162 } while (!stop_token.stop_requested()); 162 } while (!stop_token.stop_requested());
163} 163}
@@ -282,7 +282,7 @@ void VKScheduler::EndRenderPass() {
282} 282}
283 283
284void VKScheduler::AcquireNewChunk() { 284void VKScheduler::AcquireNewChunk() {
285 std::lock_guard lock{reserve_mutex}; 285 std::scoped_lock lock{reserve_mutex};
286 if (chunk_reserve.empty()) { 286 if (chunk_reserve.empty()) {
287 chunk = std::make_unique<CommandChunk>(); 287 chunk = std::make_unique<CommandChunk>();
288 return; 288 return;
diff --git a/src/video_core/shader_cache.cpp b/src/video_core/shader_cache.cpp
index 87636857d..75031767a 100644
--- a/src/video_core/shader_cache.cpp
+++ b/src/video_core/shader_cache.cpp
@@ -25,7 +25,7 @@ void ShaderCache::InvalidateRegion(VAddr addr, size_t size) {
25} 25}
26 26
27void ShaderCache::OnCPUWrite(VAddr addr, size_t size) { 27void ShaderCache::OnCPUWrite(VAddr addr, size_t size) {
28 std::lock_guard lock{invalidation_mutex}; 28 std::scoped_lock lock{invalidation_mutex};
29 InvalidatePagesInRegion(addr, size); 29 InvalidatePagesInRegion(addr, size);
30} 30}
31 31
diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp
index 4208bd044..58b0c2f10 100644
--- a/src/web_service/web_backend.cpp
+++ b/src/web_service/web_backend.cpp
@@ -32,7 +32,7 @@ constexpr std::size_t TIMEOUT_SECONDS = 30;
32struct Client::Impl { 32struct Client::Impl {
33 Impl(std::string host, std::string username, std::string token) 33 Impl(std::string host, std::string username, std::string token)
34 : host{std::move(host)}, username{std::move(username)}, token{std::move(token)} { 34 : host{std::move(host)}, username{std::move(username)}, token{std::move(token)} {
35 std::lock_guard lock{jwt_cache.mutex}; 35 std::scoped_lock lock{jwt_cache.mutex};
36 if (this->username == jwt_cache.username && this->token == jwt_cache.token) { 36 if (this->username == jwt_cache.username && this->token == jwt_cache.token) {
37 jwt = jwt_cache.jwt; 37 jwt = jwt_cache.jwt;
38 } 38 }
@@ -147,7 +147,7 @@ struct Client::Impl {
147 if (result.result_code != WebResult::Code::Success) { 147 if (result.result_code != WebResult::Code::Success) {
148 LOG_ERROR(WebService, "UpdateJWT failed"); 148 LOG_ERROR(WebService, "UpdateJWT failed");
149 } else { 149 } else {
150 std::lock_guard lock{jwt_cache.mutex}; 150 std::scoped_lock lock{jwt_cache.mutex};
151 jwt_cache.username = username; 151 jwt_cache.username = username;
152 jwt_cache.token = token; 152 jwt_cache.token = token;
153 jwt_cache.jwt = jwt = result.returned_data; 153 jwt_cache.jwt = jwt = result.returned_data;
diff --git a/src/yuzu/util/controller_navigation.cpp b/src/yuzu/util/controller_navigation.cpp
index c2b13123d..9a1868cae 100644
--- a/src/yuzu/util/controller_navigation.cpp
+++ b/src/yuzu/util/controller_navigation.cpp
@@ -39,7 +39,7 @@ void ControllerNavigation::TriggerButton(Settings::NativeButton::Values native_b
39} 39}
40 40
41void ControllerNavigation::ControllerUpdateEvent(Core::HID::ControllerTriggerType type) { 41void ControllerNavigation::ControllerUpdateEvent(Core::HID::ControllerTriggerType type) {
42 std::lock_guard lock{mutex}; 42 std::scoped_lock lock{mutex};
43 if (!Settings::values.controller_navigation) { 43 if (!Settings::values.controller_navigation) {
44 return; 44 return;
45 } 45 }