diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/arm/arm_interface.cpp | 97 | ||||
| -rw-r--r-- | src/core/arm/arm_interface.h | 18 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.cpp | 19 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.h | 8 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 38 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.h | 8 | ||||
| -rw-r--r-- | src/input_common/helpers/udp_protocol.h | 9 | ||||
| -rw-r--r-- | src/video_core/renderer_base.cpp | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_base.h | 3 | ||||
| -rw-r--r-- | src/yuzu/aboutdialog.ui | 2 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 6 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input_player.cpp | 20 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 40 | ||||
| -rw-r--r-- | src/yuzu/main.h | 3 |
14 files changed, 181 insertions, 94 deletions
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 08bf1201d..2a9390e26 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp | |||
| @@ -14,96 +14,28 @@ | |||
| 14 | #include "core/loader/loader.h" | 14 | #include "core/loader/loader.h" |
| 15 | #include "core/memory.h" | 15 | #include "core/memory.h" |
| 16 | 16 | ||
| 17 | #include "core/arm/dynarmic/arm_dynarmic_32.h" | ||
| 18 | #include "core/arm/dynarmic/arm_dynarmic_64.h" | ||
| 19 | |||
| 17 | namespace Core { | 20 | namespace Core { |
| 18 | 21 | ||
| 19 | constexpr u64 SEGMENT_BASE = 0x7100000000ull; | 22 | constexpr u64 SEGMENT_BASE = 0x7100000000ull; |
| 20 | 23 | ||
| 21 | std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext( | 24 | std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext( |
| 22 | System& system, const ThreadContext64& ctx) { | 25 | Core::System& system, const ARM_Interface::ThreadContext32& ctx) { |
| 23 | std::vector<BacktraceEntry> out; | 26 | return ARM_Dynarmic_32::GetBacktraceFromContext(system, ctx); |
| 24 | auto& memory = system.Memory(); | ||
| 25 | |||
| 26 | auto fp = ctx.cpu_registers[29]; | ||
| 27 | auto lr = ctx.cpu_registers[30]; | ||
| 28 | while (true) { | ||
| 29 | out.push_back({ | ||
| 30 | .module = "", | ||
| 31 | .address = 0, | ||
| 32 | .original_address = lr, | ||
| 33 | .offset = 0, | ||
| 34 | .name = {}, | ||
| 35 | }); | ||
| 36 | |||
| 37 | if (fp == 0) { | ||
| 38 | break; | ||
| 39 | } | ||
| 40 | |||
| 41 | lr = memory.Read64(fp + 8) - 4; | ||
| 42 | fp = memory.Read64(fp); | ||
| 43 | } | ||
| 44 | |||
| 45 | std::map<VAddr, std::string> modules; | ||
| 46 | auto& loader{system.GetAppLoader()}; | ||
| 47 | if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { | ||
| 48 | return {}; | ||
| 49 | } | ||
| 50 | |||
| 51 | std::map<std::string, Symbols::Symbols> symbols; | ||
| 52 | for (const auto& module : modules) { | ||
| 53 | symbols.insert_or_assign(module.second, | ||
| 54 | Symbols::GetSymbols(module.first, system.Memory(), | ||
| 55 | system.CurrentProcess()->Is64BitProcess())); | ||
| 56 | } | ||
| 57 | |||
| 58 | for (auto& entry : out) { | ||
| 59 | VAddr base = 0; | ||
| 60 | for (auto iter = modules.rbegin(); iter != modules.rend(); ++iter) { | ||
| 61 | const auto& module{*iter}; | ||
| 62 | if (entry.original_address >= module.first) { | ||
| 63 | entry.module = module.second; | ||
| 64 | base = module.first; | ||
| 65 | break; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | entry.offset = entry.original_address - base; | ||
| 70 | entry.address = SEGMENT_BASE + entry.offset; | ||
| 71 | |||
| 72 | if (entry.module.empty()) | ||
| 73 | entry.module = "unknown"; | ||
| 74 | |||
| 75 | const auto symbol_set = symbols.find(entry.module); | ||
| 76 | if (symbol_set != symbols.end()) { | ||
| 77 | const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset); | ||
| 78 | if (symbol.has_value()) { | ||
| 79 | // TODO(DarkLordZach): Add demangling of symbol names. | ||
| 80 | entry.name = *symbol; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | return out; | ||
| 86 | } | 27 | } |
| 87 | 28 | ||
| 88 | std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const { | 29 | std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext( |
| 89 | std::vector<BacktraceEntry> out; | 30 | Core::System& system, const ARM_Interface::ThreadContext64& ctx) { |
| 90 | auto& memory = system.Memory(); | 31 | return ARM_Dynarmic_64::GetBacktraceFromContext(system, ctx); |
| 91 | 32 | } | |
| 92 | auto fp = GetReg(29); | ||
| 93 | auto lr = GetReg(30); | ||
| 94 | while (true) { | ||
| 95 | out.push_back({"", 0, lr, 0, ""}); | ||
| 96 | if (!fp) { | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | lr = memory.Read64(fp + 8) - 4; | ||
| 100 | fp = memory.Read64(fp); | ||
| 101 | } | ||
| 102 | 33 | ||
| 34 | void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out) { | ||
| 103 | std::map<VAddr, std::string> modules; | 35 | std::map<VAddr, std::string> modules; |
| 104 | auto& loader{system.GetAppLoader()}; | 36 | auto& loader{system.GetAppLoader()}; |
| 105 | if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { | 37 | if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { |
| 106 | return {}; | 38 | return; |
| 107 | } | 39 | } |
| 108 | 40 | ||
| 109 | std::map<std::string, Symbols::Symbols> symbols; | 41 | std::map<std::string, Symbols::Symbols> symbols; |
| @@ -127,8 +59,9 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const { | |||
| 127 | entry.offset = entry.original_address - base; | 59 | entry.offset = entry.original_address - base; |
| 128 | entry.address = SEGMENT_BASE + entry.offset; | 60 | entry.address = SEGMENT_BASE + entry.offset; |
| 129 | 61 | ||
| 130 | if (entry.module.empty()) | 62 | if (entry.module.empty()) { |
| 131 | entry.module = "unknown"; | 63 | entry.module = "unknown"; |
| 64 | } | ||
| 132 | 65 | ||
| 133 | const auto symbol_set = symbols.find(entry.module); | 66 | const auto symbol_set = symbols.find(entry.module); |
| 134 | if (symbol_set != symbols.end()) { | 67 | if (symbol_set != symbols.end()) { |
| @@ -139,12 +72,10 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const { | |||
| 139 | } | 72 | } |
| 140 | } | 73 | } |
| 141 | } | 74 | } |
| 142 | |||
| 143 | return out; | ||
| 144 | } | 75 | } |
| 145 | 76 | ||
| 146 | void ARM_Interface::LogBacktrace() const { | 77 | void ARM_Interface::LogBacktrace() const { |
| 147 | const VAddr sp = GetReg(13); | 78 | const VAddr sp = GetSP(); |
| 148 | const VAddr pc = GetPC(); | 79 | const VAddr pc = GetPC(); |
| 149 | LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", sp, pc); | 80 | LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", sp, pc); |
| 150 | LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address", | 81 | LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address", |
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index dce2f4195..bcec4b3b8 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -101,6 +101,12 @@ public: | |||
| 101 | virtual u64 GetPC() const = 0; | 101 | virtual u64 GetPC() const = 0; |
| 102 | 102 | ||
| 103 | /** | 103 | /** |
| 104 | * Get the current Stack Pointer | ||
| 105 | * @return Returns current SP | ||
| 106 | */ | ||
| 107 | virtual u64 GetSP() const = 0; | ||
| 108 | |||
| 109 | /** | ||
| 104 | * Get an ARM register | 110 | * Get an ARM register |
| 105 | * @param index Register index | 111 | * @param index Register index |
| 106 | * @return Returns the value in the register | 112 | * @return Returns the value in the register |
| @@ -183,16 +189,12 @@ public: | |||
| 183 | }; | 189 | }; |
| 184 | 190 | ||
| 185 | static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, | 191 | static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, |
| 192 | const ThreadContext32& ctx); | ||
| 193 | static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, | ||
| 186 | const ThreadContext64& ctx); | 194 | const ThreadContext64& ctx); |
| 187 | 195 | ||
| 188 | std::vector<BacktraceEntry> GetBacktrace() const; | 196 | virtual std::vector<BacktraceEntry> GetBacktrace() const = 0; |
| 189 | 197 | ||
| 190 | /// fp (= r29) points to the last frame record. | ||
| 191 | /// Note that this is the frame record for the *previous* frame, not the current one. | ||
| 192 | /// Note we need to subtract 4 from our last read to get the proper address | ||
| 193 | /// Frame records are two words long: | ||
| 194 | /// fp+0 : pointer to previous frame record | ||
| 195 | /// fp+8 : value of lr for frame | ||
| 196 | void LogBacktrace() const; | 198 | void LogBacktrace() const; |
| 197 | 199 | ||
| 198 | protected: | 200 | protected: |
| @@ -200,6 +202,8 @@ protected: | |||
| 200 | System& system; | 202 | System& system; |
| 201 | CPUInterrupts& interrupt_handlers; | 203 | CPUInterrupts& interrupt_handlers; |
| 202 | bool uses_wall_clock; | 204 | bool uses_wall_clock; |
| 205 | |||
| 206 | static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out); | ||
| 203 | }; | 207 | }; |
| 204 | 208 | ||
| 205 | } // namespace Core | 209 | } // namespace Core |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 5de4384db..da5659046 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -268,6 +268,10 @@ u64 ARM_Dynarmic_32::GetPC() const { | |||
| 268 | return jit.load()->Regs()[15]; | 268 | return jit.load()->Regs()[15]; |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | u64 ARM_Dynarmic_32::GetSP() const { | ||
| 272 | return jit.load()->Regs()[13]; | ||
| 273 | } | ||
| 274 | |||
| 271 | u64 ARM_Dynarmic_32::GetReg(int index) const { | 275 | u64 ARM_Dynarmic_32::GetReg(int index) const { |
| 272 | return jit.load()->Regs()[index]; | 276 | return jit.load()->Regs()[index]; |
| 273 | } | 277 | } |
| @@ -362,4 +366,19 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table, | |||
| 362 | jit_cache.emplace(key, std::move(new_jit)); | 366 | jit_cache.emplace(key, std::move(new_jit)); |
| 363 | } | 367 | } |
| 364 | 368 | ||
| 369 | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system, | ||
| 370 | u64 sp, u64 lr) { | ||
| 371 | // No way to get accurate stack traces in A32 yet | ||
| 372 | return {}; | ||
| 373 | } | ||
| 374 | |||
| 375 | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktraceFromContext( | ||
| 376 | System& system, const ThreadContext32& ctx) { | ||
| 377 | return GetBacktrace(system, ctx.cpu_registers[13], ctx.cpu_registers[14]); | ||
| 378 | } | ||
| 379 | |||
| 380 | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace() const { | ||
| 381 | return GetBacktrace(system, GetReg(13), GetReg(14)); | ||
| 382 | } | ||
| 383 | |||
| 365 | } // namespace Core | 384 | } // namespace Core |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 684937353..1b628f94d 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h | |||
| @@ -35,6 +35,7 @@ public: | |||
| 35 | 35 | ||
| 36 | void SetPC(u64 pc) override; | 36 | void SetPC(u64 pc) override; |
| 37 | u64 GetPC() const override; | 37 | u64 GetPC() const override; |
| 38 | u64 GetSP() const override; | ||
| 38 | u64 GetReg(int index) const override; | 39 | u64 GetReg(int index) const override; |
| 39 | void SetReg(int index, u64 value) override; | 40 | void SetReg(int index, u64 value) override; |
| 40 | u128 GetVectorReg(int index) const override; | 41 | u128 GetVectorReg(int index) const override; |
| @@ -66,9 +67,16 @@ public: | |||
| 66 | void PageTableChanged(Common::PageTable& new_page_table, | 67 | void PageTableChanged(Common::PageTable& new_page_table, |
| 67 | std::size_t new_address_space_size_in_bits) override; | 68 | std::size_t new_address_space_size_in_bits) override; |
| 68 | 69 | ||
| 70 | static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, | ||
| 71 | const ThreadContext32& ctx); | ||
| 72 | |||
| 73 | std::vector<BacktraceEntry> GetBacktrace() const override; | ||
| 74 | |||
| 69 | private: | 75 | private: |
| 70 | std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; | 76 | std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; |
| 71 | 77 | ||
| 78 | static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 sp, u64 lr); | ||
| 79 | |||
| 72 | using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; | 80 | using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; |
| 73 | using JitCacheType = | 81 | using JitCacheType = |
| 74 | std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A32::Jit>, Common::PairHash>; | 82 | std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A32::Jit>, Common::PairHash>; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index ae0b158c2..871d9d10e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -328,6 +328,10 @@ u64 ARM_Dynarmic_64::GetPC() const { | |||
| 328 | return jit.load()->GetPC(); | 328 | return jit.load()->GetPC(); |
| 329 | } | 329 | } |
| 330 | 330 | ||
| 331 | u64 ARM_Dynarmic_64::GetSP() const { | ||
| 332 | return jit.load()->GetSP(); | ||
| 333 | } | ||
| 334 | |||
| 331 | u64 ARM_Dynarmic_64::GetReg(int index) const { | 335 | u64 ARM_Dynarmic_64::GetReg(int index) const { |
| 332 | return jit.load()->GetRegister(index); | 336 | return jit.load()->GetRegister(index); |
| 333 | } | 337 | } |
| @@ -430,4 +434,38 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table, | |||
| 430 | jit_cache.emplace(key, std::move(new_jit)); | 434 | jit_cache.emplace(key, std::move(new_jit)); |
| 431 | } | 435 | } |
| 432 | 436 | ||
| 437 | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::System& system, | ||
| 438 | u64 fp, u64 lr) { | ||
| 439 | std::vector<BacktraceEntry> out; | ||
| 440 | auto& memory = system.Memory(); | ||
| 441 | |||
| 442 | // fp (= r29) points to the last frame record. | ||
| 443 | // Note that this is the frame record for the *previous* frame, not the current one. | ||
| 444 | // Note we need to subtract 4 from our last read to get the proper address | ||
| 445 | // Frame records are two words long: | ||
| 446 | // fp+0 : pointer to previous frame record | ||
| 447 | // fp+8 : value of lr for frame | ||
| 448 | while (true) { | ||
| 449 | out.push_back({"", 0, lr, 0, ""}); | ||
| 450 | if (!fp) { | ||
| 451 | break; | ||
| 452 | } | ||
| 453 | lr = memory.Read64(fp + 8) - 4; | ||
| 454 | fp = memory.Read64(fp); | ||
| 455 | } | ||
| 456 | |||
| 457 | SymbolicateBacktrace(system, out); | ||
| 458 | |||
| 459 | return out; | ||
| 460 | } | ||
| 461 | |||
| 462 | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktraceFromContext( | ||
| 463 | System& system, const ThreadContext64& ctx) { | ||
| 464 | return GetBacktrace(system, ctx.cpu_registers[29], ctx.cpu_registers[30]); | ||
| 465 | } | ||
| 466 | |||
| 467 | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace() const { | ||
| 468 | return GetBacktrace(system, GetReg(29), GetReg(30)); | ||
| 469 | } | ||
| 470 | |||
| 433 | } // namespace Core | 471 | } // namespace Core |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 86018f196..78773e293 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h | |||
| @@ -33,6 +33,7 @@ public: | |||
| 33 | 33 | ||
| 34 | void SetPC(u64 pc) override; | 34 | void SetPC(u64 pc) override; |
| 35 | u64 GetPC() const override; | 35 | u64 GetPC() const override; |
| 36 | u64 GetSP() const override; | ||
| 36 | u64 GetReg(int index) const override; | 37 | u64 GetReg(int index) const override; |
| 37 | void SetReg(int index, u64 value) override; | 38 | void SetReg(int index, u64 value) override; |
| 38 | u128 GetVectorReg(int index) const override; | 39 | u128 GetVectorReg(int index) const override; |
| @@ -60,10 +61,17 @@ public: | |||
| 60 | void PageTableChanged(Common::PageTable& new_page_table, | 61 | void PageTableChanged(Common::PageTable& new_page_table, |
| 61 | std::size_t new_address_space_size_in_bits) override; | 62 | std::size_t new_address_space_size_in_bits) override; |
| 62 | 63 | ||
| 64 | static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, | ||
| 65 | const ThreadContext64& ctx); | ||
| 66 | |||
| 67 | std::vector<BacktraceEntry> GetBacktrace() const override; | ||
| 68 | |||
| 63 | private: | 69 | private: |
| 64 | std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, | 70 | std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, |
| 65 | std::size_t address_space_bits) const; | 71 | std::size_t address_space_bits) const; |
| 66 | 72 | ||
| 73 | static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr); | ||
| 74 | |||
| 67 | using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; | 75 | using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; |
| 68 | using JitCacheType = | 76 | using JitCacheType = |
| 69 | std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A64::Jit>, Common::PairHash>; | 77 | std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A64::Jit>, Common::PairHash>; |
diff --git a/src/input_common/helpers/udp_protocol.h b/src/input_common/helpers/udp_protocol.h index 9c205e944..597f51cd3 100644 --- a/src/input_common/helpers/udp_protocol.h +++ b/src/input_common/helpers/udp_protocol.h | |||
| @@ -8,8 +8,17 @@ | |||
| 8 | #include <optional> | 8 | #include <optional> |
| 9 | #include <type_traits> | 9 | #include <type_traits> |
| 10 | 10 | ||
| 11 | #ifdef _MSC_VER | ||
| 12 | #pragma warning(push) | ||
| 13 | #pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used | ||
| 14 | #endif | ||
| 15 | |||
| 11 | #include <boost/crc.hpp> | 16 | #include <boost/crc.hpp> |
| 12 | 17 | ||
| 18 | #ifdef _MSC_VER | ||
| 19 | #pragma warning(pop) | ||
| 20 | #endif | ||
| 21 | |||
| 13 | #include "common/swap.h" | 22 | #include "common/swap.h" |
| 14 | 23 | ||
| 15 | namespace InputCommon::CemuhookUDP { | 24 | namespace InputCommon::CemuhookUDP { |
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp index c9627cffd..9756a81d6 100644 --- a/src/video_core/renderer_base.cpp +++ b/src/video_core/renderer_base.cpp | |||
| @@ -26,6 +26,10 @@ void RendererBase::UpdateCurrentFramebufferLayout() { | |||
| 26 | render_window.UpdateCurrentFramebufferLayout(layout.width, layout.height); | 26 | render_window.UpdateCurrentFramebufferLayout(layout.width, layout.height); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | bool RendererBase::IsScreenshotPending() const { | ||
| 30 | return renderer_settings.screenshot_requested; | ||
| 31 | } | ||
| 32 | |||
| 29 | void RendererBase::RequestScreenshot(void* data, std::function<void(bool)> callback, | 33 | void RendererBase::RequestScreenshot(void* data, std::function<void(bool)> callback, |
| 30 | const Layout::FramebufferLayout& layout) { | 34 | const Layout::FramebufferLayout& layout) { |
| 31 | if (renderer_settings.screenshot_requested) { | 35 | if (renderer_settings.screenshot_requested) { |
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index c5f974080..30d19b178 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h | |||
| @@ -83,6 +83,9 @@ public: | |||
| 83 | /// Refreshes the settings common to all renderers | 83 | /// Refreshes the settings common to all renderers |
| 84 | void RefreshBaseSettings(); | 84 | void RefreshBaseSettings(); |
| 85 | 85 | ||
| 86 | /// Returns true if a screenshot is being processed | ||
| 87 | bool IsScreenshotPending() const; | ||
| 88 | |||
| 86 | /// Request a screenshot of the next frame | 89 | /// Request a screenshot of the next frame |
| 87 | void RequestScreenshot(void* data, std::function<void(bool)> callback, | 90 | void RequestScreenshot(void* data, std::function<void(bool)> callback, |
| 88 | const Layout::FramebufferLayout& layout); | 91 | const Layout::FramebufferLayout& layout); |
diff --git a/src/yuzu/aboutdialog.ui b/src/yuzu/aboutdialog.ui index 27d81cd13..2f7ddc7f3 100644 --- a/src/yuzu/aboutdialog.ui +++ b/src/yuzu/aboutdialog.ui | |||
| @@ -87,7 +87,7 @@ | |||
| 87 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> | 87 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> |
| 88 | p, li { white-space: pre-wrap; } | 88 | p, li { white-space: pre-wrap; } |
| 89 | </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> | 89 | </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> |
| 90 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv2.0.</span></p> | 90 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv3.0+.</span></p> |
| 91 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p> | 91 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p> |
| 92 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">This software should not be used to play games you have not legally obtained.</span></p></body></html></string> | 92 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">This software should not be used to play games you have not legally obtained.</span></p></body></html></string> |
| 93 | </property> | 93 | </property> |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 27b0300d2..a1b819ae0 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -933,6 +933,12 @@ void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) { | |||
| 933 | auto& renderer = system.Renderer(); | 933 | auto& renderer = system.Renderer(); |
| 934 | const f32 res_scale = Settings::values.resolution_info.up_factor; | 934 | const f32 res_scale = Settings::values.resolution_info.up_factor; |
| 935 | 935 | ||
| 936 | if (renderer.IsScreenshotPending()) { | ||
| 937 | LOG_WARNING(Render, | ||
| 938 | "A screenshot is already requested or in progress, ignoring the request"); | ||
| 939 | return; | ||
| 940 | } | ||
| 941 | |||
| 936 | const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)}; | 942 | const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)}; |
| 937 | screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); | 943 | screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); |
| 938 | renderer.RequestScreenshot( | 944 | renderer.RequestScreenshot( |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 291e37acf..a0f29d147 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <QMenu> | 10 | #include <QMenu> |
| 11 | #include <QMessageBox> | 11 | #include <QMessageBox> |
| 12 | #include <QTimer> | 12 | #include <QTimer> |
| 13 | #include "common/assert.h" | ||
| 13 | #include "common/param_package.h" | 14 | #include "common/param_package.h" |
| 14 | #include "core/hid/emulated_controller.h" | 15 | #include "core/hid/emulated_controller.h" |
| 15 | #include "core/hid/hid_core.h" | 16 | #include "core/hid/hid_core.h" |
| @@ -119,6 +120,23 @@ QString GetButtonName(Common::Input::ButtonNames button_name) { | |||
| 119 | } | 120 | } |
| 120 | } | 121 | } |
| 121 | 122 | ||
| 123 | QString GetDirectionName(const std::string& direction) { | ||
| 124 | if (direction == "left") { | ||
| 125 | return QObject::tr("Left"); | ||
| 126 | } | ||
| 127 | if (direction == "right") { | ||
| 128 | return QObject::tr("Right"); | ||
| 129 | } | ||
| 130 | if (direction == "up") { | ||
| 131 | return QObject::tr("Up"); | ||
| 132 | } | ||
| 133 | if (direction == "down") { | ||
| 134 | return QObject::tr("Down"); | ||
| 135 | } | ||
| 136 | UNIMPLEMENTED_MSG("Unimplemented direction name={}", direction); | ||
| 137 | return QString::fromStdString(direction); | ||
| 138 | } | ||
| 139 | |||
| 122 | void SetAnalogParam(const Common::ParamPackage& input_param, Common::ParamPackage& analog_param, | 140 | void SetAnalogParam(const Common::ParamPackage& input_param, Common::ParamPackage& analog_param, |
| 123 | const std::string& button_name) { | 141 | const std::string& button_name) { |
| 124 | // The poller returned a complete axis, so set all the buttons | 142 | // The poller returned a complete axis, so set all the buttons |
| @@ -162,7 +180,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) { | |||
| 162 | 180 | ||
| 163 | if (common_button_name == Common::Input::ButtonNames::Value) { | 181 | if (common_button_name == Common::Input::ButtonNames::Value) { |
| 164 | if (param.Has("hat")) { | 182 | if (param.Has("hat")) { |
| 165 | const QString hat = QString::fromStdString(param.Get("direction", "")); | 183 | const QString hat = GetDirectionName(param.Get("direction", "")); |
| 166 | return QObject::tr("%1%2Hat %3").arg(toggle, inverted, hat); | 184 | return QObject::tr("%1%2Hat %3").arg(toggle, inverted, hat); |
| 167 | } | 185 | } |
| 168 | if (param.Has("axis")) { | 186 | if (param.Has("axis")) { |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 52879a989..5e26aad29 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -152,7 +152,8 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; | |||
| 152 | } | 152 | } |
| 153 | #endif | 153 | #endif |
| 154 | 154 | ||
| 155 | constexpr int default_mouse_timeout = 2500; | 155 | constexpr int default_mouse_hide_timeout = 2500; |
| 156 | constexpr int default_mouse_center_timeout = 10; | ||
| 156 | 157 | ||
| 157 | /** | 158 | /** |
| 158 | * "Callouts" are one-time instructional messages shown to the user. In the config settings, there | 159 | * "Callouts" are one-time instructional messages shown to the user. In the config settings, there |
| @@ -287,10 +288,13 @@ GMainWindow::GMainWindow() | |||
| 287 | ui->menubar->setCursor(QCursor()); | 288 | ui->menubar->setCursor(QCursor()); |
| 288 | statusBar()->setCursor(QCursor()); | 289 | statusBar()->setCursor(QCursor()); |
| 289 | 290 | ||
| 290 | mouse_hide_timer.setInterval(default_mouse_timeout); | 291 | mouse_hide_timer.setInterval(default_mouse_hide_timeout); |
| 291 | connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor); | 292 | connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor); |
| 292 | connect(ui->menubar, &QMenuBar::hovered, this, &GMainWindow::ShowMouseCursor); | 293 | connect(ui->menubar, &QMenuBar::hovered, this, &GMainWindow::ShowMouseCursor); |
| 293 | 294 | ||
| 295 | mouse_center_timer.setInterval(default_mouse_center_timeout); | ||
| 296 | connect(&mouse_center_timer, &QTimer::timeout, this, &GMainWindow::CenterMouseCursor); | ||
| 297 | |||
| 294 | MigrateConfigFiles(); | 298 | MigrateConfigFiles(); |
| 295 | 299 | ||
| 296 | #if defined(HAVE_SDL2) && !defined(_WIN32) | 300 | #if defined(HAVE_SDL2) && !defined(_WIN32) |
| @@ -3301,10 +3305,26 @@ void GMainWindow::ShowMouseCursor() { | |||
| 3301 | } | 3305 | } |
| 3302 | } | 3306 | } |
| 3303 | 3307 | ||
| 3308 | void GMainWindow::CenterMouseCursor() { | ||
| 3309 | if (emu_thread == nullptr || !Settings::values.mouse_panning) { | ||
| 3310 | mouse_center_timer.stop(); | ||
| 3311 | return; | ||
| 3312 | } | ||
| 3313 | if (!this->isActiveWindow()) { | ||
| 3314 | mouse_center_timer.stop(); | ||
| 3315 | return; | ||
| 3316 | } | ||
| 3317 | const int center_x = render_window->width() / 2; | ||
| 3318 | const int center_y = render_window->height() / 2; | ||
| 3319 | |||
| 3320 | QCursor::setPos(mapToGlobal({center_x, center_y})); | ||
| 3321 | } | ||
| 3322 | |||
| 3304 | void GMainWindow::OnMouseActivity() { | 3323 | void GMainWindow::OnMouseActivity() { |
| 3305 | if (!Settings::values.mouse_panning) { | 3324 | if (!Settings::values.mouse_panning) { |
| 3306 | ShowMouseCursor(); | 3325 | ShowMouseCursor(); |
| 3307 | } | 3326 | } |
| 3327 | mouse_center_timer.stop(); | ||
| 3308 | } | 3328 | } |
| 3309 | 3329 | ||
| 3310 | void GMainWindow::OnCoreError(Core::SystemResultStatus result, std::string details) { | 3330 | void GMainWindow::OnCoreError(Core::SystemResultStatus result, std::string details) { |
| @@ -3577,6 +3597,22 @@ void GMainWindow::dragMoveEvent(QDragMoveEvent* event) { | |||
| 3577 | AcceptDropEvent(event); | 3597 | AcceptDropEvent(event); |
| 3578 | } | 3598 | } |
| 3579 | 3599 | ||
| 3600 | void GMainWindow::leaveEvent(QEvent* event) { | ||
| 3601 | if (Settings::values.mouse_panning) { | ||
| 3602 | const QRect& rect = geometry(); | ||
| 3603 | QPoint position = QCursor::pos(); | ||
| 3604 | |||
| 3605 | qint32 x = qBound(rect.left(), position.x(), rect.right()); | ||
| 3606 | qint32 y = qBound(rect.top(), position.y(), rect.bottom()); | ||
| 3607 | // Only start the timer if the mouse has left the window bound. | ||
| 3608 | // The leave event is also triggered when the window looses focus. | ||
| 3609 | if (x != position.x() || y != position.y()) { | ||
| 3610 | mouse_center_timer.start(); | ||
| 3611 | } | ||
| 3612 | event->accept(); | ||
| 3613 | } | ||
| 3614 | } | ||
| 3615 | |||
| 3580 | bool GMainWindow::ConfirmChangeGame() { | 3616 | bool GMainWindow::ConfirmChangeGame() { |
| 3581 | if (emu_thread == nullptr) | 3617 | if (emu_thread == nullptr) |
| 3582 | return true; | 3618 | return true; |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index ab95a7518..b399e9b01 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -328,6 +328,7 @@ private: | |||
| 328 | void UpdateUISettings(); | 328 | void UpdateUISettings(); |
| 329 | void HideMouseCursor(); | 329 | void HideMouseCursor(); |
| 330 | void ShowMouseCursor(); | 330 | void ShowMouseCursor(); |
| 331 | void CenterMouseCursor(); | ||
| 331 | void OpenURL(const QUrl& url); | 332 | void OpenURL(const QUrl& url); |
| 332 | void LoadTranslation(); | 333 | void LoadTranslation(); |
| 333 | void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); | 334 | void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); |
| @@ -372,6 +373,7 @@ private: | |||
| 372 | bool auto_paused = false; | 373 | bool auto_paused = false; |
| 373 | bool auto_muted = false; | 374 | bool auto_muted = false; |
| 374 | QTimer mouse_hide_timer; | 375 | QTimer mouse_hide_timer; |
| 376 | QTimer mouse_center_timer; | ||
| 375 | 377 | ||
| 376 | // FS | 378 | // FS |
| 377 | std::shared_ptr<FileSys::VfsFilesystem> vfs; | 379 | std::shared_ptr<FileSys::VfsFilesystem> vfs; |
| @@ -418,4 +420,5 @@ protected: | |||
| 418 | void dropEvent(QDropEvent* event) override; | 420 | void dropEvent(QDropEvent* event) override; |
| 419 | void dragEnterEvent(QDragEnterEvent* event) override; | 421 | void dragEnterEvent(QDragEnterEvent* event) override; |
| 420 | void dragMoveEvent(QDragMoveEvent* event) override; | 422 | void dragMoveEvent(QDragMoveEvent* event) override; |
| 423 | void leaveEvent(QEvent* event) override; | ||
| 421 | }; | 424 | }; |