summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/arm/arm_interface.h11
-rw-r--r--src/core/arm/cpu_interrupt_handler.cpp24
-rw-r--r--src/core/arm/cpu_interrupt_handler.h39
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp32
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h5
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp31
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h6
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.cpp31
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.h2
-rw-r--r--src/core/debugger/debugger.cpp9
-rw-r--r--src/core/hid/emulated_controller.cpp30
-rw-r--r--src/core/hid/emulated_controller.h7
-rw-r--r--src/core/hid/hid_types.h12
-rw-r--r--src/core/hle/kernel/kernel.cpp41
-rw-r--r--src/core/hle/kernel/kernel.h8
-rw-r--r--src/core/hle/kernel/physical_core.cpp29
-rw-r--r--src/core/hle/kernel/physical_core.h17
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp77
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp5
-rw-r--r--src/yuzu/CMakeLists.txt14
-rw-r--r--src/yuzu/bootmanager.cpp4
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui2
-rw-r--r--src/yuzu/configuration/configure_ui.cpp1
-rw-r--r--src/yuzu/main.cpp17
25 files changed, 255 insertions, 201 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index d314ff1ce..4e39649a8 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -6,8 +6,6 @@ add_library(core STATIC
6 announce_multiplayer_session.h 6 announce_multiplayer_session.h
7 arm/arm_interface.h 7 arm/arm_interface.h
8 arm/arm_interface.cpp 8 arm/arm_interface.cpp
9 arm/cpu_interrupt_handler.cpp
10 arm/cpu_interrupt_handler.h
11 arm/dynarmic/arm_dynarmic_32.cpp 9 arm/dynarmic/arm_dynarmic_32.cpp
12 arm/dynarmic/arm_dynarmic_32.h 10 arm/dynarmic/arm_dynarmic_32.h
13 arm/dynarmic/arm_dynarmic_64.cpp 11 arm/dynarmic/arm_dynarmic_64.cpp
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 73f259525..7d62d030e 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -27,7 +27,6 @@ namespace Core {
27class System; 27class System;
28class CPUInterruptHandler; 28class CPUInterruptHandler;
29 29
30using CPUInterrupts = std::array<CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>;
31using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>; 30using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>;
32 31
33/// Generic ARMv8 CPU interface 32/// Generic ARMv8 CPU interface
@@ -36,10 +35,8 @@ public:
36 YUZU_NON_COPYABLE(ARM_Interface); 35 YUZU_NON_COPYABLE(ARM_Interface);
37 YUZU_NON_MOVEABLE(ARM_Interface); 36 YUZU_NON_MOVEABLE(ARM_Interface);
38 37
39 explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_, 38 explicit ARM_Interface(System& system_, bool uses_wall_clock_)
40 bool uses_wall_clock_) 39 : system{system_}, uses_wall_clock{uses_wall_clock_} {}
41 : system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{
42 uses_wall_clock_} {}
43 virtual ~ARM_Interface() = default; 40 virtual ~ARM_Interface() = default;
44 41
45 struct ThreadContext32 { 42 struct ThreadContext32 {
@@ -181,6 +178,9 @@ public:
181 /// Signal an interrupt and ask the core to halt as soon as possible. 178 /// Signal an interrupt and ask the core to halt as soon as possible.
182 virtual void SignalInterrupt() = 0; 179 virtual void SignalInterrupt() = 0;
183 180
181 /// Clear a previous interrupt.
182 virtual void ClearInterrupt() = 0;
183
184 struct BacktraceEntry { 184 struct BacktraceEntry {
185 std::string module; 185 std::string module;
186 u64 address; 186 u64 address;
@@ -208,7 +208,6 @@ public:
208protected: 208protected:
209 /// System context that this ARM interface is running under. 209 /// System context that this ARM interface is running under.
210 System& system; 210 System& system;
211 CPUInterrupts& interrupt_handlers;
212 const WatchpointArray* watchpoints; 211 const WatchpointArray* watchpoints;
213 bool uses_wall_clock; 212 bool uses_wall_clock;
214 213
diff --git a/src/core/arm/cpu_interrupt_handler.cpp b/src/core/arm/cpu_interrupt_handler.cpp
deleted file mode 100644
index 77b6194d7..000000000
--- a/src/core/arm/cpu_interrupt_handler.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/thread.h"
5#include "core/arm/cpu_interrupt_handler.h"
6
7namespace Core {
8
9CPUInterruptHandler::CPUInterruptHandler() : interrupt_event{std::make_unique<Common::Event>()} {}
10
11CPUInterruptHandler::~CPUInterruptHandler() = default;
12
13void CPUInterruptHandler::SetInterrupt(bool is_interrupted_) {
14 if (is_interrupted_) {
15 interrupt_event->Set();
16 }
17 is_interrupted = is_interrupted_;
18}
19
20void CPUInterruptHandler::AwaitInterrupt() {
21 interrupt_event->Wait();
22}
23
24} // namespace Core
diff --git a/src/core/arm/cpu_interrupt_handler.h b/src/core/arm/cpu_interrupt_handler.h
deleted file mode 100644
index 286e12e53..000000000
--- a/src/core/arm/cpu_interrupt_handler.h
+++ /dev/null
@@ -1,39 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <atomic>
7#include <memory>
8
9namespace Common {
10class Event;
11}
12
13namespace Core {
14
15class CPUInterruptHandler {
16public:
17 CPUInterruptHandler();
18 ~CPUInterruptHandler();
19
20 CPUInterruptHandler(const CPUInterruptHandler&) = delete;
21 CPUInterruptHandler& operator=(const CPUInterruptHandler&) = delete;
22
23 CPUInterruptHandler(CPUInterruptHandler&&) = delete;
24 CPUInterruptHandler& operator=(CPUInterruptHandler&&) = delete;
25
26 bool IsInterrupted() const {
27 return is_interrupted;
28 }
29
30 void SetInterrupt(bool is_interrupted);
31
32 void AwaitInterrupt();
33
34private:
35 std::unique_ptr<Common::Event> interrupt_event;
36 std::atomic_bool is_interrupted{false};
37};
38
39} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index b8d2ce224..1638bc41d 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -11,7 +11,6 @@
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/page_table.h" 12#include "common/page_table.h"
13#include "common/settings.h" 13#include "common/settings.h"
14#include "core/arm/cpu_interrupt_handler.h"
15#include "core/arm/dynarmic/arm_dynarmic_32.h" 14#include "core/arm/dynarmic/arm_dynarmic_32.h"
16#include "core/arm/dynarmic/arm_dynarmic_cp15.h" 15#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
17#include "core/arm/dynarmic/arm_exclusive_monitor.h" 16#include "core/arm/dynarmic/arm_exclusive_monitor.h"
@@ -125,7 +124,9 @@ public:
125 } 124 }
126 125
127 void AddTicks(u64 ticks) override { 126 void AddTicks(u64 ticks) override {
128 ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); 127 if (parent.uses_wall_clock) {
128 return;
129 }
129 130
130 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a 131 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
131 // rough approximation of the amount of executed ticks in the system, it may be thrown off 132 // rough approximation of the amount of executed ticks in the system, it may be thrown off
@@ -142,7 +143,12 @@ public:
142 } 143 }
143 144
144 u64 GetTicksRemaining() override { 145 u64 GetTicksRemaining() override {
145 ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); 146 if (parent.uses_wall_clock) {
147 if (!IsInterrupted()) {
148 return minimum_run_cycles;
149 }
150 return 0U;
151 }
146 152
147 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); 153 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
148 } 154 }
@@ -168,11 +174,15 @@ public:
168 parent.jit.load()->HaltExecution(hr); 174 parent.jit.load()->HaltExecution(hr);
169 } 175 }
170 176
177 bool IsInterrupted() {
178 return parent.system.Kernel().PhysicalCore(parent.core_index).IsInterrupted();
179 }
180
171 ARM_Dynarmic_32& parent; 181 ARM_Dynarmic_32& parent;
172 Core::Memory::Memory& memory; 182 Core::Memory::Memory& memory;
173 std::size_t num_interpreted_instructions{}; 183 std::size_t num_interpreted_instructions{};
174 bool debugger_enabled{}; 184 bool debugger_enabled{};
175 static constexpr u64 minimum_run_cycles = 1000U; 185 static constexpr u64 minimum_run_cycles = 10000U;
176}; 186};
177 187
178std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const { 188std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const {
@@ -200,7 +210,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
200 210
201 // Timing 211 // Timing
202 config.wall_clock_cntpct = uses_wall_clock; 212 config.wall_clock_cntpct = uses_wall_clock;
203 config.enable_cycle_counting = !uses_wall_clock; 213 config.enable_cycle_counting = true;
204 214
205 // Code cache size 215 // Code cache size
206 config.code_cache_size = 512_MiB; 216 config.code_cache_size = 512_MiB;
@@ -311,11 +321,9 @@ void ARM_Dynarmic_32::RewindBreakpointInstruction() {
311 LoadContext(breakpoint_context); 321 LoadContext(breakpoint_context);
312} 322}
313 323
314ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, 324ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, bool uses_wall_clock_,
315 bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, 325 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
316 std::size_t core_index_) 326 : ARM_Interface{system_, uses_wall_clock_}, cb(std::make_unique<DynarmicCallbacks32>(*this)),
317 : ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
318 cb(std::make_unique<DynarmicCallbacks32>(*this)),
319 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_}, 327 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_},
320 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)}, 328 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
321 null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {} 329 null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {}
@@ -394,6 +402,10 @@ void ARM_Dynarmic_32::SignalInterrupt() {
394 jit.load()->HaltExecution(break_loop); 402 jit.load()->HaltExecution(break_loop);
395} 403}
396 404
405void ARM_Dynarmic_32::ClearInterrupt() {
406 jit.load()->ClearHalt(break_loop);
407}
408
397void ARM_Dynarmic_32::ClearInstructionCache() { 409void ARM_Dynarmic_32::ClearInstructionCache() {
398 jit.load()->ClearCache(); 410 jit.load()->ClearCache();
399} 411}
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index 346e9abf8..d24ba2289 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -28,8 +28,8 @@ class System;
28 28
29class ARM_Dynarmic_32 final : public ARM_Interface { 29class ARM_Dynarmic_32 final : public ARM_Interface {
30public: 30public:
31 ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_, 31 ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
32 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); 32 std::size_t core_index_);
33 ~ARM_Dynarmic_32() override; 33 ~ARM_Dynarmic_32() override;
34 34
35 void SetPC(u64 pc) override; 35 void SetPC(u64 pc) override;
@@ -56,6 +56,7 @@ public:
56 void LoadContext(const ThreadContext64& ctx) override {} 56 void LoadContext(const ThreadContext64& ctx) override {}
57 57
58 void SignalInterrupt() override; 58 void SignalInterrupt() override;
59 void ClearInterrupt() override;
59 void ClearExclusiveState() override; 60 void ClearExclusiveState() override;
60 61
61 void ClearInstructionCache() override; 62 void ClearInstructionCache() override;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 1a4d37cbc..921a5a734 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -10,7 +10,6 @@
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "common/page_table.h" 11#include "common/page_table.h"
12#include "common/settings.h" 12#include "common/settings.h"
13#include "core/arm/cpu_interrupt_handler.h"
14#include "core/arm/dynarmic/arm_dynarmic_64.h" 13#include "core/arm/dynarmic/arm_dynarmic_64.h"
15#include "core/arm/dynarmic/arm_exclusive_monitor.h" 14#include "core/arm/dynarmic/arm_exclusive_monitor.h"
16#include "core/core.h" 15#include "core/core.h"
@@ -166,7 +165,9 @@ public:
166 } 165 }
167 166
168 void AddTicks(u64 ticks) override { 167 void AddTicks(u64 ticks) override {
169 ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); 168 if (parent.uses_wall_clock) {
169 return;
170 }
170 171
171 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a 172 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
172 // rough approximation of the amount of executed ticks in the system, it may be thrown off 173 // rough approximation of the amount of executed ticks in the system, it may be thrown off
@@ -181,7 +182,12 @@ public:
181 } 182 }
182 183
183 u64 GetTicksRemaining() override { 184 u64 GetTicksRemaining() override {
184 ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); 185 if (parent.uses_wall_clock) {
186 if (!IsInterrupted()) {
187 return minimum_run_cycles;
188 }
189 return 0U;
190 }
185 191
186 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); 192 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
187 } 193 }
@@ -211,12 +217,16 @@ public:
211 parent.jit.load()->HaltExecution(hr); 217 parent.jit.load()->HaltExecution(hr);
212 } 218 }
213 219
220 bool IsInterrupted() {
221 return parent.system.Kernel().PhysicalCore(parent.core_index).IsInterrupted();
222 }
223
214 ARM_Dynarmic_64& parent; 224 ARM_Dynarmic_64& parent;
215 Core::Memory::Memory& memory; 225 Core::Memory::Memory& memory;
216 u64 tpidrro_el0 = 0; 226 u64 tpidrro_el0 = 0;
217 u64 tpidr_el0 = 0; 227 u64 tpidr_el0 = 0;
218 bool debugger_enabled{}; 228 bool debugger_enabled{};
219 static constexpr u64 minimum_run_cycles = 1000U; 229 static constexpr u64 minimum_run_cycles = 10000U;
220}; 230};
221 231
222std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table, 232std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table,
@@ -260,7 +270,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
260 270
261 // Timing 271 // Timing
262 config.wall_clock_cntpct = uses_wall_clock; 272 config.wall_clock_cntpct = uses_wall_clock;
263 config.enable_cycle_counting = !uses_wall_clock; 273 config.enable_cycle_counting = true;
264 274
265 // Code cache size 275 // Code cache size
266 config.code_cache_size = 512_MiB; 276 config.code_cache_size = 512_MiB;
@@ -371,10 +381,9 @@ void ARM_Dynarmic_64::RewindBreakpointInstruction() {
371 LoadContext(breakpoint_context); 381 LoadContext(breakpoint_context);
372} 382}
373 383
374ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, 384ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, bool uses_wall_clock_,
375 bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, 385 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
376 std::size_t core_index_) 386 : ARM_Interface{system_, uses_wall_clock_},
377 : ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
378 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_}, 387 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_},
379 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)}, 388 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
380 null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {} 389 null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {}
@@ -461,6 +470,10 @@ void ARM_Dynarmic_64::SignalInterrupt() {
461 jit.load()->HaltExecution(break_loop); 470 jit.load()->HaltExecution(break_loop);
462} 471}
463 472
473void ARM_Dynarmic_64::ClearInterrupt() {
474 jit.load()->ClearHalt(break_loop);
475}
476
464void ARM_Dynarmic_64::ClearInstructionCache() { 477void ARM_Dynarmic_64::ClearInstructionCache() {
465 jit.load()->ClearCache(); 478 jit.load()->ClearCache();
466} 479}
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index c77a83ad7..ed1a5eb96 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -20,14 +20,13 @@ class Memory;
20namespace Core { 20namespace Core {
21 21
22class DynarmicCallbacks64; 22class DynarmicCallbacks64;
23class CPUInterruptHandler;
24class DynarmicExclusiveMonitor; 23class DynarmicExclusiveMonitor;
25class System; 24class System;
26 25
27class ARM_Dynarmic_64 final : public ARM_Interface { 26class ARM_Dynarmic_64 final : public ARM_Interface {
28public: 27public:
29 ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_, 28 ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
30 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); 29 std::size_t core_index_);
31 ~ARM_Dynarmic_64() override; 30 ~ARM_Dynarmic_64() override;
32 31
33 void SetPC(u64 pc) override; 32 void SetPC(u64 pc) override;
@@ -50,6 +49,7 @@ public:
50 void LoadContext(const ThreadContext64& ctx) override; 49 void LoadContext(const ThreadContext64& ctx) override;
51 50
52 void SignalInterrupt() override; 51 void SignalInterrupt() override;
52 void ClearInterrupt() override;
53 void ClearExclusiveState() override; 53 void ClearExclusiveState() override;
54 54
55 void ClearInstructionCache() override; 55 void ClearInstructionCache() override;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
index e9123c13d..200efe4db 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
@@ -8,6 +8,10 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/core_timing.h" 9#include "core/core_timing.h"
10 10
11#ifdef _MSC_VER
12#include <intrin.h>
13#endif
14
11using Callback = Dynarmic::A32::Coprocessor::Callback; 15using Callback = Dynarmic::A32::Coprocessor::Callback;
12using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord; 16using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord;
13using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords; 17using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords;
@@ -47,12 +51,31 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1
47 switch (opc2) { 51 switch (opc2) {
48 case 4: 52 case 4:
49 // CP15_DATA_SYNC_BARRIER 53 // CP15_DATA_SYNC_BARRIER
50 // This is a dummy write, we ignore the value written here. 54 return Callback{
51 return &dummy_value; 55 [](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t {
56#ifdef _MSC_VER
57 _mm_mfence();
58 _mm_lfence();
59#else
60 asm volatile("mfence\n\tlfence\n\t" : : : "memory");
61#endif
62 return 0;
63 },
64 std::nullopt,
65 };
52 case 5: 66 case 5:
53 // CP15_DATA_MEMORY_BARRIER 67 // CP15_DATA_MEMORY_BARRIER
54 // This is a dummy write, we ignore the value written here. 68 return Callback{
55 return &dummy_value; 69 [](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t {
70#ifdef _MSC_VER
71 _mm_mfence();
72#else
73 asm volatile("mfence\n\t" : : : "memory");
74#endif
75 return 0;
76 },
77 std::nullopt,
78 };
56 } 79 }
57 } 80 }
58 81
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
index 5b2a51636..d90b3e568 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
@@ -35,6 +35,8 @@ public:
35 ARM_Dynarmic_32& parent; 35 ARM_Dynarmic_32& parent;
36 u32 uprw = 0; 36 u32 uprw = 0;
37 u32 uro = 0; 37 u32 uro = 0;
38
39 friend class ARM_Dynarmic_32;
38}; 40};
39 41
40} // namespace Core 42} // namespace Core
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp
index ac64d2f9d..e42bdd17d 100644
--- a/src/core/debugger/debugger.cpp
+++ b/src/core/debugger/debugger.cpp
@@ -15,6 +15,7 @@
15#include "core/debugger/debugger_interface.h" 15#include "core/debugger/debugger_interface.h"
16#include "core/debugger/gdbstub.h" 16#include "core/debugger/gdbstub.h"
17#include "core/hle/kernel/global_scheduler_context.h" 17#include "core/hle/kernel/global_scheduler_context.h"
18#include "core/hle/kernel/k_scheduler.h"
18 19
19template <typename Readable, typename Buffer, typename Callback> 20template <typename Readable, typename Buffer, typename Callback>
20static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) { 21static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) {
@@ -230,13 +231,12 @@ private:
230 } 231 }
231 232
232 void PauseEmulation() { 233 void PauseEmulation() {
234 Kernel::KScopedSchedulerLock sl{system.Kernel()};
235
233 // Put all threads to sleep on next scheduler round. 236 // Put all threads to sleep on next scheduler round.
234 for (auto* thread : ThreadList()) { 237 for (auto* thread : ThreadList()) {
235 thread->RequestSuspend(Kernel::SuspendType::Debug); 238 thread->RequestSuspend(Kernel::SuspendType::Debug);
236 } 239 }
237
238 // Signal an interrupt so that scheduler will fire.
239 system.Kernel().InterruptAllPhysicalCores();
240 } 240 }
241 241
242 void ResumeEmulation(Kernel::KThread* except = nullptr) { 242 void ResumeEmulation(Kernel::KThread* except = nullptr) {
@@ -253,7 +253,8 @@ private:
253 253
254 template <typename Callback> 254 template <typename Callback>
255 void MarkResumed(Callback&& cb) { 255 void MarkResumed(Callback&& cb) {
256 std::scoped_lock lk{connection_lock}; 256 Kernel::KScopedSchedulerLock sl{system.Kernel()};
257 std::scoped_lock cl{connection_lock};
257 stopped = false; 258 stopped = false;
258 cb(); 259 cb();
259 } 260 }
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 8c3895937..049602e7d 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/thread.h"
4#include "core/hid/emulated_controller.h" 5#include "core/hid/emulated_controller.h"
5#include "core/hid/input_converter.h" 6#include "core/hid/input_converter.h"
6 7
@@ -84,18 +85,19 @@ void EmulatedController::ReloadFromSettings() {
84 motion_params[index] = Common::ParamPackage(player.motions[index]); 85 motion_params[index] = Common::ParamPackage(player.motions[index]);
85 } 86 }
86 87
88 controller.colors_state.fullkey = {
89 .body = GetNpadColor(player.body_color_left),
90 .button = GetNpadColor(player.button_color_left),
91 };
87 controller.colors_state.left = { 92 controller.colors_state.left = {
88 .body = player.body_color_left, 93 .body = GetNpadColor(player.body_color_left),
89 .button = player.button_color_left, 94 .button = GetNpadColor(player.button_color_left),
90 }; 95 };
91 96 controller.colors_state.left = {
92 controller.colors_state.right = { 97 .body = GetNpadColor(player.body_color_right),
93 .body = player.body_color_right, 98 .button = GetNpadColor(player.button_color_right),
94 .button = player.button_color_right,
95 }; 99 };
96 100
97 controller.colors_state.fullkey = controller.colors_state.left;
98
99 // Other or debug controller should always be a pro controller 101 // Other or debug controller should always be a pro controller
100 if (npad_id_type != NpadIdType::Other) { 102 if (npad_id_type != NpadIdType::Other) {
101 SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); 103 SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type));
@@ -949,6 +951,9 @@ bool EmulatedController::TestVibration(std::size_t device_index) {
949 // Send a slight vibration to test for rumble support 951 // Send a slight vibration to test for rumble support
950 output_devices[device_index]->SetVibration(test_vibration); 952 output_devices[device_index]->SetVibration(test_vibration);
951 953
954 // Wait for about 15ms to ensure the controller is ready for the stop command
955 std::this_thread::sleep_for(std::chrono::milliseconds(15));
956
952 // Stop any vibration and return the result 957 // Stop any vibration and return the result
953 return output_devices[device_index]->SetVibration(zero_vibration) == 958 return output_devices[device_index]->SetVibration(zero_vibration) ==
954 Common::Input::VibrationError::None; 959 Common::Input::VibrationError::None;
@@ -1310,6 +1315,15 @@ const CameraState& EmulatedController::GetCamera() const {
1310 return controller.camera_state; 1315 return controller.camera_state;
1311} 1316}
1312 1317
1318NpadColor EmulatedController::GetNpadColor(u32 color) {
1319 return {
1320 .r = static_cast<u8>((color >> 16) & 0xFF),
1321 .g = static_cast<u8>((color >> 8) & 0xFF),
1322 .b = static_cast<u8>(color & 0xFF),
1323 .a = 0xff,
1324 };
1325}
1326
1313void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { 1327void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) {
1314 std::scoped_lock lock{callback_mutex}; 1328 std::scoped_lock lock{callback_mutex};
1315 for (const auto& poller_pair : callback_list) { 1329 for (const auto& poller_pair : callback_list) {
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 823c1700c..cbd7c26d3 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -425,6 +425,13 @@ private:
425 void SetCamera(const Common::Input::CallbackStatus& callback); 425 void SetCamera(const Common::Input::CallbackStatus& callback);
426 426
427 /** 427 /**
428 * Converts a color format from bgra to rgba
429 * @param color in bgra format
430 * @return NpadColor in rgba format
431 */
432 NpadColor GetNpadColor(u32 color);
433
434 /**
428 * Triggers a callback that something has changed on the controller status 435 * Triggers a callback that something has changed on the controller status
429 * @param type Input type of the event to trigger 436 * @param type Input type of the event to trigger
430 * @param is_service_update indicates if this event should only be sent to HID services 437 * @param is_service_update indicates if this event should only be sent to HID services
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index e49223016..e3b1cfbc6 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -327,10 +327,18 @@ struct TouchState {
327}; 327};
328static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); 328static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
329 329
330struct NpadColor {
331 u8 r{};
332 u8 g{};
333 u8 b{};
334 u8 a{};
335};
336static_assert(sizeof(NpadColor) == 4, "NpadColor is an invalid size");
337
330// This is nn::hid::NpadControllerColor 338// This is nn::hid::NpadControllerColor
331struct NpadControllerColor { 339struct NpadControllerColor {
332 u32 body{}; 340 NpadColor body{};
333 u32 button{}; 341 NpadColor button{};
334}; 342};
335static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size"); 343static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size");
336 344
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index f4072e1c3..ce7fa8275 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -17,7 +17,6 @@
17#include "common/thread.h" 17#include "common/thread.h"
18#include "common/thread_worker.h" 18#include "common/thread_worker.h"
19#include "core/arm/arm_interface.h" 19#include "core/arm/arm_interface.h"
20#include "core/arm/cpu_interrupt_handler.h"
21#include "core/arm/exclusive_monitor.h" 20#include "core/arm/exclusive_monitor.h"
22#include "core/core.h" 21#include "core/core.h"
23#include "core/core_timing.h" 22#include "core/core_timing.h"
@@ -82,7 +81,7 @@ struct KernelCore::Impl {
82 81
83 void InitializeCores() { 82 void InitializeCores() {
84 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { 83 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
85 cores[core_id].Initialize((*current_process).Is64BitProcess()); 84 cores[core_id]->Initialize((*current_process).Is64BitProcess());
86 system.Memory().SetCurrentPageTable(*current_process, core_id); 85 system.Memory().SetCurrentPageTable(*current_process, core_id);
87 } 86 }
88 } 87 }
@@ -100,7 +99,9 @@ struct KernelCore::Impl {
100 next_user_process_id = KProcess::ProcessIDMin; 99 next_user_process_id = KProcess::ProcessIDMin;
101 next_thread_id = 1; 100 next_thread_id = 1;
102 101
103 cores.clear(); 102 for (auto& core : cores) {
103 core = nullptr;
104 }
104 105
105 global_handle_table->Finalize(); 106 global_handle_table->Finalize();
106 global_handle_table.reset(); 107 global_handle_table.reset();
@@ -199,7 +200,7 @@ struct KernelCore::Impl {
199 const s32 core{static_cast<s32>(i)}; 200 const s32 core{static_cast<s32>(i)};
200 201
201 schedulers[i] = std::make_unique<Kernel::KScheduler>(system.Kernel()); 202 schedulers[i] = std::make_unique<Kernel::KScheduler>(system.Kernel());
202 cores.emplace_back(i, system, *schedulers[i], interrupts); 203 cores[i] = std::make_unique<Kernel::PhysicalCore>(i, system, *schedulers[i]);
203 204
204 auto* main_thread{Kernel::KThread::Create(system.Kernel())}; 205 auto* main_thread{Kernel::KThread::Create(system.Kernel())};
205 main_thread->SetName(fmt::format("MainThread:{}", core)); 206 main_thread->SetName(fmt::format("MainThread:{}", core));
@@ -761,7 +762,7 @@ struct KernelCore::Impl {
761 std::unordered_set<KAutoObject*> registered_in_use_objects; 762 std::unordered_set<KAutoObject*> registered_in_use_objects;
762 763
763 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; 764 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
764 std::vector<Kernel::PhysicalCore> cores; 765 std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores;
765 766
766 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others 767 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
767 std::atomic<u32> next_host_thread_id{Core::Hardware::NUM_CPU_CORES}; 768 std::atomic<u32> next_host_thread_id{Core::Hardware::NUM_CPU_CORES};
@@ -785,7 +786,6 @@ struct KernelCore::Impl {
785 Common::ThreadWorker service_threads_manager; 786 Common::ThreadWorker service_threads_manager;
786 787
787 std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads; 788 std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads;
788 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
789 std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; 789 std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
790 790
791 bool is_multicore{}; 791 bool is_multicore{};
@@ -874,11 +874,11 @@ const Kernel::KScheduler& KernelCore::Scheduler(std::size_t id) const {
874} 874}
875 875
876Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { 876Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) {
877 return impl->cores[id]; 877 return *impl->cores[id];
878} 878}
879 879
880const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const { 880const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
881 return impl->cores[id]; 881 return *impl->cores[id];
882} 882}
883 883
884size_t KernelCore::CurrentPhysicalCoreIndex() const { 884size_t KernelCore::CurrentPhysicalCoreIndex() const {
@@ -890,11 +890,11 @@ size_t KernelCore::CurrentPhysicalCoreIndex() const {
890} 890}
891 891
892Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() { 892Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() {
893 return impl->cores[CurrentPhysicalCoreIndex()]; 893 return *impl->cores[CurrentPhysicalCoreIndex()];
894} 894}
895 895
896const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { 896const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const {
897 return impl->cores[CurrentPhysicalCoreIndex()]; 897 return *impl->cores[CurrentPhysicalCoreIndex()];
898} 898}
899 899
900Kernel::KScheduler* KernelCore::CurrentScheduler() { 900Kernel::KScheduler* KernelCore::CurrentScheduler() {
@@ -906,15 +906,6 @@ Kernel::KScheduler* KernelCore::CurrentScheduler() {
906 return impl->schedulers[core_id].get(); 906 return impl->schedulers[core_id].get();
907} 907}
908 908
909std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts() {
910 return impl->interrupts;
911}
912
913const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts()
914 const {
915 return impl->interrupts;
916}
917
918Kernel::TimeManager& KernelCore::TimeManager() { 909Kernel::TimeManager& KernelCore::TimeManager() {
919 return impl->time_manager; 910 return impl->time_manager;
920} 911}
@@ -939,24 +930,18 @@ const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const {
939 return *impl->global_object_list_container; 930 return *impl->global_object_list_container;
940} 931}
941 932
942void KernelCore::InterruptAllPhysicalCores() {
943 for (auto& physical_core : impl->cores) {
944 physical_core.Interrupt();
945 }
946}
947
948void KernelCore::InvalidateAllInstructionCaches() { 933void KernelCore::InvalidateAllInstructionCaches() {
949 for (auto& physical_core : impl->cores) { 934 for (auto& physical_core : impl->cores) {
950 physical_core.ArmInterface().ClearInstructionCache(); 935 physical_core->ArmInterface().ClearInstructionCache();
951 } 936 }
952} 937}
953 938
954void KernelCore::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) { 939void KernelCore::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) {
955 for (auto& physical_core : impl->cores) { 940 for (auto& physical_core : impl->cores) {
956 if (!physical_core.IsInitialized()) { 941 if (!physical_core->IsInitialized()) {
957 continue; 942 continue;
958 } 943 }
959 physical_core.ArmInterface().InvalidateCacheRange(addr, size); 944 physical_core->ArmInterface().InvalidateCacheRange(addr, size);
960 } 945 }
961} 946}
962 947
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 6c7cf6af2..bcf016a97 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -9,14 +9,12 @@
9#include <string> 9#include <string>
10#include <unordered_map> 10#include <unordered_map>
11#include <vector> 11#include <vector>
12#include "core/arm/cpu_interrupt_handler.h"
13#include "core/hardware_properties.h" 12#include "core/hardware_properties.h"
14#include "core/hle/kernel/k_auto_object.h" 13#include "core/hle/kernel/k_auto_object.h"
15#include "core/hle/kernel/k_slab_heap.h" 14#include "core/hle/kernel/k_slab_heap.h"
16#include "core/hle/kernel/svc_common.h" 15#include "core/hle/kernel/svc_common.h"
17 16
18namespace Core { 17namespace Core {
19class CPUInterruptHandler;
20class ExclusiveMonitor; 18class ExclusiveMonitor;
21class System; 19class System;
22} // namespace Core 20} // namespace Core
@@ -183,12 +181,6 @@ public:
183 181
184 const KAutoObjectWithListContainer& ObjectListContainer() const; 182 const KAutoObjectWithListContainer& ObjectListContainer() const;
185 183
186 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts();
187
188 const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts() const;
189
190 void InterruptAllPhysicalCores();
191
192 void InvalidateAllInstructionCaches(); 184 void InvalidateAllInstructionCaches();
193 185
194 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); 186 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp
index 6e7dacf97..d4375962f 100644
--- a/src/core/hle/kernel/physical_core.cpp
+++ b/src/core/hle/kernel/physical_core.cpp
@@ -1,7 +1,6 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/arm/cpu_interrupt_handler.h"
5#include "core/arm/dynarmic/arm_dynarmic_32.h" 4#include "core/arm/dynarmic/arm_dynarmic_32.h"
6#include "core/arm/dynarmic/arm_dynarmic_64.h" 5#include "core/arm/dynarmic/arm_dynarmic_64.h"
7#include "core/core.h" 6#include "core/core.h"
@@ -11,16 +10,14 @@
11 10
12namespace Kernel { 11namespace Kernel {
13 12
14PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_, 13PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_)
15 Core::CPUInterrupts& interrupts_) 14 : core_index{core_index_}, system{system_}, scheduler{scheduler_} {
16 : core_index{core_index_}, system{system_}, scheduler{scheduler_},
17 interrupts{interrupts_}, guard{std::make_unique<std::mutex>()} {
18#ifdef ARCHITECTURE_x86_64 15#ifdef ARCHITECTURE_x86_64
19 // TODO(bunnei): Initialization relies on a core being available. We may later replace this with 16 // TODO(bunnei): Initialization relies on a core being available. We may later replace this with
20 // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager. 17 // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager.
21 auto& kernel = system.Kernel(); 18 auto& kernel = system.Kernel();
22 arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( 19 arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
23 system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); 20 system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
24#else 21#else
25#error Platform not supported yet. 22#error Platform not supported yet.
26#endif 23#endif
@@ -34,7 +31,7 @@ void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) {
34 if (!is_64_bit) { 31 if (!is_64_bit) {
35 // We already initialized a 64-bit core, replace with a 32-bit one. 32 // We already initialized a 64-bit core, replace with a 32-bit one.
36 arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( 33 arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
37 system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); 34 system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
38 } 35 }
39#else 36#else
40#error Platform not supported yet. 37#error Platform not supported yet.
@@ -47,24 +44,26 @@ void PhysicalCore::Run() {
47} 44}
48 45
49void PhysicalCore::Idle() { 46void PhysicalCore::Idle() {
50 interrupts[core_index].AwaitInterrupt(); 47 std::unique_lock lk{guard};
48 on_interrupt.wait(lk, [this] { return is_interrupted; });
51} 49}
52 50
53bool PhysicalCore::IsInterrupted() const { 51bool PhysicalCore::IsInterrupted() const {
54 return interrupts[core_index].IsInterrupted(); 52 return is_interrupted;
55} 53}
56 54
57void PhysicalCore::Interrupt() { 55void PhysicalCore::Interrupt() {
58 guard->lock(); 56 std::unique_lock lk{guard};
59 interrupts[core_index].SetInterrupt(true); 57 is_interrupted = true;
60 arm_interface->SignalInterrupt(); 58 arm_interface->SignalInterrupt();
61 guard->unlock(); 59 on_interrupt.notify_all();
62} 60}
63 61
64void PhysicalCore::ClearInterrupt() { 62void PhysicalCore::ClearInterrupt() {
65 guard->lock(); 63 std::unique_lock lk{guard};
66 interrupts[core_index].SetInterrupt(false); 64 is_interrupted = false;
67 guard->unlock(); 65 arm_interface->ClearInterrupt();
66 on_interrupt.notify_all();
68} 67}
69 68
70} // namespace Kernel 69} // namespace Kernel
diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h
index 898d1e5db..2fc8d4be2 100644
--- a/src/core/hle/kernel/physical_core.h
+++ b/src/core/hle/kernel/physical_core.h
@@ -14,7 +14,6 @@ class KScheduler;
14} // namespace Kernel 14} // namespace Kernel
15 15
16namespace Core { 16namespace Core {
17class CPUInterruptHandler;
18class ExclusiveMonitor; 17class ExclusiveMonitor;
19class System; 18class System;
20} // namespace Core 19} // namespace Core
@@ -23,15 +22,11 @@ namespace Kernel {
23 22
24class PhysicalCore { 23class PhysicalCore {
25public: 24public:
26 PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_, 25 PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_);
27 Core::CPUInterrupts& interrupts_);
28 ~PhysicalCore(); 26 ~PhysicalCore();
29 27
30 PhysicalCore(const PhysicalCore&) = delete; 28 YUZU_NON_COPYABLE(PhysicalCore);
31 PhysicalCore& operator=(const PhysicalCore&) = delete; 29 YUZU_NON_MOVEABLE(PhysicalCore);
32
33 PhysicalCore(PhysicalCore&&) = default;
34 PhysicalCore& operator=(PhysicalCore&&) = delete;
35 30
36 /// Initialize the core for the specified parameters. 31 /// Initialize the core for the specified parameters.
37 void Initialize(bool is_64_bit); 32 void Initialize(bool is_64_bit);
@@ -86,9 +81,11 @@ private:
86 const std::size_t core_index; 81 const std::size_t core_index;
87 Core::System& system; 82 Core::System& system;
88 Kernel::KScheduler& scheduler; 83 Kernel::KScheduler& scheduler;
89 Core::CPUInterrupts& interrupts; 84
90 std::unique_ptr<std::mutex> guard; 85 std::mutex guard;
86 std::condition_variable on_interrupt;
91 std::unique_ptr<Core::ARM_Interface> arm_interface; 87 std::unique_ptr<Core::ARM_Interface> arm_interface;
88 bool is_interrupted;
92}; 89};
93 90
94} // namespace Kernel 91} // namespace Kernel
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 3c28dee76..cb29004e8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -163,28 +163,51 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
163 } 163 }
164 LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); 164 LOG_DEBUG(Service_HID, "Npad connected {}", npad_id);
165 const auto controller_type = controller.device->GetNpadStyleIndex(); 165 const auto controller_type = controller.device->GetNpadStyleIndex();
166 const auto& body_colors = controller.device->GetColors();
167 const auto& battery_level = controller.device->GetBattery();
166 auto* shared_memory = controller.shared_memory; 168 auto* shared_memory = controller.shared_memory;
167 if (controller_type == Core::HID::NpadStyleIndex::None) { 169 if (controller_type == Core::HID::NpadStyleIndex::None) {
168 controller.styleset_changed_event->GetWritableEvent().Signal(); 170 controller.styleset_changed_event->GetWritableEvent().Signal();
169 return; 171 return;
170 } 172 }
173
174 // Reset memory values
171 shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; 175 shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None;
172 shared_memory->device_type.raw = 0; 176 shared_memory->device_type.raw = 0;
173 shared_memory->system_properties.raw = 0; 177 shared_memory->system_properties.raw = 0;
178 shared_memory->joycon_color.attribute = ColorAttribute::NoController;
179 shared_memory->joycon_color.attribute = ColorAttribute::NoController;
180 shared_memory->fullkey_color = {};
181 shared_memory->joycon_color.left = {};
182 shared_memory->joycon_color.right = {};
183 shared_memory->battery_level_dual = {};
184 shared_memory->battery_level_left = {};
185 shared_memory->battery_level_right = {};
186
174 switch (controller_type) { 187 switch (controller_type) {
175 case Core::HID::NpadStyleIndex::None: 188 case Core::HID::NpadStyleIndex::None:
176 ASSERT(false); 189 ASSERT(false);
177 break; 190 break;
178 case Core::HID::NpadStyleIndex::ProController: 191 case Core::HID::NpadStyleIndex::ProController:
192 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
193 shared_memory->fullkey_color.fullkey = body_colors.fullkey;
194 shared_memory->battery_level_dual = battery_level.dual.battery_level;
179 shared_memory->style_tag.fullkey.Assign(1); 195 shared_memory->style_tag.fullkey.Assign(1);
180 shared_memory->device_type.fullkey.Assign(1); 196 shared_memory->device_type.fullkey.Assign(1);
181 shared_memory->system_properties.is_vertical.Assign(1); 197 shared_memory->system_properties.is_vertical.Assign(1);
182 shared_memory->system_properties.use_plus.Assign(1); 198 shared_memory->system_properties.use_plus.Assign(1);
183 shared_memory->system_properties.use_minus.Assign(1); 199 shared_memory->system_properties.use_minus.Assign(1);
200 shared_memory->system_properties.is_charging_joy_dual.Assign(
201 battery_level.dual.is_charging);
184 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController; 202 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController;
185 shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1); 203 shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1);
186 break; 204 break;
187 case Core::HID::NpadStyleIndex::Handheld: 205 case Core::HID::NpadStyleIndex::Handheld:
206 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
207 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
208 shared_memory->fullkey_color.fullkey = body_colors.fullkey;
209 shared_memory->joycon_color.left = body_colors.left;
210 shared_memory->joycon_color.right = body_colors.right;
188 shared_memory->style_tag.handheld.Assign(1); 211 shared_memory->style_tag.handheld.Assign(1);
189 shared_memory->device_type.handheld_left.Assign(1); 212 shared_memory->device_type.handheld_left.Assign(1);
190 shared_memory->device_type.handheld_right.Assign(1); 213 shared_memory->device_type.handheld_right.Assign(1);
@@ -192,47 +215,86 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
192 shared_memory->system_properties.use_plus.Assign(1); 215 shared_memory->system_properties.use_plus.Assign(1);
193 shared_memory->system_properties.use_minus.Assign(1); 216 shared_memory->system_properties.use_minus.Assign(1);
194 shared_memory->system_properties.use_directional_buttons.Assign(1); 217 shared_memory->system_properties.use_directional_buttons.Assign(1);
218 shared_memory->system_properties.is_charging_joy_dual.Assign(
219 battery_level.left.is_charging);
220 shared_memory->system_properties.is_charging_joy_left.Assign(
221 battery_level.left.is_charging);
222 shared_memory->system_properties.is_charging_joy_right.Assign(
223 battery_level.right.is_charging);
195 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; 224 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
196 shared_memory->applet_nfc_xcd.applet_footer.type = 225 shared_memory->applet_nfc_xcd.applet_footer.type =
197 AppletFooterUiType::HandheldJoyConLeftJoyConRight; 226 AppletFooterUiType::HandheldJoyConLeftJoyConRight;
198 shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1); 227 shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1);
199 break; 228 break;
200 case Core::HID::NpadStyleIndex::JoyconDual: 229 case Core::HID::NpadStyleIndex::JoyconDual:
230 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
231 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
201 shared_memory->style_tag.joycon_dual.Assign(1); 232 shared_memory->style_tag.joycon_dual.Assign(1);
202 if (controller.is_dual_left_connected) { 233 if (controller.is_dual_left_connected) {
234 shared_memory->joycon_color.left = body_colors.left;
235 shared_memory->battery_level_left = battery_level.left.battery_level;
203 shared_memory->device_type.joycon_left.Assign(1); 236 shared_memory->device_type.joycon_left.Assign(1);
204 shared_memory->system_properties.use_minus.Assign(1); 237 shared_memory->system_properties.use_minus.Assign(1);
238 shared_memory->system_properties.is_charging_joy_left.Assign(
239 battery_level.left.is_charging);
205 shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1); 240 shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1);
206 } 241 }
207 if (controller.is_dual_right_connected) { 242 if (controller.is_dual_right_connected) {
243 shared_memory->joycon_color.right = body_colors.right;
244 shared_memory->battery_level_right = battery_level.right.battery_level;
208 shared_memory->device_type.joycon_right.Assign(1); 245 shared_memory->device_type.joycon_right.Assign(1);
209 shared_memory->system_properties.use_plus.Assign(1); 246 shared_memory->system_properties.use_plus.Assign(1);
247 shared_memory->system_properties.is_charging_joy_right.Assign(
248 battery_level.right.is_charging);
210 shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1); 249 shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1);
211 } 250 }
212 shared_memory->system_properties.use_directional_buttons.Assign(1); 251 shared_memory->system_properties.use_directional_buttons.Assign(1);
213 shared_memory->system_properties.is_vertical.Assign(1); 252 shared_memory->system_properties.is_vertical.Assign(1);
214 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; 253 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
254
215 if (controller.is_dual_left_connected && controller.is_dual_right_connected) { 255 if (controller.is_dual_left_connected && controller.is_dual_right_connected) {
216 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual; 256 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual;
257 shared_memory->fullkey_color.fullkey = body_colors.left;
258 shared_memory->battery_level_dual = battery_level.left.battery_level;
259 shared_memory->system_properties.is_charging_joy_dual.Assign(
260 battery_level.left.is_charging);
217 } else if (controller.is_dual_left_connected) { 261 } else if (controller.is_dual_left_connected) {
218 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; 262 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly;
263 shared_memory->fullkey_color.fullkey = body_colors.left;
264 shared_memory->battery_level_dual = battery_level.left.battery_level;
265 shared_memory->system_properties.is_charging_joy_dual.Assign(
266 battery_level.left.is_charging);
219 } else { 267 } else {
220 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; 268 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly;
269 shared_memory->fullkey_color.fullkey = body_colors.right;
270 shared_memory->battery_level_dual = battery_level.right.battery_level;
271 shared_memory->system_properties.is_charging_joy_dual.Assign(
272 battery_level.right.is_charging);
221 } 273 }
222 break; 274 break;
223 case Core::HID::NpadStyleIndex::JoyconLeft: 275 case Core::HID::NpadStyleIndex::JoyconLeft:
276 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
277 shared_memory->joycon_color.left = body_colors.left;
278 shared_memory->battery_level_dual = battery_level.left.battery_level;
224 shared_memory->style_tag.joycon_left.Assign(1); 279 shared_memory->style_tag.joycon_left.Assign(1);
225 shared_memory->device_type.joycon_left.Assign(1); 280 shared_memory->device_type.joycon_left.Assign(1);
226 shared_memory->system_properties.is_horizontal.Assign(1); 281 shared_memory->system_properties.is_horizontal.Assign(1);
227 shared_memory->system_properties.use_minus.Assign(1); 282 shared_memory->system_properties.use_minus.Assign(1);
283 shared_memory->system_properties.is_charging_joy_left.Assign(
284 battery_level.left.is_charging);
228 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; 285 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal;
229 shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1); 286 shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1);
230 break; 287 break;
231 case Core::HID::NpadStyleIndex::JoyconRight: 288 case Core::HID::NpadStyleIndex::JoyconRight:
289 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
290 shared_memory->joycon_color.right = body_colors.right;
291 shared_memory->battery_level_right = battery_level.right.battery_level;
232 shared_memory->style_tag.joycon_right.Assign(1); 292 shared_memory->style_tag.joycon_right.Assign(1);
233 shared_memory->device_type.joycon_right.Assign(1); 293 shared_memory->device_type.joycon_right.Assign(1);
234 shared_memory->system_properties.is_horizontal.Assign(1); 294 shared_memory->system_properties.is_horizontal.Assign(1);
235 shared_memory->system_properties.use_plus.Assign(1); 295 shared_memory->system_properties.use_plus.Assign(1);
296 shared_memory->system_properties.is_charging_joy_right.Assign(
297 battery_level.right.is_charging);
236 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; 298 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal;
237 shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1); 299 shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1);
238 break; 300 break;
@@ -269,21 +331,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
269 break; 331 break;
270 } 332 }
271 333
272 const auto& body_colors = controller.device->GetColors();
273
274 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
275 shared_memory->fullkey_color.fullkey = body_colors.fullkey;
276
277 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
278 shared_memory->joycon_color.left = body_colors.left;
279 shared_memory->joycon_color.right = body_colors.right;
280
281 // TODO: Investigate when we should report all batery types
282 const auto& battery_level = controller.device->GetBattery();
283 shared_memory->battery_level_dual = battery_level.dual.battery_level;
284 shared_memory->battery_level_left = battery_level.left.battery_level;
285 shared_memory->battery_level_right = battery_level.right.battery_level;
286
287 controller.is_connected = true; 334 controller.is_connected = true;
288 controller.device->Connect(); 335 controller.device->Connect();
289 SignalStyleSetChangedEvent(npad_id); 336 SignalStyleSetChangedEvent(npad_id);
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index fa8efd22e..a69ae7725 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -33,9 +33,10 @@ VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats)
33} 33}
34 34
35VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) { 35VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) {
36 // Mailbox doesn't lock the application like fifo (vsync), prefer it 36 // Mailbox (triple buffering) doesn't lock the application like fifo (vsync),
37 // prefer it if vsync option is not selected
37 const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR); 38 const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR);
38 if (found_mailbox != modes.end()) { 39 if (found_mailbox != modes.end() && !Settings::values.use_vsync.GetValue()) {
39 return VK_PRESENT_MODE_MAILBOX_KHR; 40 return VK_PRESENT_MODE_MAILBOX_KHR;
40 } 41 }
41 if (!Settings::values.use_speed_limit.GetValue()) { 42 if (!Settings::values.use_speed_limit.GetValue()) {
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index f6b389ede..50007338f 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -221,6 +221,9 @@ if (ENABLE_QT_TRANSLATION)
221 # Update source TS file if enabled 221 # Update source TS file if enabled
222 if (GENERATE_QT_TRANSLATION) 222 if (GENERATE_QT_TRANSLATION)
223 get_target_property(SRCS yuzu SOURCES) 223 get_target_property(SRCS yuzu SOURCES)
224 # these calls to qt_create_translation also creates a rule to generate en.qm which conflicts with providing english plurals
225 # so we have to set a OUTPUT_LOCATION so that we don't have multiple rules to generate en.qm
226 set_source_files_properties(${YUZU_QT_LANGUAGES}/en.ts PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations")
224 qt_create_translation(QM_FILES 227 qt_create_translation(QM_FILES
225 ${SRCS} 228 ${SRCS}
226 ${UIS} 229 ${UIS}
@@ -229,7 +232,13 @@ if (ENABLE_QT_TRANSLATION)
229 -source-language en_US 232 -source-language en_US
230 -target-language en_US 233 -target-language en_US
231 ) 234 )
232 add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts) 235
236 # Generate plurals into dist/english_plurals/generated_en.ts so it can be used to revise dist/english_plurals/en.ts
237 set(GENERATED_PLURALS_FILE ${PROJECT_SOURCE_DIR}/dist/english_plurals/generated_en.ts)
238 set_source_files_properties(${GENERATED_PLURALS_FILE} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/plurals")
239 qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US)
240
241 add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts ${GENERATED_PLURALS_FILE})
233 endif() 242 endif()
234 243
235 # Find all TS files except en.ts 244 # Find all TS files except en.ts
@@ -239,6 +248,9 @@ if (ENABLE_QT_TRANSLATION)
239 # Compile TS files to QM files 248 # Compile TS files to QM files
240 qt_add_translation(LANGUAGES_QM ${LANGUAGES_TS}) 249 qt_add_translation(LANGUAGES_QM ${LANGUAGES_TS})
241 250
251 # Compile english plurals TS file to en.qm
252 qt_add_translation(LANGUAGES_QM ${PROJECT_SOURCE_DIR}/dist/english_plurals/en.ts)
253
242 # Build a QRC file from the QM file list 254 # Build a QRC file from the QM file list
243 set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc) 255 set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc)
244 file(WRITE ${LANGUAGES_QRC} "<RCC><qresource prefix=\"languages\">\n") 256 file(WRITE ${LANGUAGES_QRC} "<RCC><qresource prefix=\"languages\">\n")
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index ef3bdfb1a..c262d0a2b 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -1089,8 +1089,8 @@ QStringList GRenderWindow::GetUnsupportedGLExtensions() const {
1089 } 1089 }
1090 1090
1091 if (!unsupported_ext.empty()) { 1091 if (!unsupported_ext.empty()) {
1092 LOG_ERROR(Frontend, "GPU does not support all required extensions: {}", 1092 const std::string gl_renderer{reinterpret_cast<const char*>(glGetString(GL_RENDERER))};
1093 glGetString(GL_RENDERER)); 1093 LOG_ERROR(Frontend, "GPU does not support all required extensions: {}", gl_renderer);
1094 } 1094 }
1095 for (const QString& ext : unsupported_ext) { 1095 for (const QString& ext : unsupported_ext) {
1096 LOG_ERROR(Frontend, "Unsupported GL extension: {}", ext.toStdString()); 1096 LOG_ERROR(Frontend, "Unsupported GL extension: {}", ext.toStdString());
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index 96de0b3d1..d6d819364 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -75,7 +75,7 @@
75 <string>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</string> 75 <string>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</string>
76 </property> 76 </property>
77 <property name="text"> 77 <property name="text">
78 <string>Use VSync (OpenGL only)</string> 78 <string>Use VSync</string>
79 </property> 79 </property>
80 </widget> 80 </widget>
81 </item> 81 </item>
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index 2e98ede8e..48f71b53c 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -219,6 +219,7 @@ void ConfigureUi::InitializeLanguageComboBox() {
219 for (const auto& lang : languages) { 219 for (const auto& lang : languages) {
220 if (QString::fromLatin1(lang.id) == QStringLiteral("en")) { 220 if (QString::fromLatin1(lang.id) == QStringLiteral("en")) {
221 ui->language_combobox->addItem(lang.name, QStringLiteral("en")); 221 ui->language_combobox->addItem(lang.name, QStringLiteral("en"));
222 language_files.removeOne(QStringLiteral("en.qm"));
222 continue; 223 continue;
223 } 224 }
224 for (int i = 0; i < language_files.size(); ++i) { 225 for (int i = 0; i < language_files.size(); ++i) {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index dc7b343d9..f82bec3b7 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -3338,7 +3338,8 @@ void GMainWindow::MigrateConfigFiles() {
3338 } 3338 }
3339 const auto origin = config_dir_fs_path / filename; 3339 const auto origin = config_dir_fs_path / filename;
3340 const auto destination = config_dir_fs_path / "custom" / filename; 3340 const auto destination = config_dir_fs_path / "custom" / filename;
3341 LOG_INFO(Frontend, "Migrating config file from {} to {}", origin, destination); 3341 LOG_INFO(Frontend, "Migrating config file from {} to {}", origin.string(),
3342 destination.string());
3342 if (!Common::FS::RenameFile(origin, destination)) { 3343 if (!Common::FS::RenameFile(origin, destination)) {
3343 // Delete the old config file if one already exists in the new location. 3344 // Delete the old config file if one already exists in the new location.
3344 Common::FS::RemoveFile(origin); 3345 Common::FS::RemoveFile(origin);
@@ -3979,11 +3980,6 @@ void GMainWindow::UpdateUITheme() {
3979} 3980}
3980 3981
3981void GMainWindow::LoadTranslation() { 3982void GMainWindow::LoadTranslation() {
3982 // If the selected language is English, no need to install any translation
3983 if (UISettings::values.language == QStringLiteral("en")) {
3984 return;
3985 }
3986
3987 bool loaded; 3983 bool loaded;
3988 3984
3989 if (UISettings::values.language.isEmpty()) { 3985 if (UISettings::values.language.isEmpty()) {
@@ -4071,6 +4067,15 @@ int main(int argc, char* argv[]) {
4071 QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); 4067 QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
4072 QApplication app(argc, argv); 4068 QApplication app(argc, argv);
4073 4069
4070 // Workaround for QTBUG-85409, for Suzhou numerals the number 1 is actually \u3021
4071 // so we can see if we get \u3008 instead
4072 // TL;DR all other number formats are consecutive in unicode code points
4073 // This bug is fixed in Qt6, specifically 6.0.0-alpha1
4074 const QLocale locale = QLocale::system();
4075 if (QStringLiteral("\u3008") == locale.toString(1)) {
4076 QLocale::setDefault(QLocale::system().name());
4077 }
4078
4074 // Qt changes the locale and causes issues in float conversion using std::to_string() when 4079 // Qt changes the locale and causes issues in float conversion using std::to_string() when
4075 // generating shaders 4080 // generating shaders
4076 setlocale(LC_ALL, "C"); 4081 setlocale(LC_ALL, "C");