diff options
Diffstat (limited to 'src')
202 files changed, 5010 insertions, 1649 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9182dbfd4..39d038493 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt | |||
| @@ -65,6 +65,10 @@ if (MSVC) | |||
| 65 | /we4305 # 'context': truncation from 'type1' to 'type2' | 65 | /we4305 # 'context': truncation from 'type1' to 'type2' |
| 66 | /we4388 # 'expression': signed/unsigned mismatch | 66 | /we4388 # 'expression': signed/unsigned mismatch |
| 67 | /we4389 # 'operator': signed/unsigned mismatch | 67 | /we4389 # 'operator': signed/unsigned mismatch |
| 68 | /we4456 # Declaration of 'identifier' hides previous local declaration | ||
| 69 | /we4457 # Declaration of 'identifier' hides function parameter | ||
| 70 | /we4458 # Declaration of 'identifier' hides class member | ||
| 71 | /we4459 # Declaration of 'identifier' hides global declaration | ||
| 68 | /we4505 # 'function': unreferenced local function has been removed | 72 | /we4505 # 'function': unreferenced local function has been removed |
| 69 | /we4547 # 'operator': operator before comma has no effect; expected operator with side-effect | 73 | /we4547 # 'operator': operator before comma has no effect; expected operator with side-effect |
| 70 | /we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'? | 74 | /we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'? |
| @@ -92,6 +96,7 @@ else() | |||
| 92 | -Werror=missing-declarations | 96 | -Werror=missing-declarations |
| 93 | -Werror=missing-field-initializers | 97 | -Werror=missing-field-initializers |
| 94 | -Werror=reorder | 98 | -Werror=reorder |
| 99 | -Werror=shadow | ||
| 95 | -Werror=sign-compare | 100 | -Werror=sign-compare |
| 96 | -Werror=switch | 101 | -Werror=switch |
| 97 | -Werror=uninitialized | 102 | -Werror=uninitialized |
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index e553b8203..89575a53e 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt | |||
| @@ -49,9 +49,6 @@ if (NOT MSVC) | |||
| 49 | target_compile_options(audio_core PRIVATE | 49 | target_compile_options(audio_core PRIVATE |
| 50 | -Werror=conversion | 50 | -Werror=conversion |
| 51 | -Werror=ignored-qualifiers | 51 | -Werror=ignored-qualifiers |
| 52 | -Werror=shadow | ||
| 53 | -Werror=unused-parameter | ||
| 54 | -Werror=unused-variable | ||
| 55 | 52 | ||
| 56 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> | 53 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> |
| 57 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> | 54 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> |
diff --git a/src/audio_core/command_generator.cpp b/src/audio_core/command_generator.cpp index ae4efafb6..f97520820 100644 --- a/src/audio_core/command_generator.cpp +++ b/src/audio_core/command_generator.cpp | |||
| @@ -129,17 +129,17 @@ s32 ToS32(float sample) { | |||
| 129 | return static_cast<s32>(rescaled_sample); | 129 | return static_cast<s32>(rescaled_sample); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_1CH{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 132 | constexpr std::array<u8, 20> REVERB_TAP_INDEX_1CH{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 133 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | 133 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 134 | 134 | ||
| 135 | constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_2CH{0, 0, 0, 1, 1, 1, 1, 0, 0, 0, | 135 | constexpr std::array<u8, 20> REVERB_TAP_INDEX_2CH{0, 0, 0, 1, 1, 1, 1, 0, 0, 0, |
| 136 | 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}; | 136 | 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}; |
| 137 | 137 | ||
| 138 | constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_4CH{0, 0, 0, 1, 1, 1, 1, 2, 2, 2, | 138 | constexpr std::array<u8, 20> REVERB_TAP_INDEX_4CH{0, 0, 0, 1, 1, 1, 1, 2, 2, 2, |
| 139 | 1, 1, 1, 0, 0, 0, 0, 3, 3, 3}; | 139 | 1, 1, 1, 0, 0, 0, 0, 3, 3, 3}; |
| 140 | 140 | ||
| 141 | constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_6CH{4, 0, 0, 1, 1, 1, 1, 2, 2, 2, | 141 | constexpr std::array<u8, 20> REVERB_TAP_INDEX_6CH{4, 0, 0, 1, 1, 1, 1, 2, 2, 2, |
| 142 | 1, 1, 1, 0, 0, 0, 0, 3, 3, 3}; | 142 | 1, 1, 1, 0, 0, 0, 0, 3, 3, 3}; |
| 143 | 143 | ||
| 144 | template <std::size_t CHANNEL_COUNT> | 144 | template <std::size_t CHANNEL_COUNT> |
| 145 | void ApplyReverbGeneric( | 145 | void ApplyReverbGeneric( |
| @@ -429,7 +429,7 @@ void CommandGenerator::GenerateDataSourceCommand(ServerVoiceInfo& voice_info, Vo | |||
| 429 | in_params.node_id); | 429 | in_params.node_id); |
| 430 | break; | 430 | break; |
| 431 | default: | 431 | default: |
| 432 | UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format); | 432 | ASSERT_MSG(false, "Unimplemented sample format={}", in_params.sample_format); |
| 433 | } | 433 | } |
| 434 | } | 434 | } |
| 435 | } | 435 | } |
| @@ -1312,7 +1312,7 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, std::s | |||
| 1312 | samples_to_read - samples_read, channel, temp_mix_offset); | 1312 | samples_to_read - samples_read, channel, temp_mix_offset); |
| 1313 | break; | 1313 | break; |
| 1314 | default: | 1314 | default: |
| 1315 | UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format); | 1315 | ASSERT_MSG(false, "Unimplemented sample format={}", in_params.sample_format); |
| 1316 | } | 1316 | } |
| 1317 | 1317 | ||
| 1318 | temp_mix_offset += samples_decoded; | 1318 | temp_mix_offset += samples_decoded; |
diff --git a/src/audio_core/effect_context.cpp b/src/audio_core/effect_context.cpp index 51059580e..79bcd1192 100644 --- a/src/audio_core/effect_context.cpp +++ b/src/audio_core/effect_context.cpp | |||
| @@ -50,7 +50,7 @@ EffectBase* EffectContext::RetargetEffect(std::size_t i, EffectType effect) { | |||
| 50 | effects[i] = std::make_unique<EffectBiquadFilter>(); | 50 | effects[i] = std::make_unique<EffectBiquadFilter>(); |
| 51 | break; | 51 | break; |
| 52 | default: | 52 | default: |
| 53 | UNREACHABLE_MSG("Unimplemented effect {}", effect); | 53 | ASSERT_MSG(false, "Unimplemented effect {}", effect); |
| 54 | effects[i] = std::make_unique<EffectStubbed>(); | 54 | effects[i] = std::make_unique<EffectStubbed>(); |
| 55 | } | 55 | } |
| 56 | return GetInfo(i); | 56 | return GetInfo(i); |
| @@ -104,7 +104,7 @@ void EffectI3dl2Reverb::Update(EffectInfo::InParams& in_params) { | |||
| 104 | auto& params = GetParams(); | 104 | auto& params = GetParams(); |
| 105 | const auto* reverb_params = reinterpret_cast<I3dl2ReverbParams*>(in_params.raw.data()); | 105 | const auto* reverb_params = reinterpret_cast<I3dl2ReverbParams*>(in_params.raw.data()); |
| 106 | if (!ValidChannelCountForEffect(reverb_params->max_channels)) { | 106 | if (!ValidChannelCountForEffect(reverb_params->max_channels)) { |
| 107 | UNREACHABLE_MSG("Invalid reverb max channel count {}", reverb_params->max_channels); | 107 | ASSERT_MSG(false, "Invalid reverb max channel count {}", reverb_params->max_channels); |
| 108 | return; | 108 | return; |
| 109 | } | 109 | } |
| 110 | 110 | ||
diff --git a/src/audio_core/splitter_context.cpp b/src/audio_core/splitter_context.cpp index 1751d0212..10646dc05 100644 --- a/src/audio_core/splitter_context.cpp +++ b/src/audio_core/splitter_context.cpp | |||
| @@ -483,7 +483,7 @@ bool NodeStates::DepthFirstSearch(EdgeMatrix& edge_matrix) { | |||
| 483 | // Add more work | 483 | // Add more work |
| 484 | index_stack.push(j); | 484 | index_stack.push(j); |
| 485 | } else if (node_state == NodeStates::State::InFound) { | 485 | } else if (node_state == NodeStates::State::InFound) { |
| 486 | UNREACHABLE_MSG("Node start marked as found"); | 486 | ASSERT_MSG(false, "Node start marked as found"); |
| 487 | ResetState(); | 487 | ResetState(); |
| 488 | return false; | 488 | return false; |
| 489 | } | 489 | } |
diff --git a/src/audio_core/voice_context.cpp b/src/audio_core/voice_context.cpp index c8e4a6caf..f58a5c754 100644 --- a/src/audio_core/voice_context.cpp +++ b/src/audio_core/voice_context.cpp | |||
| @@ -114,7 +114,7 @@ void ServerVoiceInfo::UpdateParameters(const VoiceInfo::InParams& voice_in, | |||
| 114 | in_params.current_playstate = ServerPlayState::Play; | 114 | in_params.current_playstate = ServerPlayState::Play; |
| 115 | break; | 115 | break; |
| 116 | default: | 116 | default: |
| 117 | UNREACHABLE_MSG("Unknown playstate {}", voice_in.play_state); | 117 | ASSERT_MSG(false, "Unknown playstate {}", voice_in.play_state); |
| 118 | break; | 118 | break; |
| 119 | } | 119 | } |
| 120 | 120 | ||
| @@ -410,7 +410,7 @@ bool ServerVoiceInfo::UpdateParametersForCommandGeneration( | |||
| 410 | return in_params.should_depop; | 410 | return in_params.should_depop; |
| 411 | } | 411 | } |
| 412 | default: | 412 | default: |
| 413 | UNREACHABLE_MSG("Invalid playstate {}", in_params.current_playstate); | 413 | ASSERT_MSG(false, "Invalid playstate {}", in_params.current_playstate); |
| 414 | } | 414 | } |
| 415 | 415 | ||
| 416 | return false; | 416 | return false; |
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index adf70eb8b..73bf626d4 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -58,6 +58,7 @@ add_library(common STATIC | |||
| 58 | div_ceil.h | 58 | div_ceil.h |
| 59 | dynamic_library.cpp | 59 | dynamic_library.cpp |
| 60 | dynamic_library.h | 60 | dynamic_library.h |
| 61 | elf.h | ||
| 61 | error.cpp | 62 | error.cpp |
| 62 | error.h | 63 | error.h |
| 63 | expected.h | 64 | expected.h |
diff --git a/src/common/assert.cpp b/src/common/assert.cpp index b44570528..6026b7dc2 100644 --- a/src/common/assert.cpp +++ b/src/common/assert.cpp | |||
| @@ -6,8 +6,13 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/settings.h" | 7 | #include "common/settings.h" |
| 8 | 8 | ||
| 9 | void assert_handle_failure() { | 9 | void assert_fail_impl() { |
| 10 | if (Settings::values.use_debug_asserts) { | 10 | if (Settings::values.use_debug_asserts) { |
| 11 | Crash(); | 11 | Crash(); |
| 12 | } | 12 | } |
| 13 | } | 13 | } |
| 14 | |||
| 15 | [[noreturn]] void unreachable_impl() { | ||
| 16 | Crash(); | ||
| 17 | throw std::runtime_error("Unreachable code"); | ||
| 18 | } | ||
diff --git a/src/common/assert.h b/src/common/assert.h index dbfd8abaf..8c927fcc0 100644 --- a/src/common/assert.h +++ b/src/common/assert.h | |||
| @@ -9,44 +9,43 @@ | |||
| 9 | // Sometimes we want to try to continue even after hitting an assert. | 9 | // Sometimes we want to try to continue even after hitting an assert. |
| 10 | // However touching this file yields a global recompilation as this header is included almost | 10 | // However touching this file yields a global recompilation as this header is included almost |
| 11 | // everywhere. So let's just move the handling of the failed assert to a single cpp file. | 11 | // everywhere. So let's just move the handling of the failed assert to a single cpp file. |
| 12 | void assert_handle_failure(); | ||
| 13 | 12 | ||
| 14 | // For asserts we'd like to keep all the junk executed when an assert happens away from the | 13 | void assert_fail_impl(); |
| 15 | // important code in the function. One way of doing this is to put all the relevant code inside a | 14 | [[noreturn]] void unreachable_impl(); |
| 16 | // lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to | 15 | |
| 17 | // specify __declspec on lambda functions, so what we do instead is define a noinline wrapper | 16 | #ifdef _MSC_VER |
| 18 | // template that calls the lambda. This seems to generate an extra instruction at the call-site | 17 | #define YUZU_NO_INLINE __declspec(noinline) |
| 19 | // compared to the ideal implementation (which wouldn't support ASSERT_MSG parameters), but is good | 18 | #else |
| 20 | // enough for our purposes. | 19 | #define YUZU_NO_INLINE __attribute__((noinline)) |
| 21 | template <typename Fn> | ||
| 22 | #if defined(_MSC_VER) | ||
| 23 | [[msvc::noinline]] | ||
| 24 | #elif defined(__GNUC__) | ||
| 25 | [[gnu::cold, gnu::noinline]] | ||
| 26 | #endif | 20 | #endif |
| 27 | static void | ||
| 28 | assert_noinline_call(const Fn& fn) { | ||
| 29 | fn(); | ||
| 30 | assert_handle_failure(); | ||
| 31 | } | ||
| 32 | 21 | ||
| 33 | #define ASSERT(_a_) \ | 22 | #define ASSERT(_a_) \ |
| 34 | do \ | 23 | ([&]() YUZU_NO_INLINE { \ |
| 35 | if (!(_a_)) { \ | 24 | if (!(_a_)) [[unlikely]] { \ |
| 36 | assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \ | 25 | LOG_CRITICAL(Debug, "Assertion Failed!"); \ |
| 26 | assert_fail_impl(); \ | ||
| 37 | } \ | 27 | } \ |
| 38 | while (0) | 28 | }()) |
| 39 | 29 | ||
| 40 | #define ASSERT_MSG(_a_, ...) \ | 30 | #define ASSERT_MSG(_a_, ...) \ |
| 41 | do \ | 31 | ([&]() YUZU_NO_INLINE { \ |
| 42 | if (!(_a_)) { \ | 32 | if (!(_a_)) [[unlikely]] { \ |
| 43 | assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \ | 33 | LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \ |
| 34 | assert_fail_impl(); \ | ||
| 44 | } \ | 35 | } \ |
| 45 | while (0) | 36 | }()) |
| 37 | |||
| 38 | #define UNREACHABLE() \ | ||
| 39 | do { \ | ||
| 40 | LOG_CRITICAL(Debug, "Unreachable code!"); \ | ||
| 41 | unreachable_impl(); \ | ||
| 42 | } while (0) | ||
| 46 | 43 | ||
| 47 | #define UNREACHABLE() assert_noinline_call([] { LOG_CRITICAL(Debug, "Unreachable code!"); }) | ||
| 48 | #define UNREACHABLE_MSG(...) \ | 44 | #define UNREACHABLE_MSG(...) \ |
| 49 | assert_noinline_call([&] { LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); }) | 45 | do { \ |
| 46 | LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); \ | ||
| 47 | unreachable_impl(); \ | ||
| 48 | } while (0) | ||
| 50 | 49 | ||
| 51 | #ifdef _DEBUG | 50 | #ifdef _DEBUG |
| 52 | #define DEBUG_ASSERT(_a_) ASSERT(_a_) | 51 | #define DEBUG_ASSERT(_a_) ASSERT(_a_) |
diff --git a/src/common/bounded_threadsafe_queue.h b/src/common/bounded_threadsafe_queue.h new file mode 100644 index 000000000..e83064c7f --- /dev/null +++ b/src/common/bounded_threadsafe_queue.h | |||
| @@ -0,0 +1,180 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright (c) 2020 Erik Rigtorp <erik@rigtorp.se> | ||
| 2 | // SPDX-License-Identifier: MIT | ||
| 3 | #pragma once | ||
| 4 | #ifdef _MSC_VER | ||
| 5 | #pragma warning(push) | ||
| 6 | #pragma warning(disable : 4324) | ||
| 7 | #endif | ||
| 8 | |||
| 9 | #include <atomic> | ||
| 10 | #include <bit> | ||
| 11 | #include <condition_variable> | ||
| 12 | #include <memory> | ||
| 13 | #include <mutex> | ||
| 14 | #include <new> | ||
| 15 | #include <stdexcept> | ||
| 16 | #include <stop_token> | ||
| 17 | #include <type_traits> | ||
| 18 | #include <utility> | ||
| 19 | |||
| 20 | namespace Common { | ||
| 21 | namespace mpsc { | ||
| 22 | #if defined(__cpp_lib_hardware_interference_size) | ||
| 23 | constexpr size_t hardware_interference_size = std::hardware_destructive_interference_size; | ||
| 24 | #else | ||
| 25 | constexpr size_t hardware_interference_size = 64; | ||
| 26 | #endif | ||
| 27 | |||
| 28 | template <typename T> | ||
| 29 | using AlignedAllocator = std::allocator<T>; | ||
| 30 | |||
| 31 | template <typename T> | ||
| 32 | struct Slot { | ||
| 33 | ~Slot() noexcept { | ||
| 34 | if (turn.test()) { | ||
| 35 | destroy(); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | template <typename... Args> | ||
| 40 | void construct(Args&&... args) noexcept { | ||
| 41 | static_assert(std::is_nothrow_constructible_v<T, Args&&...>, | ||
| 42 | "T must be nothrow constructible with Args&&..."); | ||
| 43 | std::construct_at(reinterpret_cast<T*>(&storage), std::forward<Args>(args)...); | ||
| 44 | } | ||
| 45 | |||
| 46 | void destroy() noexcept { | ||
| 47 | static_assert(std::is_nothrow_destructible_v<T>, "T must be nothrow destructible"); | ||
| 48 | std::destroy_at(reinterpret_cast<T*>(&storage)); | ||
| 49 | } | ||
| 50 | |||
| 51 | T&& move() noexcept { | ||
| 52 | return reinterpret_cast<T&&>(storage); | ||
| 53 | } | ||
| 54 | |||
| 55 | // Align to avoid false sharing between adjacent slots | ||
| 56 | alignas(hardware_interference_size) std::atomic_flag turn{}; | ||
| 57 | struct aligned_store { | ||
| 58 | struct type { | ||
| 59 | alignas(T) unsigned char data[sizeof(T)]; | ||
| 60 | }; | ||
| 61 | }; | ||
| 62 | typename aligned_store::type storage; | ||
| 63 | }; | ||
| 64 | |||
| 65 | template <typename T, typename Allocator = AlignedAllocator<Slot<T>>> | ||
| 66 | class Queue { | ||
| 67 | public: | ||
| 68 | explicit Queue(const size_t capacity, const Allocator& allocator = Allocator()) | ||
| 69 | : allocator_(allocator) { | ||
| 70 | if (capacity < 1) { | ||
| 71 | throw std::invalid_argument("capacity < 1"); | ||
| 72 | } | ||
| 73 | // Ensure that the queue length is an integer power of 2 | ||
| 74 | // This is so that idx(i) can be a simple i & mask_ insted of i % capacity | ||
| 75 | // https://github.com/rigtorp/MPMCQueue/pull/36 | ||
| 76 | if (!std::has_single_bit(capacity)) { | ||
| 77 | throw std::invalid_argument("capacity must be an integer power of 2"); | ||
| 78 | } | ||
| 79 | |||
| 80 | mask_ = capacity - 1; | ||
| 81 | |||
| 82 | // Allocate one extra slot to prevent false sharing on the last slot | ||
| 83 | slots_ = allocator_.allocate(mask_ + 2); | ||
| 84 | // Allocators are not required to honor alignment for over-aligned types | ||
| 85 | // (see http://eel.is/c++draft/allocator.requirements#10) so we verify | ||
| 86 | // alignment here | ||
| 87 | if (reinterpret_cast<uintptr_t>(slots_) % alignof(Slot<T>) != 0) { | ||
| 88 | allocator_.deallocate(slots_, mask_ + 2); | ||
| 89 | throw std::bad_alloc(); | ||
| 90 | } | ||
| 91 | for (size_t i = 0; i < mask_ + 1; ++i) { | ||
| 92 | std::construct_at(&slots_[i]); | ||
| 93 | } | ||
| 94 | static_assert(alignof(Slot<T>) == hardware_interference_size, | ||
| 95 | "Slot must be aligned to cache line boundary to prevent false sharing"); | ||
| 96 | static_assert(sizeof(Slot<T>) % hardware_interference_size == 0, | ||
| 97 | "Slot size must be a multiple of cache line size to prevent " | ||
| 98 | "false sharing between adjacent slots"); | ||
| 99 | static_assert(sizeof(Queue) % hardware_interference_size == 0, | ||
| 100 | "Queue size must be a multiple of cache line size to " | ||
| 101 | "prevent false sharing between adjacent queues"); | ||
| 102 | } | ||
| 103 | |||
| 104 | ~Queue() noexcept { | ||
| 105 | for (size_t i = 0; i < mask_ + 1; ++i) { | ||
| 106 | slots_[i].~Slot(); | ||
| 107 | } | ||
| 108 | allocator_.deallocate(slots_, mask_ + 2); | ||
| 109 | } | ||
| 110 | |||
| 111 | // non-copyable and non-movable | ||
| 112 | Queue(const Queue&) = delete; | ||
| 113 | Queue& operator=(const Queue&) = delete; | ||
| 114 | |||
| 115 | void Push(const T& v) noexcept { | ||
| 116 | static_assert(std::is_nothrow_copy_constructible_v<T>, | ||
| 117 | "T must be nothrow copy constructible"); | ||
| 118 | emplace(v); | ||
| 119 | } | ||
| 120 | |||
| 121 | template <typename P, typename = std::enable_if_t<std::is_nothrow_constructible_v<T, P&&>>> | ||
| 122 | void Push(P&& v) noexcept { | ||
| 123 | emplace(std::forward<P>(v)); | ||
| 124 | } | ||
| 125 | |||
| 126 | void Pop(T& v, std::stop_token stop) noexcept { | ||
| 127 | auto const tail = tail_.fetch_add(1); | ||
| 128 | auto& slot = slots_[idx(tail)]; | ||
| 129 | if (false == slot.turn.test()) { | ||
| 130 | std::unique_lock lock{cv_mutex}; | ||
| 131 | cv.wait(lock, stop, [&slot] { return slot.turn.test(); }); | ||
| 132 | } | ||
| 133 | v = slot.move(); | ||
| 134 | slot.destroy(); | ||
| 135 | slot.turn.clear(); | ||
| 136 | slot.turn.notify_one(); | ||
| 137 | } | ||
| 138 | |||
| 139 | private: | ||
| 140 | template <typename... Args> | ||
| 141 | void emplace(Args&&... args) noexcept { | ||
| 142 | static_assert(std::is_nothrow_constructible_v<T, Args&&...>, | ||
| 143 | "T must be nothrow constructible with Args&&..."); | ||
| 144 | auto const head = head_.fetch_add(1); | ||
| 145 | auto& slot = slots_[idx(head)]; | ||
| 146 | slot.turn.wait(true); | ||
| 147 | slot.construct(std::forward<Args>(args)...); | ||
| 148 | slot.turn.test_and_set(); | ||
| 149 | cv.notify_one(); | ||
| 150 | } | ||
| 151 | |||
| 152 | constexpr size_t idx(size_t i) const noexcept { | ||
| 153 | return i & mask_; | ||
| 154 | } | ||
| 155 | |||
| 156 | std::conditional_t<true, std::condition_variable_any, std::condition_variable> cv; | ||
| 157 | std::mutex cv_mutex; | ||
| 158 | size_t mask_; | ||
| 159 | Slot<T>* slots_; | ||
| 160 | [[no_unique_address]] Allocator allocator_; | ||
| 161 | |||
| 162 | // Align to avoid false sharing between head_ and tail_ | ||
| 163 | alignas(hardware_interference_size) std::atomic<size_t> head_{0}; | ||
| 164 | alignas(hardware_interference_size) std::atomic<size_t> tail_{0}; | ||
| 165 | |||
| 166 | static_assert(std::is_nothrow_copy_assignable_v<T> || std::is_nothrow_move_assignable_v<T>, | ||
| 167 | "T must be nothrow copy or move assignable"); | ||
| 168 | |||
| 169 | static_assert(std::is_nothrow_destructible_v<T>, "T must be nothrow destructible"); | ||
| 170 | }; | ||
| 171 | } // namespace mpsc | ||
| 172 | |||
| 173 | template <typename T, typename Allocator = mpsc::AlignedAllocator<mpsc::Slot<T>>> | ||
| 174 | using MPSCQueue = mpsc::Queue<T, Allocator>; | ||
| 175 | |||
| 176 | } // namespace Common | ||
| 177 | |||
| 178 | #ifdef _MSC_VER | ||
| 179 | #pragma warning(pop) | ||
| 180 | #endif | ||
diff --git a/src/common/detached_tasks.cpp b/src/common/detached_tasks.cpp index c1362631e..ec31d0b88 100644 --- a/src/common/detached_tasks.cpp +++ b/src/common/detached_tasks.cpp | |||
| @@ -33,9 +33,9 @@ void DetachedTasks::AddTask(std::function<void()> task) { | |||
| 33 | ++instance->count; | 33 | ++instance->count; |
| 34 | std::thread([task{std::move(task)}]() { | 34 | std::thread([task{std::move(task)}]() { |
| 35 | task(); | 35 | task(); |
| 36 | std::unique_lock lock{instance->mutex}; | 36 | std::unique_lock thread_lock{instance->mutex}; |
| 37 | --instance->count; | 37 | --instance->count; |
| 38 | std::notify_all_at_thread_exit(instance->cv, std::move(lock)); | 38 | std::notify_all_at_thread_exit(instance->cv, std::move(thread_lock)); |
| 39 | }).detach(); | 39 | }).detach(); |
| 40 | } | 40 | } |
| 41 | 41 | ||
diff --git a/src/common/elf.h b/src/common/elf.h new file mode 100644 index 000000000..14a5e9597 --- /dev/null +++ b/src/common/elf.h | |||
| @@ -0,0 +1,333 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <cstddef> | ||
| 8 | |||
| 9 | #include "common_types.h" | ||
| 10 | |||
| 11 | namespace Common { | ||
| 12 | namespace ELF { | ||
| 13 | |||
| 14 | /* Type for a 16-bit quantity. */ | ||
| 15 | using Elf32_Half = u16; | ||
| 16 | using Elf64_Half = u16; | ||
| 17 | |||
| 18 | /* Types for signed and unsigned 32-bit quantities. */ | ||
| 19 | using Elf32_Word = u32; | ||
| 20 | using Elf32_Sword = s32; | ||
| 21 | using Elf64_Word = u32; | ||
| 22 | using Elf64_Sword = s32; | ||
| 23 | |||
| 24 | /* Types for signed and unsigned 64-bit quantities. */ | ||
| 25 | using Elf32_Xword = u64; | ||
| 26 | using Elf32_Sxword = s64; | ||
| 27 | using Elf64_Xword = u64; | ||
| 28 | using Elf64_Sxword = s64; | ||
| 29 | |||
| 30 | /* Type of addresses. */ | ||
| 31 | using Elf32_Addr = u32; | ||
| 32 | using Elf64_Addr = u64; | ||
| 33 | |||
| 34 | /* Type of file offsets. */ | ||
| 35 | using Elf32_Off = u32; | ||
| 36 | using Elf64_Off = u64; | ||
| 37 | |||
| 38 | /* Type for section indices, which are 16-bit quantities. */ | ||
| 39 | using Elf32_Section = u16; | ||
| 40 | using Elf64_Section = u16; | ||
| 41 | |||
| 42 | /* Type for version symbol information. */ | ||
| 43 | using Elf32_Versym = Elf32_Half; | ||
| 44 | using Elf64_Versym = Elf64_Half; | ||
| 45 | |||
| 46 | constexpr size_t ElfIdentSize = 16; | ||
| 47 | |||
| 48 | /* The ELF file header. This appears at the start of every ELF file. */ | ||
| 49 | |||
| 50 | struct Elf32_Ehdr { | ||
| 51 | std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */ | ||
| 52 | Elf32_Half e_type; /* Object file type */ | ||
| 53 | Elf32_Half e_machine; /* Architecture */ | ||
| 54 | Elf32_Word e_version; /* Object file version */ | ||
| 55 | Elf32_Addr e_entry; /* Entry point virtual address */ | ||
| 56 | Elf32_Off e_phoff; /* Program header table file offset */ | ||
| 57 | Elf32_Off e_shoff; /* Section header table file offset */ | ||
| 58 | Elf32_Word e_flags; /* Processor-specific flags */ | ||
| 59 | Elf32_Half e_ehsize; /* ELF header size in bytes */ | ||
| 60 | Elf32_Half e_phentsize; /* Program header table entry size */ | ||
| 61 | Elf32_Half e_phnum; /* Program header table entry count */ | ||
| 62 | Elf32_Half e_shentsize; /* Section header table entry size */ | ||
| 63 | Elf32_Half e_shnum; /* Section header table entry count */ | ||
| 64 | Elf32_Half e_shstrndx; /* Section header string table index */ | ||
| 65 | }; | ||
| 66 | |||
| 67 | struct Elf64_Ehdr { | ||
| 68 | std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */ | ||
| 69 | Elf64_Half e_type; /* Object file type */ | ||
| 70 | Elf64_Half e_machine; /* Architecture */ | ||
| 71 | Elf64_Word e_version; /* Object file version */ | ||
| 72 | Elf64_Addr e_entry; /* Entry point virtual address */ | ||
| 73 | Elf64_Off e_phoff; /* Program header table file offset */ | ||
| 74 | Elf64_Off e_shoff; /* Section header table file offset */ | ||
| 75 | Elf64_Word e_flags; /* Processor-specific flags */ | ||
| 76 | Elf64_Half e_ehsize; /* ELF header size in bytes */ | ||
| 77 | Elf64_Half e_phentsize; /* Program header table entry size */ | ||
| 78 | Elf64_Half e_phnum; /* Program header table entry count */ | ||
| 79 | Elf64_Half e_shentsize; /* Section header table entry size */ | ||
| 80 | Elf64_Half e_shnum; /* Section header table entry count */ | ||
| 81 | Elf64_Half e_shstrndx; /* Section header string table index */ | ||
| 82 | }; | ||
| 83 | |||
| 84 | constexpr u8 ElfClass32 = 1; /* 32-bit objects */ | ||
| 85 | constexpr u8 ElfClass64 = 2; /* 64-bit objects */ | ||
| 86 | constexpr u8 ElfData2Lsb = 1; /* 2's complement, little endian */ | ||
| 87 | constexpr u8 ElfVersionCurrent = 1; /* EV_CURRENT */ | ||
| 88 | constexpr u8 ElfOsAbiNone = 0; /* System V ABI */ | ||
| 89 | |||
| 90 | constexpr u16 ElfTypeNone = 0; /* No file type */ | ||
| 91 | constexpr u16 ElfTypeRel = 0; /* Relocatable file */ | ||
| 92 | constexpr u16 ElfTypeExec = 0; /* Executable file */ | ||
| 93 | constexpr u16 ElfTypeDyn = 0; /* Shared object file */ | ||
| 94 | |||
| 95 | constexpr u16 ElfMachineArm = 40; /* ARM */ | ||
| 96 | constexpr u16 ElfMachineAArch64 = 183; /* ARM AARCH64 */ | ||
| 97 | |||
| 98 | constexpr std::array<u8, ElfIdentSize> Elf32Ident{ | ||
| 99 | 0x7f, 'E', 'L', 'F', ElfClass32, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone}; | ||
| 100 | |||
| 101 | constexpr std::array<u8, ElfIdentSize> Elf64Ident{ | ||
| 102 | 0x7f, 'E', 'L', 'F', ElfClass64, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone}; | ||
| 103 | |||
| 104 | /* Section header. */ | ||
| 105 | |||
| 106 | struct Elf32_Shdr { | ||
| 107 | Elf32_Word sh_name; /* Section name (string tbl index) */ | ||
| 108 | Elf32_Word sh_type; /* Section type */ | ||
| 109 | Elf32_Word sh_flags; /* Section flags */ | ||
| 110 | Elf32_Addr sh_addr; /* Section virtual addr at execution */ | ||
| 111 | Elf32_Off sh_offset; /* Section file offset */ | ||
| 112 | Elf32_Word sh_size; /* Section size in bytes */ | ||
| 113 | Elf32_Word sh_link; /* Link to another section */ | ||
| 114 | Elf32_Word sh_info; /* Additional section information */ | ||
| 115 | Elf32_Word sh_addralign; /* Section alignment */ | ||
| 116 | Elf32_Word sh_entsize; /* Entry size if section holds table */ | ||
| 117 | }; | ||
| 118 | |||
| 119 | struct Elf64_Shdr { | ||
| 120 | Elf64_Word sh_name; /* Section name (string tbl index) */ | ||
| 121 | Elf64_Word sh_type; /* Section type */ | ||
| 122 | Elf64_Xword sh_flags; /* Section flags */ | ||
| 123 | Elf64_Addr sh_addr; /* Section virtual addr at execution */ | ||
| 124 | Elf64_Off sh_offset; /* Section file offset */ | ||
| 125 | Elf64_Xword sh_size; /* Section size in bytes */ | ||
| 126 | Elf64_Word sh_link; /* Link to another section */ | ||
| 127 | Elf64_Word sh_info; /* Additional section information */ | ||
| 128 | Elf64_Xword sh_addralign; /* Section alignment */ | ||
| 129 | Elf64_Xword sh_entsize; /* Entry size if section holds table */ | ||
| 130 | }; | ||
| 131 | |||
| 132 | constexpr u32 ElfShnUndef = 0; /* Undefined section */ | ||
| 133 | |||
| 134 | constexpr u32 ElfShtNull = 0; /* Section header table entry unused */ | ||
| 135 | constexpr u32 ElfShtProgBits = 1; /* Program data */ | ||
| 136 | constexpr u32 ElfShtSymtab = 2; /* Symbol table */ | ||
| 137 | constexpr u32 ElfShtStrtab = 3; /* String table */ | ||
| 138 | constexpr u32 ElfShtRela = 4; /* Relocation entries with addends */ | ||
| 139 | constexpr u32 ElfShtDynamic = 6; /* Dynamic linking information */ | ||
| 140 | constexpr u32 ElfShtNobits = 7; /* Program space with no data (bss) */ | ||
| 141 | constexpr u32 ElfShtRel = 9; /* Relocation entries, no addends */ | ||
| 142 | constexpr u32 ElfShtDynsym = 11; /* Dynamic linker symbol table */ | ||
| 143 | |||
| 144 | /* Symbol table entry. */ | ||
| 145 | |||
| 146 | struct Elf32_Sym { | ||
| 147 | Elf32_Word st_name; /* Symbol name (string tbl index) */ | ||
| 148 | Elf32_Addr st_value; /* Symbol value */ | ||
| 149 | Elf32_Word st_size; /* Symbol size */ | ||
| 150 | u8 st_info; /* Symbol type and binding */ | ||
| 151 | u8 st_other; /* Symbol visibility */ | ||
| 152 | Elf32_Section st_shndx; /* Section index */ | ||
| 153 | }; | ||
| 154 | |||
| 155 | struct Elf64_Sym { | ||
| 156 | Elf64_Word st_name; /* Symbol name (string tbl index) */ | ||
| 157 | u8 st_info; /* Symbol type and binding */ | ||
| 158 | u8 st_other; /* Symbol visibility */ | ||
| 159 | Elf64_Section st_shndx; /* Section index */ | ||
| 160 | Elf64_Addr st_value; /* Symbol value */ | ||
| 161 | Elf64_Xword st_size; /* Symbol size */ | ||
| 162 | }; | ||
| 163 | |||
| 164 | /* How to extract and insert information held in the st_info field. */ | ||
| 165 | |||
| 166 | static inline u8 ElfStBind(u8 st_info) { | ||
| 167 | return st_info >> 4; | ||
| 168 | } | ||
| 169 | static inline u8 ElfStType(u8 st_info) { | ||
| 170 | return st_info & 0xf; | ||
| 171 | } | ||
| 172 | static inline u8 ElfStInfo(u8 st_bind, u8 st_type) { | ||
| 173 | return static_cast<u8>((st_bind << 4) + (st_type & 0xf)); | ||
| 174 | } | ||
| 175 | |||
| 176 | constexpr u8 ElfBindLocal = 0; /* Local symbol */ | ||
| 177 | constexpr u8 ElfBindGlobal = 1; /* Global symbol */ | ||
| 178 | constexpr u8 ElfBindWeak = 2; /* Weak symbol */ | ||
| 179 | |||
| 180 | constexpr u8 ElfTypeUnspec = 0; /* Symbol type is unspecified */ | ||
| 181 | constexpr u8 ElfTypeObject = 1; /* Symbol is a data object */ | ||
| 182 | constexpr u8 ElfTypeFunc = 2; /* Symbol is a code object */ | ||
| 183 | |||
| 184 | static inline u8 ElfStVisibility(u8 st_other) { | ||
| 185 | return static_cast<u8>(st_other & 0x3); | ||
| 186 | } | ||
| 187 | |||
| 188 | constexpr u8 ElfVisibilityDefault = 0; /* Default symbol visibility rules */ | ||
| 189 | constexpr u8 ElfVisibilityInternal = 1; /* Processor specific hidden class */ | ||
| 190 | constexpr u8 ElfVisibilityHidden = 2; /* Sym unavailable in other modules */ | ||
| 191 | constexpr u8 ElfVisibilityProtected = 3; /* Not preemptible, not exported */ | ||
| 192 | |||
| 193 | /* Relocation table entry without addend (in section of type ShtRel). */ | ||
| 194 | |||
| 195 | struct Elf32_Rel { | ||
| 196 | Elf32_Addr r_offset; /* Address */ | ||
| 197 | Elf32_Word r_info; /* Relocation type and symbol index */ | ||
| 198 | }; | ||
| 199 | |||
| 200 | /* Relocation table entry with addend (in section of type ShtRela). */ | ||
| 201 | |||
| 202 | struct Elf32_Rela { | ||
| 203 | Elf32_Addr r_offset; /* Address */ | ||
| 204 | Elf32_Word r_info; /* Relocation type and symbol index */ | ||
| 205 | Elf32_Sword r_addend; /* Addend */ | ||
| 206 | }; | ||
| 207 | |||
| 208 | struct Elf64_Rela { | ||
| 209 | Elf64_Addr r_offset; /* Address */ | ||
| 210 | Elf64_Xword r_info; /* Relocation type and symbol index */ | ||
| 211 | Elf64_Sxword r_addend; /* Addend */ | ||
| 212 | }; | ||
| 213 | |||
| 214 | /* How to extract and insert information held in the r_info field. */ | ||
| 215 | |||
| 216 | static inline u32 Elf32RelSymIndex(Elf32_Word r_info) { | ||
| 217 | return r_info >> 8; | ||
| 218 | } | ||
| 219 | static inline u8 Elf32RelType(Elf32_Word r_info) { | ||
| 220 | return static_cast<u8>(r_info & 0xff); | ||
| 221 | } | ||
| 222 | static inline Elf32_Word Elf32RelInfo(u32 sym_index, u8 type) { | ||
| 223 | return (sym_index << 8) + type; | ||
| 224 | } | ||
| 225 | static inline u32 Elf64RelSymIndex(Elf64_Xword r_info) { | ||
| 226 | return static_cast<u32>(r_info >> 32); | ||
| 227 | } | ||
| 228 | static inline u32 Elf64RelType(Elf64_Xword r_info) { | ||
| 229 | return r_info & 0xffffffff; | ||
| 230 | } | ||
| 231 | static inline Elf64_Xword Elf64RelInfo(u32 sym_index, u32 type) { | ||
| 232 | return (static_cast<Elf64_Xword>(sym_index) << 32) + type; | ||
| 233 | } | ||
| 234 | |||
| 235 | constexpr u32 ElfArmCopy = 20; /* Copy symbol at runtime */ | ||
| 236 | constexpr u32 ElfArmGlobDat = 21; /* Create GOT entry */ | ||
| 237 | constexpr u32 ElfArmJumpSlot = 22; /* Create PLT entry */ | ||
| 238 | constexpr u32 ElfArmRelative = 23; /* Adjust by program base */ | ||
| 239 | |||
| 240 | constexpr u32 ElfAArch64Copy = 1024; /* Copy symbol at runtime */ | ||
| 241 | constexpr u32 ElfAArch64GlobDat = 1025; /* Create GOT entry */ | ||
| 242 | constexpr u32 ElfAArch64JumpSlot = 1026; /* Create PLT entry */ | ||
| 243 | constexpr u32 ElfAArch64Relative = 1027; /* Adjust by program base */ | ||
| 244 | |||
| 245 | /* Program segment header. */ | ||
| 246 | |||
| 247 | struct Elf32_Phdr { | ||
| 248 | Elf32_Word p_type; /* Segment type */ | ||
| 249 | Elf32_Off p_offset; /* Segment file offset */ | ||
| 250 | Elf32_Addr p_vaddr; /* Segment virtual address */ | ||
| 251 | Elf32_Addr p_paddr; /* Segment physical address */ | ||
| 252 | Elf32_Word p_filesz; /* Segment size in file */ | ||
| 253 | Elf32_Word p_memsz; /* Segment size in memory */ | ||
| 254 | Elf32_Word p_flags; /* Segment flags */ | ||
| 255 | Elf32_Word p_align; /* Segment alignment */ | ||
| 256 | }; | ||
| 257 | |||
| 258 | struct Elf64_Phdr { | ||
| 259 | Elf64_Word p_type; /* Segment type */ | ||
| 260 | Elf64_Word p_flags; /* Segment flags */ | ||
| 261 | Elf64_Off p_offset; /* Segment file offset */ | ||
| 262 | Elf64_Addr p_vaddr; /* Segment virtual address */ | ||
| 263 | Elf64_Addr p_paddr; /* Segment physical address */ | ||
| 264 | Elf64_Xword p_filesz; /* Segment size in file */ | ||
| 265 | Elf64_Xword p_memsz; /* Segment size in memory */ | ||
| 266 | Elf64_Xword p_align; /* Segment alignment */ | ||
| 267 | }; | ||
| 268 | |||
| 269 | /* Legal values for p_type (segment type). */ | ||
| 270 | |||
| 271 | constexpr u32 ElfPtNull = 0; /* Program header table entry unused */ | ||
| 272 | constexpr u32 ElfPtLoad = 1; /* Loadable program segment */ | ||
| 273 | constexpr u32 ElfPtDynamic = 2; /* Dynamic linking information */ | ||
| 274 | constexpr u32 ElfPtInterp = 3; /* Program interpreter */ | ||
| 275 | constexpr u32 ElfPtNote = 4; /* Auxiliary information */ | ||
| 276 | constexpr u32 ElfPtPhdr = 6; /* Entry for header table itself */ | ||
| 277 | constexpr u32 ElfPtTls = 7; /* Thread-local storage segment */ | ||
| 278 | |||
| 279 | /* Legal values for p_flags (segment flags). */ | ||
| 280 | |||
| 281 | constexpr u32 ElfPfExec = 0; /* Segment is executable */ | ||
| 282 | constexpr u32 ElfPfWrite = 1; /* Segment is writable */ | ||
| 283 | constexpr u32 ElfPfRead = 2; /* Segment is readable */ | ||
| 284 | |||
| 285 | /* Dynamic section entry. */ | ||
| 286 | |||
| 287 | struct Elf32_Dyn { | ||
| 288 | Elf32_Sword d_tag; /* Dynamic entry type */ | ||
| 289 | union { | ||
| 290 | Elf32_Word d_val; /* Integer value */ | ||
| 291 | Elf32_Addr d_ptr; /* Address value */ | ||
| 292 | } d_un; | ||
| 293 | }; | ||
| 294 | |||
| 295 | struct Elf64_Dyn { | ||
| 296 | Elf64_Sxword d_tag; /* Dynamic entry type */ | ||
| 297 | union { | ||
| 298 | Elf64_Xword d_val; /* Integer value */ | ||
| 299 | Elf64_Addr d_ptr; /* Address value */ | ||
| 300 | } d_un; | ||
| 301 | }; | ||
| 302 | |||
| 303 | /* Legal values for d_tag (dynamic entry type). */ | ||
| 304 | |||
| 305 | constexpr u32 ElfDtNull = 0; /* Marks end of dynamic section */ | ||
| 306 | constexpr u32 ElfDtNeeded = 1; /* Name of needed library */ | ||
| 307 | constexpr u32 ElfDtPltRelSz = 2; /* Size in bytes of PLT relocs */ | ||
| 308 | constexpr u32 ElfDtPltGot = 3; /* Processor defined value */ | ||
| 309 | constexpr u32 ElfDtHash = 4; /* Address of symbol hash table */ | ||
| 310 | constexpr u32 ElfDtStrtab = 5; /* Address of string table */ | ||
| 311 | constexpr u32 ElfDtSymtab = 6; /* Address of symbol table */ | ||
| 312 | constexpr u32 ElfDtRela = 7; /* Address of Rela relocs */ | ||
| 313 | constexpr u32 ElfDtRelasz = 8; /* Total size of Rela relocs */ | ||
| 314 | constexpr u32 ElfDtRelaent = 9; /* Size of one Rela reloc */ | ||
| 315 | constexpr u32 ElfDtStrsz = 10; /* Size of string table */ | ||
| 316 | constexpr u32 ElfDtSyment = 11; /* Size of one symbol table entry */ | ||
| 317 | constexpr u32 ElfDtInit = 12; /* Address of init function */ | ||
| 318 | constexpr u32 ElfDtFini = 13; /* Address of termination function */ | ||
| 319 | constexpr u32 ElfDtRel = 17; /* Address of Rel relocs */ | ||
| 320 | constexpr u32 ElfDtRelsz = 18; /* Total size of Rel relocs */ | ||
| 321 | constexpr u32 ElfDtRelent = 19; /* Size of one Rel reloc */ | ||
| 322 | constexpr u32 ElfDtPltRel = 20; /* Type of reloc in PLT */ | ||
| 323 | constexpr u32 ElfDtTextRel = 22; /* Reloc might modify .text */ | ||
| 324 | constexpr u32 ElfDtJmpRel = 23; /* Address of PLT relocs */ | ||
| 325 | constexpr u32 ElfDtBindNow = 24; /* Process relocations of object */ | ||
| 326 | constexpr u32 ElfDtInitArray = 25; /* Array with addresses of init fct */ | ||
| 327 | constexpr u32 ElfDtFiniArray = 26; /* Array with addresses of fini fct */ | ||
| 328 | constexpr u32 ElfDtInitArraySz = 27; /* Size in bytes of DT_INIT_ARRAY */ | ||
| 329 | constexpr u32 ElfDtFiniArraySz = 28; /* Size in bytes of DT_FINI_ARRAY */ | ||
| 330 | constexpr u32 ElfDtSymtabShndx = 34; /* Address of SYMTAB_SHNDX section */ | ||
| 331 | |||
| 332 | } // namespace ELF | ||
| 333 | } // namespace Common | ||
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index 62318e70c..1074f2421 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp | |||
| @@ -232,9 +232,7 @@ void SetYuzuPath(YuzuPath yuzu_path, const fs::path& new_path) { | |||
| 232 | fs::path GetExeDirectory() { | 232 | fs::path GetExeDirectory() { |
| 233 | wchar_t exe_path[MAX_PATH]; | 233 | wchar_t exe_path[MAX_PATH]; |
| 234 | 234 | ||
| 235 | GetModuleFileNameW(nullptr, exe_path, MAX_PATH); | 235 | if (GetModuleFileNameW(nullptr, exe_path, MAX_PATH) == 0) { |
| 236 | |||
| 237 | if (!exe_path) { | ||
| 238 | LOG_ERROR(Common_Filesystem, | 236 | LOG_ERROR(Common_Filesystem, |
| 239 | "Failed to get the path to the executable of the current process"); | 237 | "Failed to get the path to the executable of the current process"); |
| 240 | } | 238 | } |
diff --git a/src/common/input.h b/src/common/input.h index 54fcb24b0..bb42aaacc 100644 --- a/src/common/input.h +++ b/src/common/input.h | |||
| @@ -72,6 +72,7 @@ enum class PollingError { | |||
| 72 | enum class VibrationAmplificationType { | 72 | enum class VibrationAmplificationType { |
| 73 | Linear, | 73 | Linear, |
| 74 | Exponential, | 74 | Exponential, |
| 75 | Test, | ||
| 75 | }; | 76 | }; |
| 76 | 77 | ||
| 77 | // Analog properties for calibration | 78 | // Analog properties for calibration |
diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 9a9c74a70..751549583 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp | |||
| @@ -70,6 +70,7 @@ void LogSettings() { | |||
| 70 | log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir)); | 70 | log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir)); |
| 71 | log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir)); | 71 | log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir)); |
| 72 | log_setting("Debugging_ProgramArgs", values.program_args.GetValue()); | 72 | log_setting("Debugging_ProgramArgs", values.program_args.GetValue()); |
| 73 | log_setting("Debugging_GDBStub", values.use_gdbstub.GetValue()); | ||
| 73 | log_setting("Input_EnableMotion", values.motion_enabled.GetValue()); | 74 | log_setting("Input_EnableMotion", values.motion_enabled.GetValue()); |
| 74 | log_setting("Input_EnableVibration", values.vibration_enabled.GetValue()); | 75 | log_setting("Input_EnableVibration", values.vibration_enabled.GetValue()); |
| 75 | log_setting("Input_EnableRawInput", values.enable_raw_input.GetValue()); | 76 | log_setting("Input_EnableRawInput", values.enable_raw_input.GetValue()); |
| @@ -146,7 +147,7 @@ void UpdateRescalingInfo() { | |||
| 146 | info.down_shift = 0; | 147 | info.down_shift = 0; |
| 147 | break; | 148 | break; |
| 148 | default: | 149 | default: |
| 149 | UNREACHABLE(); | 150 | ASSERT(false); |
| 150 | info.up_scale = 1; | 151 | info.up_scale = 1; |
| 151 | info.down_shift = 0; | 152 | info.down_shift = 0; |
| 152 | } | 153 | } |
diff --git a/src/common/settings.h b/src/common/settings.h index 5b34169a8..a507744a2 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -496,7 +496,7 @@ struct Values { | |||
| 496 | 496 | ||
| 497 | // Renderer | 497 | // Renderer |
| 498 | RangedSetting<RendererBackend> renderer_backend{ | 498 | RangedSetting<RendererBackend> renderer_backend{ |
| 499 | RendererBackend::OpenGL, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"}; | 499 | RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"}; |
| 500 | BasicSetting<bool> renderer_debug{false, "debug"}; | 500 | BasicSetting<bool> renderer_debug{false, "debug"}; |
| 501 | BasicSetting<bool> renderer_shader_feedback{false, "shader_feedback"}; | 501 | BasicSetting<bool> renderer_shader_feedback{false, "shader_feedback"}; |
| 502 | BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"}; | 502 | BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"}; |
| @@ -601,11 +601,12 @@ struct Values { | |||
| 601 | // Debugging | 601 | // Debugging |
| 602 | bool record_frame_times; | 602 | bool record_frame_times; |
| 603 | BasicSetting<bool> use_gdbstub{false, "use_gdbstub"}; | 603 | BasicSetting<bool> use_gdbstub{false, "use_gdbstub"}; |
| 604 | BasicSetting<u16> gdbstub_port{0, "gdbstub_port"}; | 604 | BasicSetting<u16> gdbstub_port{6543, "gdbstub_port"}; |
| 605 | BasicSetting<std::string> program_args{std::string(), "program_args"}; | 605 | BasicSetting<std::string> program_args{std::string(), "program_args"}; |
| 606 | BasicSetting<bool> dump_exefs{false, "dump_exefs"}; | 606 | BasicSetting<bool> dump_exefs{false, "dump_exefs"}; |
| 607 | BasicSetting<bool> dump_nso{false, "dump_nso"}; | 607 | BasicSetting<bool> dump_nso{false, "dump_nso"}; |
| 608 | BasicSetting<bool> dump_shaders{false, "dump_shaders"}; | 608 | BasicSetting<bool> dump_shaders{false, "dump_shaders"}; |
| 609 | BasicSetting<bool> dump_macros{false, "dump_macros"}; | ||
| 609 | BasicSetting<bool> enable_fs_access_log{false, "enable_fs_access_log"}; | 610 | BasicSetting<bool> enable_fs_access_log{false, "enable_fs_access_log"}; |
| 610 | BasicSetting<bool> reporting_services{false, "reporting_services"}; | 611 | BasicSetting<bool> reporting_services{false, "reporting_services"}; |
| 611 | BasicSetting<bool> quest_flag{false, "quest_flag"}; | 612 | BasicSetting<bool> quest_flag{false, "quest_flag"}; |
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 703aa5db8..7a495bc79 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp | |||
| @@ -178,6 +178,10 @@ std::wstring UTF8ToUTF16W(const std::string& input) { | |||
| 178 | 178 | ||
| 179 | #endif | 179 | #endif |
| 180 | 180 | ||
| 181 | std::u16string U16StringFromBuffer(const u16* input, std::size_t length) { | ||
| 182 | return std::u16string(reinterpret_cast<const char16_t*>(input), length); | ||
| 183 | } | ||
| 184 | |||
| 181 | std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer, std::size_t max_len) { | 185 | std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer, std::size_t max_len) { |
| 182 | std::size_t len = 0; | 186 | std::size_t len = 0; |
| 183 | while (len < buffer.length() && len < max_len && buffer[len] != '\0') { | 187 | while (len < buffer.length() && len < max_len && buffer[len] != '\0') { |
diff --git a/src/common/string_util.h b/src/common/string_util.h index a33830aec..ce18a33cf 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h | |||
| @@ -44,6 +44,8 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _ | |||
| 44 | 44 | ||
| 45 | #endif | 45 | #endif |
| 46 | 46 | ||
| 47 | [[nodiscard]] std::u16string U16StringFromBuffer(const u16* input, std::size_t length); | ||
| 48 | |||
| 47 | /** | 49 | /** |
| 48 | * Compares the string defined by the range [`begin`, `end`) to the null-terminated C-string | 50 | * Compares the string defined by the range [`begin`, `end`) to the null-terminated C-string |
| 49 | * `other` for equality. | 51 | * `other` for equality. |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 62230bae0..670410e75 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -36,6 +36,13 @@ add_library(core STATIC | |||
| 36 | crypto/ctr_encryption_layer.h | 36 | crypto/ctr_encryption_layer.h |
| 37 | crypto/xts_encryption_layer.cpp | 37 | crypto/xts_encryption_layer.cpp |
| 38 | crypto/xts_encryption_layer.h | 38 | crypto/xts_encryption_layer.h |
| 39 | debugger/debugger_interface.h | ||
| 40 | debugger/debugger.cpp | ||
| 41 | debugger/debugger.h | ||
| 42 | debugger/gdbstub_arch.cpp | ||
| 43 | debugger/gdbstub_arch.h | ||
| 44 | debugger/gdbstub.cpp | ||
| 45 | debugger/gdbstub.h | ||
| 39 | device_memory.cpp | 46 | device_memory.cpp |
| 40 | device_memory.h | 47 | device_memory.h |
| 41 | file_sys/bis_factory.cpp | 48 | file_sys/bis_factory.cpp |
| @@ -736,16 +743,11 @@ if (MSVC) | |||
| 736 | /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data | 743 | /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data |
| 737 | /we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch | 744 | /we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch |
| 738 | /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data | 745 | /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data |
| 739 | /we4456 # Declaration of 'identifier' hides previous local declaration | ||
| 740 | /we4457 # Declaration of 'identifier' hides function parameter | ||
| 741 | /we4458 # Declaration of 'identifier' hides class member | ||
| 742 | /we4459 # Declaration of 'identifier' hides global declaration | ||
| 743 | ) | 746 | ) |
| 744 | else() | 747 | else() |
| 745 | target_compile_options(core PRIVATE | 748 | target_compile_options(core PRIVATE |
| 746 | -Werror=conversion | 749 | -Werror=conversion |
| 747 | -Werror=ignored-qualifiers | 750 | -Werror=ignored-qualifiers |
| 748 | -Werror=shadow | ||
| 749 | 751 | ||
| 750 | $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> | 752 | $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> |
| 751 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> | 753 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> |
| @@ -761,6 +763,9 @@ create_target_directory_groups(core) | |||
| 761 | 763 | ||
| 762 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) | 764 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) |
| 763 | target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus) | 765 | target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus) |
| 766 | if (MINGW) | ||
| 767 | target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY}) | ||
| 768 | endif() | ||
| 764 | 769 | ||
| 765 | if (ENABLE_WEB_SERVICE) | 770 | if (ENABLE_WEB_SERVICE) |
| 766 | target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) | 771 | target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) |
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index c347e7ea7..9a285dfc6 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp | |||
| @@ -9,7 +9,9 @@ | |||
| 9 | #include "core/arm/arm_interface.h" | 9 | #include "core/arm/arm_interface.h" |
| 10 | #include "core/arm/symbols.h" | 10 | #include "core/arm/symbols.h" |
| 11 | #include "core/core.h" | 11 | #include "core/core.h" |
| 12 | #include "core/debugger/debugger.h" | ||
| 12 | #include "core/hle/kernel/k_process.h" | 13 | #include "core/hle/kernel/k_process.h" |
| 14 | #include "core/hle/kernel/svc.h" | ||
| 13 | #include "core/loader/loader.h" | 15 | #include "core/loader/loader.h" |
| 14 | #include "core/memory.h" | 16 | #include "core/memory.h" |
| 15 | 17 | ||
| @@ -88,4 +90,50 @@ void ARM_Interface::LogBacktrace() const { | |||
| 88 | } | 90 | } |
| 89 | } | 91 | } |
| 90 | 92 | ||
| 93 | void ARM_Interface::Run() { | ||
| 94 | using Kernel::StepState; | ||
| 95 | using Kernel::SuspendType; | ||
| 96 | |||
| 97 | while (true) { | ||
| 98 | Kernel::KThread* current_thread{system.Kernel().CurrentScheduler()->GetCurrentThread()}; | ||
| 99 | Dynarmic::HaltReason hr{}; | ||
| 100 | |||
| 101 | // Notify the debugger and go to sleep if a step was performed | ||
| 102 | // and this thread has been scheduled again. | ||
| 103 | if (current_thread->GetStepState() == StepState::StepPerformed) { | ||
| 104 | system.GetDebugger().NotifyThreadStopped(current_thread); | ||
| 105 | current_thread->RequestSuspend(SuspendType::Debug); | ||
| 106 | break; | ||
| 107 | } | ||
| 108 | |||
| 109 | // Otherwise, run the thread. | ||
| 110 | system.EnterDynarmicProfile(); | ||
| 111 | if (current_thread->GetStepState() == StepState::StepPending) { | ||
| 112 | hr = StepJit(); | ||
| 113 | |||
| 114 | if (Has(hr, step_thread)) { | ||
| 115 | current_thread->SetStepState(StepState::StepPerformed); | ||
| 116 | } | ||
| 117 | } else { | ||
| 118 | hr = RunJit(); | ||
| 119 | } | ||
| 120 | system.ExitDynarmicProfile(); | ||
| 121 | |||
| 122 | // Notify the debugger and go to sleep if a breakpoint was hit. | ||
| 123 | if (Has(hr, breakpoint)) { | ||
| 124 | system.GetDebugger().NotifyThreadStopped(current_thread); | ||
| 125 | current_thread->RequestSuspend(Kernel::SuspendType::Debug); | ||
| 126 | break; | ||
| 127 | } | ||
| 128 | |||
| 129 | // Handle syscalls and scheduling (this may change the current thread) | ||
| 130 | if (Has(hr, svc_call)) { | ||
| 131 | Kernel::Svc::Call(system, GetSvcNumber()); | ||
| 132 | } | ||
| 133 | if (Has(hr, break_loop) || !uses_wall_clock) { | ||
| 134 | break; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 91 | } // namespace Core | 139 | } // namespace Core |
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 8ce973a77..66f6107e9 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -6,6 +6,9 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | |||
| 10 | #include <dynarmic/interface/halt_reason.h> | ||
| 11 | |||
| 9 | #include "common/common_funcs.h" | 12 | #include "common/common_funcs.h" |
| 10 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 11 | #include "core/hardware_properties.h" | 14 | #include "core/hardware_properties.h" |
| @@ -64,10 +67,7 @@ public: | |||
| 64 | static_assert(sizeof(ThreadContext64) == 0x320); | 67 | static_assert(sizeof(ThreadContext64) == 0x320); |
| 65 | 68 | ||
| 66 | /// Runs the CPU until an event happens | 69 | /// Runs the CPU until an event happens |
| 67 | virtual void Run() = 0; | 70 | void Run(); |
| 68 | |||
| 69 | /// Step CPU by one instruction | ||
| 70 | virtual void Step() = 0; | ||
| 71 | 71 | ||
| 72 | /// Clear all instruction cache | 72 | /// Clear all instruction cache |
| 73 | virtual void ClearInstructionCache() = 0; | 73 | virtual void ClearInstructionCache() = 0; |
| @@ -194,6 +194,11 @@ public: | |||
| 194 | 194 | ||
| 195 | void LogBacktrace() const; | 195 | void LogBacktrace() const; |
| 196 | 196 | ||
| 197 | static constexpr Dynarmic::HaltReason step_thread = Dynarmic::HaltReason::Step; | ||
| 198 | static constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2; | ||
| 199 | static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3; | ||
| 200 | static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4; | ||
| 201 | |||
| 197 | protected: | 202 | protected: |
| 198 | /// System context that this ARM interface is running under. | 203 | /// System context that this ARM interface is running under. |
| 199 | System& system; | 204 | System& system; |
| @@ -201,6 +206,10 @@ protected: | |||
| 201 | bool uses_wall_clock; | 206 | bool uses_wall_clock; |
| 202 | 207 | ||
| 203 | static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out); | 208 | static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out); |
| 209 | |||
| 210 | virtual Dynarmic::HaltReason RunJit() = 0; | ||
| 211 | virtual Dynarmic::HaltReason StepJit() = 0; | ||
| 212 | virtual u32 GetSvcNumber() const = 0; | ||
| 204 | }; | 213 | }; |
| 205 | 214 | ||
| 206 | } // namespace Core | 215 | } // namespace Core |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 781a77f6f..7c82d0b96 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #include "core/arm/dynarmic/arm_exclusive_monitor.h" | 17 | #include "core/arm/dynarmic/arm_exclusive_monitor.h" |
| 18 | #include "core/core.h" | 18 | #include "core/core.h" |
| 19 | #include "core/core_timing.h" | 19 | #include "core/core_timing.h" |
| 20 | #include "core/debugger/debugger.h" | ||
| 21 | #include "core/hle/kernel/k_process.h" | ||
| 20 | #include "core/hle/kernel/svc.h" | 22 | #include "core/hle/kernel/svc.h" |
| 21 | #include "core/memory.h" | 23 | #include "core/memory.h" |
| 22 | 24 | ||
| @@ -24,9 +26,6 @@ namespace Core { | |||
| 24 | 26 | ||
| 25 | using namespace Common::Literals; | 27 | using namespace Common::Literals; |
| 26 | 28 | ||
| 27 | constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2; | ||
| 28 | constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3; | ||
| 29 | |||
| 30 | class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { | 29 | class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { |
| 31 | public: | 30 | public: |
| 32 | explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) | 31 | explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) |
| @@ -78,16 +77,21 @@ public: | |||
| 78 | } | 77 | } |
| 79 | 78 | ||
| 80 | void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { | 79 | void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { |
| 80 | if (parent.system.DebuggerEnabled()) { | ||
| 81 | parent.jit.load()->Regs()[15] = pc; | ||
| 82 | parent.jit.load()->HaltExecution(ARM_Interface::breakpoint); | ||
| 83 | return; | ||
| 84 | } | ||
| 85 | |||
| 81 | parent.LogBacktrace(); | 86 | parent.LogBacktrace(); |
| 82 | LOG_CRITICAL(Core_ARM, | 87 | LOG_CRITICAL(Core_ARM, |
| 83 | "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})", | 88 | "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})", |
| 84 | exception, pc, MemoryReadCode(pc), parent.IsInThumbMode()); | 89 | exception, pc, MemoryReadCode(pc), parent.IsInThumbMode()); |
| 85 | UNIMPLEMENTED(); | ||
| 86 | } | 90 | } |
| 87 | 91 | ||
| 88 | void CallSVC(u32 swi) override { | 92 | void CallSVC(u32 swi) override { |
| 89 | parent.svc_swi = swi; | 93 | parent.svc_swi = swi; |
| 90 | parent.jit.load()->HaltExecution(svc_call); | 94 | parent.jit.load()->HaltExecution(ARM_Interface::svc_call); |
| 91 | } | 95 | } |
| 92 | 96 | ||
| 93 | void AddTicks(u64 ticks) override { | 97 | void AddTicks(u64 ticks) override { |
| @@ -232,20 +236,16 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* | |||
| 232 | return std::make_unique<Dynarmic::A32::Jit>(config); | 236 | return std::make_unique<Dynarmic::A32::Jit>(config); |
| 233 | } | 237 | } |
| 234 | 238 | ||
| 235 | void ARM_Dynarmic_32::Run() { | 239 | Dynarmic::HaltReason ARM_Dynarmic_32::RunJit() { |
| 236 | while (true) { | 240 | return jit.load()->Run(); |
| 237 | const auto hr = jit.load()->Run(); | 241 | } |
| 238 | if (Has(hr, svc_call)) { | 242 | |
| 239 | Kernel::Svc::Call(system, svc_swi); | 243 | Dynarmic::HaltReason ARM_Dynarmic_32::StepJit() { |
| 240 | } | 244 | return jit.load()->Step(); |
| 241 | if (Has(hr, break_loop) || !uses_wall_clock) { | ||
| 242 | break; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | void ARM_Dynarmic_32::Step() { | 247 | u32 ARM_Dynarmic_32::GetSvcNumber() const { |
| 248 | jit.load()->Step(); | 248 | return svc_swi; |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, | 251 | ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index abfe76644..5b1d60005 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h | |||
| @@ -41,8 +41,6 @@ public: | |||
| 41 | void SetVectorReg(int index, u128 value) override; | 41 | void SetVectorReg(int index, u128 value) override; |
| 42 | u32 GetPSTATE() const override; | 42 | u32 GetPSTATE() const override; |
| 43 | void SetPSTATE(u32 pstate) override; | 43 | void SetPSTATE(u32 pstate) override; |
| 44 | void Run() override; | ||
| 45 | void Step() override; | ||
| 46 | VAddr GetTlsAddress() const override; | 44 | VAddr GetTlsAddress() const override; |
| 47 | void SetTlsAddress(VAddr address) override; | 45 | void SetTlsAddress(VAddr address) override; |
| 48 | void SetTPIDR_EL0(u64 value) override; | 46 | void SetTPIDR_EL0(u64 value) override; |
| @@ -70,6 +68,11 @@ public: | |||
| 70 | 68 | ||
| 71 | std::vector<BacktraceEntry> GetBacktrace() const override; | 69 | std::vector<BacktraceEntry> GetBacktrace() const override; |
| 72 | 70 | ||
| 71 | protected: | ||
| 72 | Dynarmic::HaltReason RunJit() override; | ||
| 73 | Dynarmic::HaltReason StepJit() override; | ||
| 74 | u32 GetSvcNumber() const override; | ||
| 75 | |||
| 73 | private: | 76 | private: |
| 74 | std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; | 77 | std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; |
| 75 | 78 | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 1b1334598..d4c67eafd 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "core/arm/dynarmic/arm_exclusive_monitor.h" | 15 | #include "core/arm/dynarmic/arm_exclusive_monitor.h" |
| 16 | #include "core/core.h" | 16 | #include "core/core.h" |
| 17 | #include "core/core_timing.h" | 17 | #include "core/core_timing.h" |
| 18 | #include "core/debugger/debugger.h" | ||
| 18 | #include "core/hardware_properties.h" | 19 | #include "core/hardware_properties.h" |
| 19 | #include "core/hle/kernel/k_process.h" | 20 | #include "core/hle/kernel/k_process.h" |
| 20 | #include "core/hle/kernel/svc.h" | 21 | #include "core/hle/kernel/svc.h" |
| @@ -25,9 +26,6 @@ namespace Core { | |||
| 25 | using Vector = Dynarmic::A64::Vector; | 26 | using Vector = Dynarmic::A64::Vector; |
| 26 | using namespace Common::Literals; | 27 | using namespace Common::Literals; |
| 27 | 28 | ||
| 28 | constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2; | ||
| 29 | constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3; | ||
| 30 | |||
| 31 | class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { | 29 | class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { |
| 32 | public: | 30 | public: |
| 33 | explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) | 31 | explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) |
| @@ -119,8 +117,13 @@ public: | |||
| 119 | case Dynarmic::A64::Exception::SendEventLocal: | 117 | case Dynarmic::A64::Exception::SendEventLocal: |
| 120 | case Dynarmic::A64::Exception::Yield: | 118 | case Dynarmic::A64::Exception::Yield: |
| 121 | return; | 119 | return; |
| 122 | case Dynarmic::A64::Exception::Breakpoint: | ||
| 123 | default: | 120 | default: |
| 121 | if (parent.system.DebuggerEnabled()) { | ||
| 122 | parent.jit.load()->SetPC(pc); | ||
| 123 | parent.jit.load()->HaltExecution(ARM_Interface::breakpoint); | ||
| 124 | return; | ||
| 125 | } | ||
| 126 | |||
| 124 | parent.LogBacktrace(); | 127 | parent.LogBacktrace(); |
| 125 | ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", | 128 | ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", |
| 126 | static_cast<std::size_t>(exception), pc, MemoryReadCode(pc)); | 129 | static_cast<std::size_t>(exception), pc, MemoryReadCode(pc)); |
| @@ -129,7 +132,7 @@ public: | |||
| 129 | 132 | ||
| 130 | void CallSVC(u32 swi) override { | 133 | void CallSVC(u32 swi) override { |
| 131 | parent.svc_swi = swi; | 134 | parent.svc_swi = swi; |
| 132 | parent.jit.load()->HaltExecution(svc_call); | 135 | parent.jit.load()->HaltExecution(ARM_Interface::svc_call); |
| 133 | } | 136 | } |
| 134 | 137 | ||
| 135 | void AddTicks(u64 ticks) override { | 138 | void AddTicks(u64 ticks) override { |
| @@ -293,20 +296,16 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* | |||
| 293 | return std::make_shared<Dynarmic::A64::Jit>(config); | 296 | return std::make_shared<Dynarmic::A64::Jit>(config); |
| 294 | } | 297 | } |
| 295 | 298 | ||
| 296 | void ARM_Dynarmic_64::Run() { | 299 | Dynarmic::HaltReason ARM_Dynarmic_64::RunJit() { |
| 297 | while (true) { | 300 | return jit.load()->Run(); |
| 298 | const auto hr = jit.load()->Run(); | 301 | } |
| 299 | if (Has(hr, svc_call)) { | 302 | |
| 300 | Kernel::Svc::Call(system, svc_swi); | 303 | Dynarmic::HaltReason ARM_Dynarmic_64::StepJit() { |
| 301 | } | 304 | return jit.load()->Step(); |
| 302 | if (Has(hr, break_loop) || !uses_wall_clock) { | ||
| 303 | break; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | } | 305 | } |
| 307 | 306 | ||
| 308 | void ARM_Dynarmic_64::Step() { | 307 | u32 ARM_Dynarmic_64::GetSvcNumber() const { |
| 309 | jit.load()->Step(); | 308 | return svc_swi; |
| 310 | } | 309 | } |
| 311 | 310 | ||
| 312 | ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, | 311 | ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 01a7e4dad..abfbc3c3f 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h | |||
| @@ -39,8 +39,6 @@ public: | |||
| 39 | void SetVectorReg(int index, u128 value) override; | 39 | void SetVectorReg(int index, u128 value) override; |
| 40 | u32 GetPSTATE() const override; | 40 | u32 GetPSTATE() const override; |
| 41 | void SetPSTATE(u32 pstate) override; | 41 | void SetPSTATE(u32 pstate) override; |
| 42 | void Run() override; | ||
| 43 | void Step() override; | ||
| 44 | VAddr GetTlsAddress() const override; | 42 | VAddr GetTlsAddress() const override; |
| 45 | void SetTlsAddress(VAddr address) override; | 43 | void SetTlsAddress(VAddr address) override; |
| 46 | void SetTPIDR_EL0(u64 value) override; | 44 | void SetTPIDR_EL0(u64 value) override; |
| @@ -64,6 +62,11 @@ public: | |||
| 64 | 62 | ||
| 65 | std::vector<BacktraceEntry> GetBacktrace() const override; | 63 | std::vector<BacktraceEntry> GetBacktrace() const override; |
| 66 | 64 | ||
| 65 | protected: | ||
| 66 | Dynarmic::HaltReason RunJit() override; | ||
| 67 | Dynarmic::HaltReason StepJit() override; | ||
| 68 | u32 GetSvcNumber() const override; | ||
| 69 | |||
| 67 | private: | 70 | private: |
| 68 | std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, | 71 | std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, |
| 69 | std::size_t address_space_bits) const; | 72 | std::size_t address_space_bits) const; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp index a043e6735..6aae79c48 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp | |||
| @@ -20,7 +20,7 @@ struct fmt::formatter<Dynarmic::A32::CoprocReg> { | |||
| 20 | } | 20 | } |
| 21 | template <typename FormatContext> | 21 | template <typename FormatContext> |
| 22 | auto format(const Dynarmic::A32::CoprocReg& reg, FormatContext& ctx) { | 22 | auto format(const Dynarmic::A32::CoprocReg& reg, FormatContext& ctx) { |
| 23 | return format_to(ctx.out(), "cp{}", static_cast<size_t>(reg)); | 23 | return fmt::format_to(ctx.out(), "cp{}", static_cast<size_t>(reg)); |
| 24 | } | 24 | } |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
diff --git a/src/core/arm/symbols.cpp b/src/core/arm/symbols.cpp index 4aa1a1ee1..0259c7ea2 100644 --- a/src/core/arm/symbols.cpp +++ b/src/core/arm/symbols.cpp | |||
| @@ -3,73 +3,14 @@ | |||
| 3 | 3 | ||
| 4 | #include "common/bit_field.h" | 4 | #include "common/bit_field.h" |
| 5 | #include "common/common_funcs.h" | 5 | #include "common/common_funcs.h" |
| 6 | #include "common/elf.h" | ||
| 6 | #include "core/arm/symbols.h" | 7 | #include "core/arm/symbols.h" |
| 7 | #include "core/core.h" | 8 | #include "core/core.h" |
| 8 | #include "core/memory.h" | 9 | #include "core/memory.h" |
| 9 | 10 | ||
| 10 | namespace Core { | 11 | using namespace Common::ELF; |
| 11 | namespace { | ||
| 12 | |||
| 13 | constexpr u64 ELF_DYNAMIC_TAG_NULL = 0; | ||
| 14 | constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5; | ||
| 15 | constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6; | ||
| 16 | constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11; | ||
| 17 | |||
| 18 | enum class ELFSymbolType : u8 { | ||
| 19 | None = 0, | ||
| 20 | Object = 1, | ||
| 21 | Function = 2, | ||
| 22 | Section = 3, | ||
| 23 | File = 4, | ||
| 24 | Common = 5, | ||
| 25 | TLS = 6, | ||
| 26 | }; | ||
| 27 | |||
| 28 | enum class ELFSymbolBinding : u8 { | ||
| 29 | Local = 0, | ||
| 30 | Global = 1, | ||
| 31 | Weak = 2, | ||
| 32 | }; | ||
| 33 | |||
| 34 | enum class ELFSymbolVisibility : u8 { | ||
| 35 | Default = 0, | ||
| 36 | Internal = 1, | ||
| 37 | Hidden = 2, | ||
| 38 | Protected = 3, | ||
| 39 | }; | ||
| 40 | |||
| 41 | struct ELF64Symbol { | ||
| 42 | u32 name_index; | ||
| 43 | union { | ||
| 44 | u8 info; | ||
| 45 | |||
| 46 | BitField<0, 4, ELFSymbolType> type; | ||
| 47 | BitField<4, 4, ELFSymbolBinding> binding; | ||
| 48 | }; | ||
| 49 | ELFSymbolVisibility visibility; | ||
| 50 | u16 sh_index; | ||
| 51 | u64 value; | ||
| 52 | u64 size; | ||
| 53 | }; | ||
| 54 | static_assert(sizeof(ELF64Symbol) == 0x18, "ELF64Symbol has incorrect size."); | ||
| 55 | |||
| 56 | struct ELF32Symbol { | ||
| 57 | u32 name_index; | ||
| 58 | u32 value; | ||
| 59 | u32 size; | ||
| 60 | union { | ||
| 61 | u8 info; | ||
| 62 | |||
| 63 | BitField<0, 4, ELFSymbolType> type; | ||
| 64 | BitField<4, 4, ELFSymbolBinding> binding; | ||
| 65 | }; | ||
| 66 | ELFSymbolVisibility visibility; | ||
| 67 | u16 sh_index; | ||
| 68 | }; | ||
| 69 | static_assert(sizeof(ELF32Symbol) == 0x10, "ELF32Symbol has incorrect size."); | ||
| 70 | |||
| 71 | } // Anonymous namespace | ||
| 72 | 12 | ||
| 13 | namespace Core { | ||
| 73 | namespace Symbols { | 14 | namespace Symbols { |
| 74 | 15 | ||
| 75 | template <typename Word, typename ELFSymbol, typename ByteReader> | 16 | template <typename Word, typename ELFSymbol, typename ByteReader> |
| @@ -110,15 +51,15 @@ static Symbols GetSymbols(ByteReader ReadBytes) { | |||
| 110 | const Word value = ReadWord(dynamic_index + sizeof(Word)); | 51 | const Word value = ReadWord(dynamic_index + sizeof(Word)); |
| 111 | dynamic_index += 2 * sizeof(Word); | 52 | dynamic_index += 2 * sizeof(Word); |
| 112 | 53 | ||
| 113 | if (tag == ELF_DYNAMIC_TAG_NULL) { | 54 | if (tag == ElfDtNull) { |
| 114 | break; | 55 | break; |
| 115 | } | 56 | } |
| 116 | 57 | ||
| 117 | if (tag == ELF_DYNAMIC_TAG_STRTAB) { | 58 | if (tag == ElfDtStrtab) { |
| 118 | string_table_offset = value; | 59 | string_table_offset = value; |
| 119 | } else if (tag == ELF_DYNAMIC_TAG_SYMTAB) { | 60 | } else if (tag == ElfDtSymtab) { |
| 120 | symbol_table_offset = value; | 61 | symbol_table_offset = value; |
| 121 | } else if (tag == ELF_DYNAMIC_TAG_SYMENT) { | 62 | } else if (tag == ElfDtSyment) { |
| 122 | symbol_entry_size = value; | 63 | symbol_entry_size = value; |
| 123 | } | 64 | } |
| 124 | } | 65 | } |
| @@ -134,14 +75,14 @@ static Symbols GetSymbols(ByteReader ReadBytes) { | |||
| 134 | ELFSymbol symbol{}; | 75 | ELFSymbol symbol{}; |
| 135 | ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol)); | 76 | ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol)); |
| 136 | 77 | ||
| 137 | VAddr string_offset = string_table_offset + symbol.name_index; | 78 | VAddr string_offset = string_table_offset + symbol.st_name; |
| 138 | std::string name; | 79 | std::string name; |
| 139 | for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) { | 80 | for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) { |
| 140 | name += static_cast<char>(c); | 81 | name += static_cast<char>(c); |
| 141 | } | 82 | } |
| 142 | 83 | ||
| 143 | symbol_index += symbol_entry_size; | 84 | symbol_index += symbol_entry_size; |
| 144 | out[name] = std::make_pair(symbol.value, symbol.size); | 85 | out[name] = std::make_pair(symbol.st_value, symbol.st_size); |
| 145 | } | 86 | } |
| 146 | 87 | ||
| 147 | return out; | 88 | return out; |
| @@ -152,9 +93,9 @@ Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64) { | |||
| 152 | [&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }}; | 93 | [&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }}; |
| 153 | 94 | ||
| 154 | if (is_64) { | 95 | if (is_64) { |
| 155 | return GetSymbols<u64, ELF64Symbol>(ReadBytes); | 96 | return GetSymbols<u64, Elf64_Sym>(ReadBytes); |
| 156 | } else { | 97 | } else { |
| 157 | return GetSymbols<u32, ELF32Symbol>(ReadBytes); | 98 | return GetSymbols<u32, Elf32_Sym>(ReadBytes); |
| 158 | } | 99 | } |
| 159 | } | 100 | } |
| 160 | 101 | ||
| @@ -164,9 +105,9 @@ Symbols GetSymbols(std::span<const u8> data, bool is_64) { | |||
| 164 | }}; | 105 | }}; |
| 165 | 106 | ||
| 166 | if (is_64) { | 107 | if (is_64) { |
| 167 | return GetSymbols<u64, ELF64Symbol>(ReadBytes); | 108 | return GetSymbols<u64, Elf64_Sym>(ReadBytes); |
| 168 | } else { | 109 | } else { |
| 169 | return GetSymbols<u32, ELF32Symbol>(ReadBytes); | 110 | return GetSymbols<u32, Elf32_Sym>(ReadBytes); |
| 170 | } | 111 | } |
| 171 | } | 112 | } |
| 172 | 113 | ||
diff --git a/src/core/core.cpp b/src/core/core.cpp index 8a887904d..954136adb 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include "core/core.h" | 17 | #include "core/core.h" |
| 18 | #include "core/core_timing.h" | 18 | #include "core/core_timing.h" |
| 19 | #include "core/cpu_manager.h" | 19 | #include "core/cpu_manager.h" |
| 20 | #include "core/debugger/debugger.h" | ||
| 20 | #include "core/device_memory.h" | 21 | #include "core/device_memory.h" |
| 21 | #include "core/file_sys/bis_factory.h" | 22 | #include "core/file_sys/bis_factory.h" |
| 22 | #include "core/file_sys/mode.h" | 23 | #include "core/file_sys/mode.h" |
| @@ -171,6 +172,10 @@ struct System::Impl { | |||
| 171 | } | 172 | } |
| 172 | } | 173 | } |
| 173 | 174 | ||
| 175 | void InitializeDebugger(System& system, u16 port) { | ||
| 176 | debugger = std::make_unique<Debugger>(system, port); | ||
| 177 | } | ||
| 178 | |||
| 174 | SystemResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { | 179 | SystemResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { |
| 175 | LOG_DEBUG(Core, "initialized OK"); | 180 | LOG_DEBUG(Core, "initialized OK"); |
| 176 | 181 | ||
| @@ -329,6 +334,7 @@ struct System::Impl { | |||
| 329 | gpu_core->NotifyShutdown(); | 334 | gpu_core->NotifyShutdown(); |
| 330 | } | 335 | } |
| 331 | 336 | ||
| 337 | debugger.reset(); | ||
| 332 | services.reset(); | 338 | services.reset(); |
| 333 | service_manager.reset(); | 339 | service_manager.reset(); |
| 334 | cheat_engine.reset(); | 340 | cheat_engine.reset(); |
| @@ -436,6 +442,9 @@ struct System::Impl { | |||
| 436 | /// Network instance | 442 | /// Network instance |
| 437 | Network::NetworkInstance network_instance; | 443 | Network::NetworkInstance network_instance; |
| 438 | 444 | ||
| 445 | /// Debugger | ||
| 446 | std::unique_ptr<Core::Debugger> debugger; | ||
| 447 | |||
| 439 | SystemResultStatus status = SystemResultStatus::Success; | 448 | SystemResultStatus status = SystemResultStatus::Success; |
| 440 | std::string status_details = ""; | 449 | std::string status_details = ""; |
| 441 | 450 | ||
| @@ -472,10 +481,6 @@ SystemResultStatus System::Pause() { | |||
| 472 | return impl->Pause(); | 481 | return impl->Pause(); |
| 473 | } | 482 | } |
| 474 | 483 | ||
| 475 | SystemResultStatus System::SingleStep() { | ||
| 476 | return SystemResultStatus::Success; | ||
| 477 | } | ||
| 478 | |||
| 479 | void System::InvalidateCpuInstructionCaches() { | 484 | void System::InvalidateCpuInstructionCaches() { |
| 480 | impl->kernel.InvalidateAllInstructionCaches(); | 485 | impl->kernel.InvalidateAllInstructionCaches(); |
| 481 | } | 486 | } |
| @@ -488,6 +493,12 @@ void System::Shutdown() { | |||
| 488 | impl->Shutdown(); | 493 | impl->Shutdown(); |
| 489 | } | 494 | } |
| 490 | 495 | ||
| 496 | void System::DetachDebugger() { | ||
| 497 | if (impl->debugger) { | ||
| 498 | impl->debugger->NotifyShutdown(); | ||
| 499 | } | ||
| 500 | } | ||
| 501 | |||
| 491 | std::unique_lock<std::mutex> System::StallCPU() { | 502 | std::unique_lock<std::mutex> System::StallCPU() { |
| 492 | return impl->StallCPU(); | 503 | return impl->StallCPU(); |
| 493 | } | 504 | } |
| @@ -496,6 +507,10 @@ void System::UnstallCPU() { | |||
| 496 | impl->UnstallCPU(); | 507 | impl->UnstallCPU(); |
| 497 | } | 508 | } |
| 498 | 509 | ||
| 510 | void System::InitializeDebugger() { | ||
| 511 | impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue()); | ||
| 512 | } | ||
| 513 | |||
| 499 | SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, | 514 | SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, |
| 500 | u64 program_id, std::size_t program_index) { | 515 | u64 program_id, std::size_t program_index) { |
| 501 | return impl->Load(*this, emu_window, filepath, program_id, program_index); | 516 | return impl->Load(*this, emu_window, filepath, program_id, program_index); |
| @@ -809,6 +824,18 @@ bool System::IsMulticore() const { | |||
| 809 | return impl->is_multicore; | 824 | return impl->is_multicore; |
| 810 | } | 825 | } |
| 811 | 826 | ||
| 827 | bool System::DebuggerEnabled() const { | ||
| 828 | return Settings::values.use_gdbstub.GetValue(); | ||
| 829 | } | ||
| 830 | |||
| 831 | Core::Debugger& System::GetDebugger() { | ||
| 832 | return *impl->debugger; | ||
| 833 | } | ||
| 834 | |||
| 835 | const Core::Debugger& System::GetDebugger() const { | ||
| 836 | return *impl->debugger; | ||
| 837 | } | ||
| 838 | |||
| 812 | void System::RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback) { | 839 | void System::RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback) { |
| 813 | impl->execute_program_callback = std::move(callback); | 840 | impl->execute_program_callback = std::move(callback); |
| 814 | } | 841 | } |
diff --git a/src/core/core.h b/src/core/core.h index 4a0c7dc84..5c367349e 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -97,6 +97,7 @@ namespace Core { | |||
| 97 | 97 | ||
| 98 | class ARM_Interface; | 98 | class ARM_Interface; |
| 99 | class CpuManager; | 99 | class CpuManager; |
| 100 | class Debugger; | ||
| 100 | class DeviceMemory; | 101 | class DeviceMemory; |
| 101 | class ExclusiveMonitor; | 102 | class ExclusiveMonitor; |
| 102 | class SpeedLimiter; | 103 | class SpeedLimiter; |
| @@ -148,12 +149,6 @@ public: | |||
| 148 | [[nodiscard]] SystemResultStatus Pause(); | 149 | [[nodiscard]] SystemResultStatus Pause(); |
| 149 | 150 | ||
| 150 | /** | 151 | /** |
| 151 | * Step the CPU one instruction | ||
| 152 | * @return Result status, indicating whether or not the operation succeeded. | ||
| 153 | */ | ||
| 154 | [[nodiscard]] SystemResultStatus SingleStep(); | ||
| 155 | |||
| 156 | /** | ||
| 157 | * Invalidate the CPU instruction caches | 152 | * Invalidate the CPU instruction caches |
| 158 | * This function should only be used by GDB Stub to support breakpoints, memory updates and | 153 | * This function should only be used by GDB Stub to support breakpoints, memory updates and |
| 159 | * step/continue commands. | 154 | * step/continue commands. |
| @@ -165,10 +160,18 @@ public: | |||
| 165 | /// Shutdown the emulated system. | 160 | /// Shutdown the emulated system. |
| 166 | void Shutdown(); | 161 | void Shutdown(); |
| 167 | 162 | ||
| 163 | /// Forcibly detach the debugger if it is running. | ||
| 164 | void DetachDebugger(); | ||
| 165 | |||
| 168 | std::unique_lock<std::mutex> StallCPU(); | 166 | std::unique_lock<std::mutex> StallCPU(); |
| 169 | void UnstallCPU(); | 167 | void UnstallCPU(); |
| 170 | 168 | ||
| 171 | /** | 169 | /** |
| 170 | * Initialize the debugger. | ||
| 171 | */ | ||
| 172 | void InitializeDebugger(); | ||
| 173 | |||
| 174 | /** | ||
| 172 | * Load an executable application. | 175 | * Load an executable application. |
| 173 | * @param emu_window Reference to the host-system window used for video output and keyboard | 176 | * @param emu_window Reference to the host-system window used for video output and keyboard |
| 174 | * input. | 177 | * input. |
| @@ -354,6 +357,9 @@ public: | |||
| 354 | [[nodiscard]] Service::Time::TimeManager& GetTimeManager(); | 357 | [[nodiscard]] Service::Time::TimeManager& GetTimeManager(); |
| 355 | [[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const; | 358 | [[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const; |
| 356 | 359 | ||
| 360 | [[nodiscard]] Core::Debugger& GetDebugger(); | ||
| 361 | [[nodiscard]] const Core::Debugger& GetDebugger() const; | ||
| 362 | |||
| 357 | void SetExitLock(bool locked); | 363 | void SetExitLock(bool locked); |
| 358 | [[nodiscard]] bool GetExitLock() const; | 364 | [[nodiscard]] bool GetExitLock() const; |
| 359 | 365 | ||
| @@ -375,6 +381,9 @@ public: | |||
| 375 | /// Tells if system is running on multicore. | 381 | /// Tells if system is running on multicore. |
| 376 | [[nodiscard]] bool IsMulticore() const; | 382 | [[nodiscard]] bool IsMulticore() const; |
| 377 | 383 | ||
| 384 | /// Tells if the system debugger is enabled. | ||
| 385 | [[nodiscard]] bool DebuggerEnabled() const; | ||
| 386 | |||
| 378 | /// Type used for the frontend to designate a callback for System to re-launch the application | 387 | /// Type used for the frontend to designate a callback for System to re-launch the application |
| 379 | /// using a specified program index. | 388 | /// using a specified program index. |
| 380 | using ExecuteProgramCallback = std::function<void(std::size_t)>; | 389 | using ExecuteProgramCallback = std::function<void(std::size_t)>; |
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 09d9c5163..132fe5b60 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp | |||
| @@ -16,7 +16,8 @@ | |||
| 16 | 16 | ||
| 17 | namespace Core { | 17 | namespace Core { |
| 18 | 18 | ||
| 19 | CpuManager::CpuManager(System& system_) : system{system_} {} | 19 | CpuManager::CpuManager(System& system_) |
| 20 | : pause_barrier{std::make_unique<Common::Barrier>(1)}, system{system_} {} | ||
| 20 | CpuManager::~CpuManager() = default; | 21 | CpuManager::~CpuManager() = default; |
| 21 | 22 | ||
| 22 | void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, | 23 | void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, |
| @@ -30,8 +31,10 @@ void CpuManager::Initialize() { | |||
| 30 | for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | 31 | for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { |
| 31 | core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core); | 32 | core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core); |
| 32 | } | 33 | } |
| 34 | pause_barrier = std::make_unique<Common::Barrier>(Core::Hardware::NUM_CPU_CORES + 1); | ||
| 33 | } else { | 35 | } else { |
| 34 | core_data[0].host_thread = std::jthread(ThreadStart, std::ref(*this), 0); | 36 | core_data[0].host_thread = std::jthread(ThreadStart, std::ref(*this), 0); |
| 37 | pause_barrier = std::make_unique<Common::Barrier>(2); | ||
| 35 | } | 38 | } |
| 36 | } | 39 | } |
| 37 | 40 | ||
| @@ -110,12 +113,10 @@ void CpuManager::MultiCoreRunGuestLoop() { | |||
| 110 | 113 | ||
| 111 | while (true) { | 114 | while (true) { |
| 112 | auto* physical_core = &kernel.CurrentPhysicalCore(); | 115 | auto* physical_core = &kernel.CurrentPhysicalCore(); |
| 113 | system.EnterDynarmicProfile(); | ||
| 114 | while (!physical_core->IsInterrupted()) { | 116 | while (!physical_core->IsInterrupted()) { |
| 115 | physical_core->Run(); | 117 | physical_core->Run(); |
| 116 | physical_core = &kernel.CurrentPhysicalCore(); | 118 | physical_core = &kernel.CurrentPhysicalCore(); |
| 117 | } | 119 | } |
| 118 | system.ExitDynarmicProfile(); | ||
| 119 | { | 120 | { |
| 120 | Kernel::KScopedDisableDispatch dd(kernel); | 121 | Kernel::KScopedDisableDispatch dd(kernel); |
| 121 | physical_core->ArmInterface().ClearExclusiveState(); | 122 | physical_core->ArmInterface().ClearExclusiveState(); |
| @@ -138,51 +139,14 @@ void CpuManager::MultiCoreRunSuspendThread() { | |||
| 138 | auto core = kernel.CurrentPhysicalCoreIndex(); | 139 | auto core = kernel.CurrentPhysicalCoreIndex(); |
| 139 | auto& scheduler = *kernel.CurrentScheduler(); | 140 | auto& scheduler = *kernel.CurrentScheduler(); |
| 140 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); | 141 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); |
| 142 | current_thread->DisableDispatch(); | ||
| 143 | |||
| 141 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); | 144 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); |
| 142 | ASSERT(scheduler.ContextSwitchPending()); | ||
| 143 | ASSERT(core == kernel.CurrentPhysicalCoreIndex()); | 145 | ASSERT(core == kernel.CurrentPhysicalCoreIndex()); |
| 144 | scheduler.RescheduleCurrentCore(); | 146 | scheduler.RescheduleCurrentCore(); |
| 145 | } | 147 | } |
| 146 | } | 148 | } |
| 147 | 149 | ||
| 148 | void CpuManager::MultiCorePause(bool paused) { | ||
| 149 | if (!paused) { | ||
| 150 | bool all_not_barrier = false; | ||
| 151 | while (!all_not_barrier) { | ||
| 152 | all_not_barrier = true; | ||
| 153 | for (const auto& data : core_data) { | ||
| 154 | all_not_barrier &= !data.is_running.load() && data.initialized.load(); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | for (auto& data : core_data) { | ||
| 158 | data.enter_barrier->Set(); | ||
| 159 | } | ||
| 160 | if (paused_state.load()) { | ||
| 161 | bool all_barrier = false; | ||
| 162 | while (!all_barrier) { | ||
| 163 | all_barrier = true; | ||
| 164 | for (const auto& data : core_data) { | ||
| 165 | all_barrier &= data.is_paused.load() && data.initialized.load(); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | for (auto& data : core_data) { | ||
| 169 | data.exit_barrier->Set(); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | } else { | ||
| 173 | /// Wait until all cores are paused. | ||
| 174 | bool all_barrier = false; | ||
| 175 | while (!all_barrier) { | ||
| 176 | all_barrier = true; | ||
| 177 | for (const auto& data : core_data) { | ||
| 178 | all_barrier &= data.is_paused.load() && data.initialized.load(); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | /// Don't release the barrier | ||
| 182 | } | ||
| 183 | paused_state = paused; | ||
| 184 | } | ||
| 185 | |||
| 186 | /////////////////////////////////////////////////////////////////////////////// | 150 | /////////////////////////////////////////////////////////////////////////////// |
| 187 | /// SingleCore /// | 151 | /// SingleCore /// |
| 188 | /////////////////////////////////////////////////////////////////////////////// | 152 | /////////////////////////////////////////////////////////////////////////////// |
| @@ -200,12 +164,10 @@ void CpuManager::SingleCoreRunGuestLoop() { | |||
| 200 | auto& kernel = system.Kernel(); | 164 | auto& kernel = system.Kernel(); |
| 201 | while (true) { | 165 | while (true) { |
| 202 | auto* physical_core = &kernel.CurrentPhysicalCore(); | 166 | auto* physical_core = &kernel.CurrentPhysicalCore(); |
| 203 | system.EnterDynarmicProfile(); | ||
| 204 | if (!physical_core->IsInterrupted()) { | 167 | if (!physical_core->IsInterrupted()) { |
| 205 | physical_core->Run(); | 168 | physical_core->Run(); |
| 206 | physical_core = &kernel.CurrentPhysicalCore(); | 169 | physical_core = &kernel.CurrentPhysicalCore(); |
| 207 | } | 170 | } |
| 208 | system.ExitDynarmicProfile(); | ||
| 209 | kernel.SetIsPhantomModeForSingleCore(true); | 171 | kernel.SetIsPhantomModeForSingleCore(true); |
| 210 | system.CoreTiming().Advance(); | 172 | system.CoreTiming().Advance(); |
| 211 | kernel.SetIsPhantomModeForSingleCore(false); | 173 | kernel.SetIsPhantomModeForSingleCore(false); |
| @@ -235,8 +197,9 @@ void CpuManager::SingleCoreRunSuspendThread() { | |||
| 235 | auto core = kernel.GetCurrentHostThreadID(); | 197 | auto core = kernel.GetCurrentHostThreadID(); |
| 236 | auto& scheduler = *kernel.CurrentScheduler(); | 198 | auto& scheduler = *kernel.CurrentScheduler(); |
| 237 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); | 199 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); |
| 200 | current_thread->DisableDispatch(); | ||
| 201 | |||
| 238 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context); | 202 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context); |
| 239 | ASSERT(scheduler.ContextSwitchPending()); | ||
| 240 | ASSERT(core == kernel.GetCurrentHostThreadID()); | 203 | ASSERT(core == kernel.GetCurrentHostThreadID()); |
| 241 | scheduler.RescheduleCurrentCore(); | 204 | scheduler.RescheduleCurrentCore(); |
| 242 | } | 205 | } |
| @@ -274,37 +237,21 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) { | |||
| 274 | } | 237 | } |
| 275 | } | 238 | } |
| 276 | 239 | ||
| 277 | void CpuManager::SingleCorePause(bool paused) { | ||
| 278 | if (!paused) { | ||
| 279 | bool all_not_barrier = false; | ||
| 280 | while (!all_not_barrier) { | ||
| 281 | all_not_barrier = !core_data[0].is_running.load() && core_data[0].initialized.load(); | ||
| 282 | } | ||
| 283 | core_data[0].enter_barrier->Set(); | ||
| 284 | if (paused_state.load()) { | ||
| 285 | bool all_barrier = false; | ||
| 286 | while (!all_barrier) { | ||
| 287 | all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load(); | ||
| 288 | } | ||
| 289 | core_data[0].exit_barrier->Set(); | ||
| 290 | } | ||
| 291 | } else { | ||
| 292 | /// Wait until all cores are paused. | ||
| 293 | bool all_barrier = false; | ||
| 294 | while (!all_barrier) { | ||
| 295 | all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load(); | ||
| 296 | } | ||
| 297 | /// Don't release the barrier | ||
| 298 | } | ||
| 299 | paused_state = paused; | ||
| 300 | } | ||
| 301 | |||
| 302 | void CpuManager::Pause(bool paused) { | 240 | void CpuManager::Pause(bool paused) { |
| 303 | if (is_multicore) { | 241 | std::scoped_lock lk{pause_lock}; |
| 304 | MultiCorePause(paused); | 242 | |
| 305 | } else { | 243 | if (pause_state == paused) { |
| 306 | SingleCorePause(paused); | 244 | return; |
| 307 | } | 245 | } |
| 246 | |||
| 247 | // Set the new state | ||
| 248 | pause_state.store(paused); | ||
| 249 | |||
| 250 | // Wake up any waiting threads | ||
| 251 | pause_state.notify_all(); | ||
| 252 | |||
| 253 | // Wait for all threads to successfully change state before returning | ||
| 254 | pause_barrier->Sync(); | ||
| 308 | } | 255 | } |
| 309 | 256 | ||
| 310 | void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { | 257 | void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { |
| @@ -320,27 +267,29 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { | |||
| 320 | Common::SetCurrentThreadName(name.c_str()); | 267 | Common::SetCurrentThreadName(name.c_str()); |
| 321 | Common::SetCurrentThreadPriority(Common::ThreadPriority::High); | 268 | Common::SetCurrentThreadPriority(Common::ThreadPriority::High); |
| 322 | auto& data = core_data[core]; | 269 | auto& data = core_data[core]; |
| 323 | data.enter_barrier = std::make_unique<Common::Event>(); | ||
| 324 | data.exit_barrier = std::make_unique<Common::Event>(); | ||
| 325 | data.host_context = Common::Fiber::ThreadToFiber(); | 270 | data.host_context = Common::Fiber::ThreadToFiber(); |
| 326 | data.is_running = false; | ||
| 327 | data.initialized = true; | ||
| 328 | const bool sc_sync = !is_async_gpu && !is_multicore; | 271 | const bool sc_sync = !is_async_gpu && !is_multicore; |
| 329 | bool sc_sync_first_use = sc_sync; | 272 | bool sc_sync_first_use = sc_sync; |
| 330 | 273 | ||
| 331 | // Cleanup | 274 | // Cleanup |
| 332 | SCOPE_EXIT({ | 275 | SCOPE_EXIT({ |
| 333 | data.host_context->Exit(); | 276 | data.host_context->Exit(); |
| 334 | data.enter_barrier.reset(); | ||
| 335 | data.exit_barrier.reset(); | ||
| 336 | data.initialized = false; | ||
| 337 | MicroProfileOnThreadExit(); | 277 | MicroProfileOnThreadExit(); |
| 338 | }); | 278 | }); |
| 339 | 279 | ||
| 340 | /// Running | 280 | /// Running |
| 341 | while (running_mode) { | 281 | while (running_mode) { |
| 342 | data.is_running = false; | 282 | if (pause_state.load(std::memory_order_relaxed)) { |
| 343 | data.enter_barrier->Wait(); | 283 | // Wait for caller to acknowledge pausing |
| 284 | pause_barrier->Sync(); | ||
| 285 | |||
| 286 | // Wait until unpaused | ||
| 287 | pause_state.wait(true, std::memory_order_relaxed); | ||
| 288 | |||
| 289 | // Wait for caller to acknowledge unpausing | ||
| 290 | pause_barrier->Sync(); | ||
| 291 | } | ||
| 292 | |||
| 344 | if (sc_sync_first_use) { | 293 | if (sc_sync_first_use) { |
| 345 | system.GPU().ObtainContext(); | 294 | system.GPU().ObtainContext(); |
| 346 | sc_sync_first_use = false; | 295 | sc_sync_first_use = false; |
| @@ -352,12 +301,7 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { | |||
| 352 | } | 301 | } |
| 353 | 302 | ||
| 354 | auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | 303 | auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); |
| 355 | data.is_running = true; | ||
| 356 | Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); | 304 | Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); |
| 357 | data.is_running = false; | ||
| 358 | data.is_paused = true; | ||
| 359 | data.exit_barrier->Wait(); | ||
| 360 | data.is_paused = false; | ||
| 361 | } | 305 | } |
| 362 | } | 306 | } |
| 363 | 307 | ||
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index aee352245..ddd9691ca 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h | |||
| @@ -69,13 +69,11 @@ private: | |||
| 69 | void MultiCoreRunGuestLoop(); | 69 | void MultiCoreRunGuestLoop(); |
| 70 | void MultiCoreRunIdleThread(); | 70 | void MultiCoreRunIdleThread(); |
| 71 | void MultiCoreRunSuspendThread(); | 71 | void MultiCoreRunSuspendThread(); |
| 72 | void MultiCorePause(bool paused); | ||
| 73 | 72 | ||
| 74 | void SingleCoreRunGuestThread(); | 73 | void SingleCoreRunGuestThread(); |
| 75 | void SingleCoreRunGuestLoop(); | 74 | void SingleCoreRunGuestLoop(); |
| 76 | void SingleCoreRunIdleThread(); | 75 | void SingleCoreRunIdleThread(); |
| 77 | void SingleCoreRunSuspendThread(); | 76 | void SingleCoreRunSuspendThread(); |
| 78 | void SingleCorePause(bool paused); | ||
| 79 | 77 | ||
| 80 | static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core); | 78 | static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core); |
| 81 | 79 | ||
| @@ -83,16 +81,13 @@ private: | |||
| 83 | 81 | ||
| 84 | struct CoreData { | 82 | struct CoreData { |
| 85 | std::shared_ptr<Common::Fiber> host_context; | 83 | std::shared_ptr<Common::Fiber> host_context; |
| 86 | std::unique_ptr<Common::Event> enter_barrier; | ||
| 87 | std::unique_ptr<Common::Event> exit_barrier; | ||
| 88 | std::atomic<bool> is_running; | ||
| 89 | std::atomic<bool> is_paused; | ||
| 90 | std::atomic<bool> initialized; | ||
| 91 | std::jthread host_thread; | 84 | std::jthread host_thread; |
| 92 | }; | 85 | }; |
| 93 | 86 | ||
| 94 | std::atomic<bool> running_mode{}; | 87 | std::atomic<bool> running_mode{}; |
| 95 | std::atomic<bool> paused_state{}; | 88 | std::atomic<bool> pause_state{}; |
| 89 | std::unique_ptr<Common::Barrier> pause_barrier{}; | ||
| 90 | std::mutex pause_lock{}; | ||
| 96 | 91 | ||
| 97 | std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{}; | 92 | std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{}; |
| 98 | 93 | ||
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index e3c4f80eb..443323390 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -140,7 +140,6 @@ u64 GetSignatureTypeDataSize(SignatureType type) { | |||
| 140 | return 0x3C; | 140 | return 0x3C; |
| 141 | } | 141 | } |
| 142 | UNREACHABLE(); | 142 | UNREACHABLE(); |
| 143 | return 0; | ||
| 144 | } | 143 | } |
| 145 | 144 | ||
| 146 | u64 GetSignatureTypePaddingSize(SignatureType type) { | 145 | u64 GetSignatureTypePaddingSize(SignatureType type) { |
| @@ -155,7 +154,6 @@ u64 GetSignatureTypePaddingSize(SignatureType type) { | |||
| 155 | return 0x40; | 154 | return 0x40; |
| 156 | } | 155 | } |
| 157 | UNREACHABLE(); | 156 | UNREACHABLE(); |
| 158 | return 0; | ||
| 159 | } | 157 | } |
| 160 | 158 | ||
| 161 | SignatureType Ticket::GetSignatureType() const { | 159 | SignatureType Ticket::GetSignatureType() const { |
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp new file mode 100644 index 000000000..edf991d71 --- /dev/null +++ b/src/core/debugger/debugger.cpp | |||
| @@ -0,0 +1,310 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <mutex> | ||
| 6 | #include <thread> | ||
| 7 | |||
| 8 | #include <boost/asio.hpp> | ||
| 9 | #include <boost/process/async_pipe.hpp> | ||
| 10 | |||
| 11 | #include "common/logging/log.h" | ||
| 12 | #include "common/thread.h" | ||
| 13 | #include "core/core.h" | ||
| 14 | #include "core/debugger/debugger.h" | ||
| 15 | #include "core/debugger/debugger_interface.h" | ||
| 16 | #include "core/debugger/gdbstub.h" | ||
| 17 | #include "core/hle/kernel/global_scheduler_context.h" | ||
| 18 | |||
| 19 | template <typename Readable, typename Buffer, typename Callback> | ||
| 20 | static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) { | ||
| 21 | static_assert(std::is_trivial_v<Buffer>); | ||
| 22 | auto boost_buffer{boost::asio::buffer(&buffer, sizeof(Buffer))}; | ||
| 23 | r.async_read_some( | ||
| 24 | boost_buffer, [&, c](const boost::system::error_code& error, size_t bytes_read) { | ||
| 25 | if (!error.failed()) { | ||
| 26 | const u8* buffer_start = reinterpret_cast<const u8*>(&buffer); | ||
| 27 | std::span<const u8> received_data{buffer_start, buffer_start + bytes_read}; | ||
| 28 | c(received_data); | ||
| 29 | } | ||
| 30 | |||
| 31 | AsyncReceiveInto(r, buffer, c); | ||
| 32 | }); | ||
| 33 | } | ||
| 34 | |||
| 35 | template <typename Readable, typename Buffer> | ||
| 36 | static std::span<const u8> ReceiveInto(Readable& r, Buffer& buffer) { | ||
| 37 | static_assert(std::is_trivial_v<Buffer>); | ||
| 38 | auto boost_buffer{boost::asio::buffer(&buffer, sizeof(Buffer))}; | ||
| 39 | size_t bytes_read = r.read_some(boost_buffer); | ||
| 40 | const u8* buffer_start = reinterpret_cast<const u8*>(&buffer); | ||
| 41 | std::span<const u8> received_data{buffer_start, buffer_start + bytes_read}; | ||
| 42 | return received_data; | ||
| 43 | } | ||
| 44 | |||
| 45 | enum class SignalType { | ||
| 46 | Stopped, | ||
| 47 | ShuttingDown, | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct SignalInfo { | ||
| 51 | SignalType type; | ||
| 52 | Kernel::KThread* thread; | ||
| 53 | }; | ||
| 54 | |||
| 55 | namespace Core { | ||
| 56 | |||
| 57 | class DebuggerImpl : public DebuggerBackend { | ||
| 58 | public: | ||
| 59 | explicit DebuggerImpl(Core::System& system_, u16 port) | ||
| 60 | : system{system_}, signal_pipe{io_context}, client_socket{io_context} { | ||
| 61 | frontend = std::make_unique<GDBStub>(*this, system); | ||
| 62 | InitializeServer(port); | ||
| 63 | } | ||
| 64 | |||
| 65 | ~DebuggerImpl() override { | ||
| 66 | ShutdownServer(); | ||
| 67 | } | ||
| 68 | |||
| 69 | bool SignalDebugger(SignalInfo signal_info) { | ||
| 70 | std::scoped_lock lk{connection_lock}; | ||
| 71 | |||
| 72 | if (stopped) { | ||
| 73 | // Do not notify the debugger about another event. | ||
| 74 | // It should be ignored. | ||
| 75 | return false; | ||
| 76 | } | ||
| 77 | |||
| 78 | // Set up the state. | ||
| 79 | stopped = true; | ||
| 80 | info = signal_info; | ||
| 81 | |||
| 82 | // Write a single byte into the pipe to wake up the debug interface. | ||
| 83 | boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped))); | ||
| 84 | return true; | ||
| 85 | } | ||
| 86 | |||
| 87 | std::span<const u8> ReadFromClient() override { | ||
| 88 | return ReceiveInto(client_socket, client_data); | ||
| 89 | } | ||
| 90 | |||
| 91 | void WriteToClient(std::span<const u8> data) override { | ||
| 92 | boost::asio::write(client_socket, boost::asio::buffer(data.data(), data.size_bytes())); | ||
| 93 | } | ||
| 94 | |||
| 95 | void SetActiveThread(Kernel::KThread* thread) override { | ||
| 96 | active_thread = thread; | ||
| 97 | } | ||
| 98 | |||
| 99 | Kernel::KThread* GetActiveThread() override { | ||
| 100 | return active_thread; | ||
| 101 | } | ||
| 102 | |||
| 103 | private: | ||
| 104 | void InitializeServer(u16 port) { | ||
| 105 | using boost::asio::ip::tcp; | ||
| 106 | |||
| 107 | LOG_INFO(Debug_GDBStub, "Starting server on port {}...", port); | ||
| 108 | |||
| 109 | // Run the connection thread. | ||
| 110 | connection_thread = std::jthread([&, port](std::stop_token stop_token) { | ||
| 111 | try { | ||
| 112 | // Initialize the listening socket and accept a new client. | ||
| 113 | tcp::endpoint endpoint{boost::asio::ip::address_v4::any(), port}; | ||
| 114 | tcp::acceptor acceptor{io_context, endpoint}; | ||
| 115 | |||
| 116 | acceptor.async_accept(client_socket, [](const auto&) {}); | ||
| 117 | io_context.run_one(); | ||
| 118 | io_context.restart(); | ||
| 119 | |||
| 120 | if (stop_token.stop_requested()) { | ||
| 121 | return; | ||
| 122 | } | ||
| 123 | |||
| 124 | ThreadLoop(stop_token); | ||
| 125 | } catch (const std::exception& ex) { | ||
| 126 | LOG_CRITICAL(Debug_GDBStub, "Stopping server: {}", ex.what()); | ||
| 127 | } | ||
| 128 | }); | ||
| 129 | } | ||
| 130 | |||
| 131 | void ShutdownServer() { | ||
| 132 | connection_thread.request_stop(); | ||
| 133 | io_context.stop(); | ||
| 134 | connection_thread.join(); | ||
| 135 | } | ||
| 136 | |||
| 137 | void ThreadLoop(std::stop_token stop_token) { | ||
| 138 | Common::SetCurrentThreadName("yuzu:Debugger"); | ||
| 139 | |||
| 140 | // Set up the client signals for new data. | ||
| 141 | AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); }); | ||
| 142 | AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); }); | ||
| 143 | |||
| 144 | // Stop the emulated CPU. | ||
| 145 | AllCoreStop(); | ||
| 146 | |||
| 147 | // Set the active thread. | ||
| 148 | UpdateActiveThread(); | ||
| 149 | |||
| 150 | // Set up the frontend. | ||
| 151 | frontend->Connected(); | ||
| 152 | |||
| 153 | // Main event loop. | ||
| 154 | while (!stop_token.stop_requested() && io_context.run()) { | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | void PipeData(std::span<const u8> data) { | ||
| 159 | switch (info.type) { | ||
| 160 | case SignalType::Stopped: | ||
| 161 | // Stop emulation. | ||
| 162 | AllCoreStop(); | ||
| 163 | |||
| 164 | // Notify the client. | ||
| 165 | active_thread = info.thread; | ||
| 166 | UpdateActiveThread(); | ||
| 167 | frontend->Stopped(active_thread); | ||
| 168 | |||
| 169 | break; | ||
| 170 | case SignalType::ShuttingDown: | ||
| 171 | frontend->ShuttingDown(); | ||
| 172 | |||
| 173 | // Wait for emulation to shut down gracefully now. | ||
| 174 | suspend.reset(); | ||
| 175 | signal_pipe.close(); | ||
| 176 | client_socket.shutdown(boost::asio::socket_base::shutdown_both); | ||
| 177 | LOG_INFO(Debug_GDBStub, "Shut down server"); | ||
| 178 | |||
| 179 | break; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | void ClientData(std::span<const u8> data) { | ||
| 184 | const auto actions{frontend->ClientData(data)}; | ||
| 185 | for (const auto action : actions) { | ||
| 186 | switch (action) { | ||
| 187 | case DebuggerAction::Interrupt: { | ||
| 188 | { | ||
| 189 | std::scoped_lock lk{connection_lock}; | ||
| 190 | stopped = true; | ||
| 191 | } | ||
| 192 | AllCoreStop(); | ||
| 193 | UpdateActiveThread(); | ||
| 194 | frontend->Stopped(active_thread); | ||
| 195 | break; | ||
| 196 | } | ||
| 197 | case DebuggerAction::Continue: | ||
| 198 | active_thread->SetStepState(Kernel::StepState::NotStepping); | ||
| 199 | ResumeInactiveThreads(); | ||
| 200 | AllCoreResume(); | ||
| 201 | break; | ||
| 202 | case DebuggerAction::StepThreadUnlocked: | ||
| 203 | active_thread->SetStepState(Kernel::StepState::StepPending); | ||
| 204 | ResumeInactiveThreads(); | ||
| 205 | AllCoreResume(); | ||
| 206 | break; | ||
| 207 | case DebuggerAction::StepThreadLocked: | ||
| 208 | active_thread->SetStepState(Kernel::StepState::StepPending); | ||
| 209 | SuspendInactiveThreads(); | ||
| 210 | AllCoreResume(); | ||
| 211 | break; | ||
| 212 | case DebuggerAction::ShutdownEmulation: { | ||
| 213 | // Suspend all threads and release any locks held | ||
| 214 | active_thread->RequestSuspend(Kernel::SuspendType::Debug); | ||
| 215 | SuspendInactiveThreads(); | ||
| 216 | AllCoreResume(); | ||
| 217 | |||
| 218 | // Spawn another thread that will exit after shutdown, | ||
| 219 | // to avoid a deadlock | ||
| 220 | Core::System* system_ref{&system}; | ||
| 221 | std::thread t([system_ref] { system_ref->Exit(); }); | ||
| 222 | t.detach(); | ||
| 223 | break; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | void AllCoreStop() { | ||
| 230 | if (!suspend) { | ||
| 231 | suspend = system.StallCPU(); | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | void AllCoreResume() { | ||
| 236 | stopped = false; | ||
| 237 | system.UnstallCPU(); | ||
| 238 | suspend.reset(); | ||
| 239 | } | ||
| 240 | |||
| 241 | void SuspendInactiveThreads() { | ||
| 242 | for (auto* thread : ThreadList()) { | ||
| 243 | if (thread != active_thread) { | ||
| 244 | thread->RequestSuspend(Kernel::SuspendType::Debug); | ||
| 245 | } | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | void ResumeInactiveThreads() { | ||
| 250 | for (auto* thread : ThreadList()) { | ||
| 251 | if (thread != active_thread) { | ||
| 252 | thread->Resume(Kernel::SuspendType::Debug); | ||
| 253 | thread->SetStepState(Kernel::StepState::NotStepping); | ||
| 254 | } | ||
| 255 | } | ||
| 256 | } | ||
| 257 | |||
| 258 | void UpdateActiveThread() { | ||
| 259 | const auto& threads{ThreadList()}; | ||
| 260 | if (std::find(threads.begin(), threads.end(), active_thread) == threads.end()) { | ||
| 261 | active_thread = threads[0]; | ||
| 262 | } | ||
| 263 | active_thread->Resume(Kernel::SuspendType::Debug); | ||
| 264 | active_thread->SetStepState(Kernel::StepState::NotStepping); | ||
| 265 | } | ||
| 266 | |||
| 267 | const std::vector<Kernel::KThread*>& ThreadList() { | ||
| 268 | return system.GlobalSchedulerContext().GetThreadList(); | ||
| 269 | } | ||
| 270 | |||
| 271 | private: | ||
| 272 | System& system; | ||
| 273 | std::unique_ptr<DebuggerFrontend> frontend; | ||
| 274 | |||
| 275 | std::jthread connection_thread; | ||
| 276 | std::mutex connection_lock; | ||
| 277 | boost::asio::io_context io_context; | ||
| 278 | boost::process::async_pipe signal_pipe; | ||
| 279 | boost::asio::ip::tcp::socket client_socket; | ||
| 280 | std::optional<std::unique_lock<std::mutex>> suspend; | ||
| 281 | |||
| 282 | SignalInfo info; | ||
| 283 | Kernel::KThread* active_thread; | ||
| 284 | bool pipe_data; | ||
| 285 | bool stopped; | ||
| 286 | |||
| 287 | std::array<u8, 4096> client_data; | ||
| 288 | }; | ||
| 289 | |||
| 290 | Debugger::Debugger(Core::System& system, u16 port) { | ||
| 291 | try { | ||
| 292 | impl = std::make_unique<DebuggerImpl>(system, port); | ||
| 293 | } catch (const std::exception& ex) { | ||
| 294 | LOG_CRITICAL(Debug_GDBStub, "Failed to initialize debugger: {}", ex.what()); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | Debugger::~Debugger() = default; | ||
| 299 | |||
| 300 | bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) { | ||
| 301 | return impl && impl->SignalDebugger(SignalInfo{SignalType::Stopped, thread}); | ||
| 302 | } | ||
| 303 | |||
| 304 | void Debugger::NotifyShutdown() { | ||
| 305 | if (impl) { | ||
| 306 | impl->SignalDebugger(SignalInfo{SignalType::ShuttingDown, nullptr}); | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | } // namespace Core | ||
diff --git a/src/core/debugger/debugger.h b/src/core/debugger/debugger.h new file mode 100644 index 000000000..f9738ca3d --- /dev/null +++ b/src/core/debugger/debugger.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | class KThread; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Core { | ||
| 15 | class System; | ||
| 16 | |||
| 17 | class DebuggerImpl; | ||
| 18 | |||
| 19 | class Debugger { | ||
| 20 | public: | ||
| 21 | /** | ||
| 22 | * Blocks and waits for a connection on localhost, port `server_port`. | ||
| 23 | * Does not create the debugger if the port is already in use. | ||
| 24 | */ | ||
| 25 | explicit Debugger(Core::System& system, u16 server_port); | ||
| 26 | ~Debugger(); | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Notify the debugger that the given thread is stopped | ||
| 30 | * (due to a breakpoint, or due to stopping after a successful step). | ||
| 31 | * | ||
| 32 | * The debugger will asynchronously halt emulation after the notification has | ||
| 33 | * occurred. If another thread attempts to notify before emulation has stopped, | ||
| 34 | * it is ignored and this method will return false. Otherwise it will return true. | ||
| 35 | */ | ||
| 36 | bool NotifyThreadStopped(Kernel::KThread* thread); | ||
| 37 | |||
| 38 | /** | ||
| 39 | * Notify the debugger that a shutdown is being performed now and disconnect. | ||
| 40 | */ | ||
| 41 | void NotifyShutdown(); | ||
| 42 | |||
| 43 | private: | ||
| 44 | std::unique_ptr<DebuggerImpl> impl; | ||
| 45 | }; | ||
| 46 | } // namespace Core | ||
diff --git a/src/core/debugger/debugger_interface.h b/src/core/debugger/debugger_interface.h new file mode 100644 index 000000000..c0bb4ecaf --- /dev/null +++ b/src/core/debugger/debugger_interface.h | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <functional> | ||
| 7 | #include <span> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | class KThread; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Core { | ||
| 17 | |||
| 18 | enum class DebuggerAction { | ||
| 19 | Interrupt, ///< Stop emulation as soon as possible. | ||
| 20 | Continue, ///< Resume emulation. | ||
| 21 | StepThreadLocked, ///< Step the currently-active thread without resuming others. | ||
| 22 | StepThreadUnlocked, ///< Step the currently-active thread and resume others. | ||
| 23 | ShutdownEmulation, ///< Shut down the emulator. | ||
| 24 | }; | ||
| 25 | |||
| 26 | class DebuggerBackend { | ||
| 27 | public: | ||
| 28 | virtual ~DebuggerBackend() = default; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Can be invoked from a callback to synchronously wait for more data. | ||
| 32 | * Will return as soon as least one byte is received. Reads up to 4096 bytes. | ||
| 33 | */ | ||
| 34 | virtual std::span<const u8> ReadFromClient() = 0; | ||
| 35 | |||
| 36 | /** | ||
| 37 | * Can be invoked from a callback to write data to the client. | ||
| 38 | * Returns immediately after the data is sent. | ||
| 39 | */ | ||
| 40 | virtual void WriteToClient(std::span<const u8> data) = 0; | ||
| 41 | |||
| 42 | /** | ||
| 43 | * Gets the currently active thread when the debugger is stopped. | ||
| 44 | */ | ||
| 45 | virtual Kernel::KThread* GetActiveThread() = 0; | ||
| 46 | |||
| 47 | /** | ||
| 48 | * Sets the currently active thread when the debugger is stopped. | ||
| 49 | */ | ||
| 50 | virtual void SetActiveThread(Kernel::KThread* thread) = 0; | ||
| 51 | }; | ||
| 52 | |||
| 53 | class DebuggerFrontend { | ||
| 54 | public: | ||
| 55 | explicit DebuggerFrontend(DebuggerBackend& backend_) : backend{backend_} {} | ||
| 56 | |||
| 57 | virtual ~DebuggerFrontend() = default; | ||
| 58 | |||
| 59 | /** | ||
| 60 | * Called after the client has successfully connected to the port. | ||
| 61 | */ | ||
| 62 | virtual void Connected() = 0; | ||
| 63 | |||
| 64 | /** | ||
| 65 | * Called when emulation has stopped. | ||
| 66 | */ | ||
| 67 | virtual void Stopped(Kernel::KThread* thread) = 0; | ||
| 68 | |||
| 69 | /** | ||
| 70 | * Called when emulation is shutting down. | ||
| 71 | */ | ||
| 72 | virtual void ShuttingDown() = 0; | ||
| 73 | |||
| 74 | /** | ||
| 75 | * Called when new data is asynchronously received on the client socket. | ||
| 76 | * A list of actions to perform is returned. | ||
| 77 | */ | ||
| 78 | [[nodiscard]] virtual std::vector<DebuggerAction> ClientData(std::span<const u8> data) = 0; | ||
| 79 | |||
| 80 | protected: | ||
| 81 | DebuggerBackend& backend; | ||
| 82 | }; | ||
| 83 | |||
| 84 | } // namespace Core | ||
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp new file mode 100644 index 000000000..52e76f659 --- /dev/null +++ b/src/core/debugger/gdbstub.cpp | |||
| @@ -0,0 +1,620 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <atomic> | ||
| 5 | #include <numeric> | ||
| 6 | #include <optional> | ||
| 7 | #include <thread> | ||
| 8 | |||
| 9 | #include <boost/algorithm/string.hpp> | ||
| 10 | |||
| 11 | #include "common/hex_util.h" | ||
| 12 | #include "common/logging/log.h" | ||
| 13 | #include "common/scope_exit.h" | ||
| 14 | #include "core/arm/arm_interface.h" | ||
| 15 | #include "core/core.h" | ||
| 16 | #include "core/debugger/gdbstub.h" | ||
| 17 | #include "core/debugger/gdbstub_arch.h" | ||
| 18 | #include "core/hle/kernel/k_page_table.h" | ||
| 19 | #include "core/hle/kernel/k_process.h" | ||
| 20 | #include "core/hle/kernel/k_thread.h" | ||
| 21 | #include "core/loader/loader.h" | ||
| 22 | #include "core/memory.h" | ||
| 23 | |||
| 24 | namespace Core { | ||
| 25 | |||
| 26 | constexpr char GDB_STUB_START = '$'; | ||
| 27 | constexpr char GDB_STUB_END = '#'; | ||
| 28 | constexpr char GDB_STUB_ACK = '+'; | ||
| 29 | constexpr char GDB_STUB_NACK = '-'; | ||
| 30 | constexpr char GDB_STUB_INT3 = 0x03; | ||
| 31 | constexpr int GDB_STUB_SIGTRAP = 5; | ||
| 32 | |||
| 33 | constexpr char GDB_STUB_REPLY_ERR[] = "E01"; | ||
| 34 | constexpr char GDB_STUB_REPLY_OK[] = "OK"; | ||
| 35 | constexpr char GDB_STUB_REPLY_EMPTY[] = ""; | ||
| 36 | |||
| 37 | static u8 CalculateChecksum(std::string_view data) { | ||
| 38 | return std::accumulate(data.begin(), data.end(), u8{0}, | ||
| 39 | [](u8 lhs, u8 rhs) { return static_cast<u8>(lhs + rhs); }); | ||
| 40 | } | ||
| 41 | |||
| 42 | static std::string EscapeGDB(std::string_view data) { | ||
| 43 | std::string escaped; | ||
| 44 | escaped.reserve(data.size()); | ||
| 45 | |||
| 46 | for (char c : data) { | ||
| 47 | switch (c) { | ||
| 48 | case '#': | ||
| 49 | escaped += "}\x03"; | ||
| 50 | break; | ||
| 51 | case '$': | ||
| 52 | escaped += "}\x04"; | ||
| 53 | break; | ||
| 54 | case '*': | ||
| 55 | escaped += "}\x0a"; | ||
| 56 | break; | ||
| 57 | case '}': | ||
| 58 | escaped += "}\x5d"; | ||
| 59 | break; | ||
| 60 | default: | ||
| 61 | escaped += c; | ||
| 62 | break; | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | return escaped; | ||
| 67 | } | ||
| 68 | |||
| 69 | static std::string EscapeXML(std::string_view data) { | ||
| 70 | std::string escaped; | ||
| 71 | escaped.reserve(data.size()); | ||
| 72 | |||
| 73 | for (char c : data) { | ||
| 74 | switch (c) { | ||
| 75 | case '&': | ||
| 76 | escaped += "&"; | ||
| 77 | break; | ||
| 78 | case '"': | ||
| 79 | escaped += """; | ||
| 80 | break; | ||
| 81 | case '<': | ||
| 82 | escaped += "<"; | ||
| 83 | break; | ||
| 84 | case '>': | ||
| 85 | escaped += ">"; | ||
| 86 | break; | ||
| 87 | default: | ||
| 88 | escaped += c; | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | return escaped; | ||
| 94 | } | ||
| 95 | |||
| 96 | GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_) | ||
| 97 | : DebuggerFrontend(backend_), system{system_} { | ||
| 98 | if (system.CurrentProcess()->Is64BitProcess()) { | ||
| 99 | arch = std::make_unique<GDBStubA64>(); | ||
| 100 | } else { | ||
| 101 | arch = std::make_unique<GDBStubA32>(); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | GDBStub::~GDBStub() = default; | ||
| 106 | |||
| 107 | void GDBStub::Connected() {} | ||
| 108 | |||
| 109 | void GDBStub::ShuttingDown() {} | ||
| 110 | |||
| 111 | void GDBStub::Stopped(Kernel::KThread* thread) { | ||
| 112 | SendReply(arch->ThreadStatus(thread, GDB_STUB_SIGTRAP)); | ||
| 113 | } | ||
| 114 | |||
| 115 | std::vector<DebuggerAction> GDBStub::ClientData(std::span<const u8> data) { | ||
| 116 | std::vector<DebuggerAction> actions; | ||
| 117 | current_command.insert(current_command.end(), data.begin(), data.end()); | ||
| 118 | |||
| 119 | while (current_command.size() != 0) { | ||
| 120 | ProcessData(actions); | ||
| 121 | } | ||
| 122 | |||
| 123 | return actions; | ||
| 124 | } | ||
| 125 | |||
| 126 | void GDBStub::ProcessData(std::vector<DebuggerAction>& actions) { | ||
| 127 | const char c{current_command[0]}; | ||
| 128 | |||
| 129 | // Acknowledgement | ||
| 130 | if (c == GDB_STUB_ACK || c == GDB_STUB_NACK) { | ||
| 131 | current_command.erase(current_command.begin()); | ||
| 132 | return; | ||
| 133 | } | ||
| 134 | |||
| 135 | // Interrupt | ||
| 136 | if (c == GDB_STUB_INT3) { | ||
| 137 | LOG_INFO(Debug_GDBStub, "Received interrupt"); | ||
| 138 | current_command.erase(current_command.begin()); | ||
| 139 | actions.push_back(DebuggerAction::Interrupt); | ||
| 140 | SendStatus(GDB_STUB_ACK); | ||
| 141 | return; | ||
| 142 | } | ||
| 143 | |||
| 144 | // Otherwise, require the data to be the start of a command | ||
| 145 | if (c != GDB_STUB_START) { | ||
| 146 | LOG_ERROR(Debug_GDBStub, "Invalid command buffer contents: {}", current_command.data()); | ||
| 147 | current_command.clear(); | ||
| 148 | SendStatus(GDB_STUB_NACK); | ||
| 149 | return; | ||
| 150 | } | ||
| 151 | |||
| 152 | // Continue reading until command is complete | ||
| 153 | while (CommandEnd() == current_command.end()) { | ||
| 154 | const auto new_data{backend.ReadFromClient()}; | ||
| 155 | current_command.insert(current_command.end(), new_data.begin(), new_data.end()); | ||
| 156 | } | ||
| 157 | |||
| 158 | // Execute and respond to GDB | ||
| 159 | const auto command{DetachCommand()}; | ||
| 160 | |||
| 161 | if (command) { | ||
| 162 | SendStatus(GDB_STUB_ACK); | ||
| 163 | ExecuteCommand(*command, actions); | ||
| 164 | } else { | ||
| 165 | SendStatus(GDB_STUB_NACK); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction>& actions) { | ||
| 170 | LOG_TRACE(Debug_GDBStub, "Executing command: {}", packet); | ||
| 171 | |||
| 172 | if (packet.length() == 0) { | ||
| 173 | SendReply(GDB_STUB_REPLY_ERR); | ||
| 174 | return; | ||
| 175 | } | ||
| 176 | |||
| 177 | if (packet.starts_with("vCont")) { | ||
| 178 | HandleVCont(packet.substr(5), actions); | ||
| 179 | return; | ||
| 180 | } | ||
| 181 | |||
| 182 | std::string_view command{packet.substr(1, packet.size())}; | ||
| 183 | |||
| 184 | switch (packet[0]) { | ||
| 185 | case 'H': { | ||
| 186 | Kernel::KThread* thread{nullptr}; | ||
| 187 | s64 thread_id{strtoll(command.data() + 1, nullptr, 16)}; | ||
| 188 | if (thread_id >= 1) { | ||
| 189 | thread = GetThreadByID(thread_id); | ||
| 190 | } else { | ||
| 191 | thread = backend.GetActiveThread(); | ||
| 192 | } | ||
| 193 | |||
| 194 | if (thread) { | ||
| 195 | SendReply(GDB_STUB_REPLY_OK); | ||
| 196 | backend.SetActiveThread(thread); | ||
| 197 | } else { | ||
| 198 | SendReply(GDB_STUB_REPLY_ERR); | ||
| 199 | } | ||
| 200 | break; | ||
| 201 | } | ||
| 202 | case 'T': { | ||
| 203 | s64 thread_id{strtoll(command.data(), nullptr, 16)}; | ||
| 204 | if (GetThreadByID(thread_id)) { | ||
| 205 | SendReply(GDB_STUB_REPLY_OK); | ||
| 206 | } else { | ||
| 207 | SendReply(GDB_STUB_REPLY_ERR); | ||
| 208 | } | ||
| 209 | break; | ||
| 210 | } | ||
| 211 | case 'Q': | ||
| 212 | case 'q': | ||
| 213 | HandleQuery(command); | ||
| 214 | break; | ||
| 215 | case '?': | ||
| 216 | SendReply(arch->ThreadStatus(backend.GetActiveThread(), GDB_STUB_SIGTRAP)); | ||
| 217 | break; | ||
| 218 | case 'k': | ||
| 219 | LOG_INFO(Debug_GDBStub, "Shutting down emulation"); | ||
| 220 | actions.push_back(DebuggerAction::ShutdownEmulation); | ||
| 221 | break; | ||
| 222 | case 'g': | ||
| 223 | SendReply(arch->ReadRegisters(backend.GetActiveThread())); | ||
| 224 | break; | ||
| 225 | case 'G': | ||
| 226 | arch->WriteRegisters(backend.GetActiveThread(), command); | ||
| 227 | SendReply(GDB_STUB_REPLY_OK); | ||
| 228 | break; | ||
| 229 | case 'p': { | ||
| 230 | const size_t reg{static_cast<size_t>(strtoll(command.data(), nullptr, 16))}; | ||
| 231 | SendReply(arch->RegRead(backend.GetActiveThread(), reg)); | ||
| 232 | break; | ||
| 233 | } | ||
| 234 | case 'P': { | ||
| 235 | const auto sep{std::find(command.begin(), command.end(), '=') - command.begin() + 1}; | ||
| 236 | const size_t reg{static_cast<size_t>(strtoll(command.data(), nullptr, 16))}; | ||
| 237 | arch->RegWrite(backend.GetActiveThread(), reg, std::string_view(command).substr(sep)); | ||
| 238 | break; | ||
| 239 | } | ||
| 240 | case 'm': { | ||
| 241 | const auto sep{std::find(command.begin(), command.end(), ',') - command.begin() + 1}; | ||
| 242 | const size_t addr{static_cast<size_t>(strtoll(command.data(), nullptr, 16))}; | ||
| 243 | const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))}; | ||
| 244 | |||
| 245 | if (system.Memory().IsValidVirtualAddressRange(addr, size)) { | ||
| 246 | std::vector<u8> mem(size); | ||
| 247 | system.Memory().ReadBlock(addr, mem.data(), size); | ||
| 248 | |||
| 249 | SendReply(Common::HexToString(mem)); | ||
| 250 | } else { | ||
| 251 | SendReply(GDB_STUB_REPLY_ERR); | ||
| 252 | } | ||
| 253 | break; | ||
| 254 | } | ||
| 255 | case 'M': { | ||
| 256 | const auto size_sep{std::find(command.begin(), command.end(), ',') - command.begin() + 1}; | ||
| 257 | const auto mem_sep{std::find(command.begin(), command.end(), ':') - command.begin() + 1}; | ||
| 258 | |||
| 259 | const size_t addr{static_cast<size_t>(strtoll(command.data(), nullptr, 16))}; | ||
| 260 | const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; | ||
| 261 | |||
| 262 | const auto mem_substr{std::string_view(command).substr(mem_sep)}; | ||
| 263 | const auto mem{Common::HexStringToVector(mem_substr, false)}; | ||
| 264 | |||
| 265 | if (system.Memory().IsValidVirtualAddressRange(addr, size)) { | ||
| 266 | system.Memory().WriteBlock(addr, mem.data(), size); | ||
| 267 | system.InvalidateCpuInstructionCacheRange(addr, size); | ||
| 268 | SendReply(GDB_STUB_REPLY_OK); | ||
| 269 | } else { | ||
| 270 | SendReply(GDB_STUB_REPLY_ERR); | ||
| 271 | } | ||
| 272 | break; | ||
| 273 | } | ||
| 274 | case 's': | ||
| 275 | actions.push_back(DebuggerAction::StepThreadLocked); | ||
| 276 | break; | ||
| 277 | case 'C': | ||
| 278 | case 'c': | ||
| 279 | actions.push_back(DebuggerAction::Continue); | ||
| 280 | break; | ||
| 281 | case 'Z': { | ||
| 282 | const auto addr_sep{std::find(command.begin(), command.end(), ',') - command.begin() + 1}; | ||
| 283 | const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; | ||
| 284 | |||
| 285 | if (system.Memory().IsValidVirtualAddress(addr)) { | ||
| 286 | replaced_instructions[addr] = system.Memory().Read32(addr); | ||
| 287 | system.Memory().Write32(addr, arch->BreakpointInstruction()); | ||
| 288 | system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); | ||
| 289 | |||
| 290 | SendReply(GDB_STUB_REPLY_OK); | ||
| 291 | } else { | ||
| 292 | SendReply(GDB_STUB_REPLY_ERR); | ||
| 293 | } | ||
| 294 | break; | ||
| 295 | } | ||
| 296 | case 'z': { | ||
| 297 | const auto addr_sep{std::find(command.begin(), command.end(), ',') - command.begin() + 1}; | ||
| 298 | const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; | ||
| 299 | |||
| 300 | const auto orig_insn{replaced_instructions.find(addr)}; | ||
| 301 | if (system.Memory().IsValidVirtualAddress(addr) && | ||
| 302 | orig_insn != replaced_instructions.end()) { | ||
| 303 | system.Memory().Write32(addr, orig_insn->second); | ||
| 304 | system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); | ||
| 305 | replaced_instructions.erase(addr); | ||
| 306 | |||
| 307 | SendReply(GDB_STUB_REPLY_OK); | ||
| 308 | } else { | ||
| 309 | SendReply(GDB_STUB_REPLY_ERR); | ||
| 310 | } | ||
| 311 | break; | ||
| 312 | } | ||
| 313 | default: | ||
| 314 | SendReply(GDB_STUB_REPLY_EMPTY); | ||
| 315 | break; | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | // Structure offsets are from Atmosphere | ||
| 320 | // See osdbg_thread_local_region.os.horizon.hpp and osdbg_thread_type.os.horizon.hpp | ||
| 321 | |||
| 322 | static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory, | ||
| 323 | const Kernel::KThread* thread) { | ||
| 324 | // Read thread type from TLS | ||
| 325 | const VAddr tls_thread_type{memory.Read32(thread->GetTLSAddress() + 0x1fc)}; | ||
| 326 | const VAddr argument_thread_type{thread->GetArgument()}; | ||
| 327 | |||
| 328 | if (argument_thread_type && tls_thread_type != argument_thread_type) { | ||
| 329 | // Probably not created by nnsdk, no name available. | ||
| 330 | return std::nullopt; | ||
| 331 | } | ||
| 332 | |||
| 333 | if (!tls_thread_type) { | ||
| 334 | return std::nullopt; | ||
| 335 | } | ||
| 336 | |||
| 337 | const u16 version{memory.Read16(tls_thread_type + 0x26)}; | ||
| 338 | VAddr name_pointer{}; | ||
| 339 | if (version == 1) { | ||
| 340 | name_pointer = memory.Read32(tls_thread_type + 0xe4); | ||
| 341 | } else { | ||
| 342 | name_pointer = memory.Read32(tls_thread_type + 0xe8); | ||
| 343 | } | ||
| 344 | |||
| 345 | if (!name_pointer) { | ||
| 346 | // No name provided. | ||
| 347 | return std::nullopt; | ||
| 348 | } | ||
| 349 | |||
| 350 | return memory.ReadCString(name_pointer, 256); | ||
| 351 | } | ||
| 352 | |||
| 353 | static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory, | ||
| 354 | const Kernel::KThread* thread) { | ||
| 355 | // Read thread type from TLS | ||
| 356 | const VAddr tls_thread_type{memory.Read64(thread->GetTLSAddress() + 0x1f8)}; | ||
| 357 | const VAddr argument_thread_type{thread->GetArgument()}; | ||
| 358 | |||
| 359 | if (argument_thread_type && tls_thread_type != argument_thread_type) { | ||
| 360 | // Probably not created by nnsdk, no name available. | ||
| 361 | return std::nullopt; | ||
| 362 | } | ||
| 363 | |||
| 364 | if (!tls_thread_type) { | ||
| 365 | return std::nullopt; | ||
| 366 | } | ||
| 367 | |||
| 368 | const u16 version{memory.Read16(tls_thread_type + 0x46)}; | ||
| 369 | VAddr name_pointer{}; | ||
| 370 | if (version == 1) { | ||
| 371 | name_pointer = memory.Read64(tls_thread_type + 0x1a0); | ||
| 372 | } else { | ||
| 373 | name_pointer = memory.Read64(tls_thread_type + 0x1a8); | ||
| 374 | } | ||
| 375 | |||
| 376 | if (!name_pointer) { | ||
| 377 | // No name provided. | ||
| 378 | return std::nullopt; | ||
| 379 | } | ||
| 380 | |||
| 381 | return memory.ReadCString(name_pointer, 256); | ||
| 382 | } | ||
| 383 | |||
| 384 | static std::optional<std::string> GetThreadName(Core::System& system, | ||
| 385 | const Kernel::KThread* thread) { | ||
| 386 | if (system.CurrentProcess()->Is64BitProcess()) { | ||
| 387 | return GetNameFromThreadType64(system.Memory(), thread); | ||
| 388 | } else { | ||
| 389 | return GetNameFromThreadType32(system.Memory(), thread); | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | static std::string_view GetThreadWaitReason(const Kernel::KThread* thread) { | ||
| 394 | switch (thread->GetWaitReasonForDebugging()) { | ||
| 395 | case Kernel::ThreadWaitReasonForDebugging::Sleep: | ||
| 396 | return "Sleep"; | ||
| 397 | case Kernel::ThreadWaitReasonForDebugging::IPC: | ||
| 398 | return "IPC"; | ||
| 399 | case Kernel::ThreadWaitReasonForDebugging::Synchronization: | ||
| 400 | return "Synchronization"; | ||
| 401 | case Kernel::ThreadWaitReasonForDebugging::ConditionVar: | ||
| 402 | return "ConditionVar"; | ||
| 403 | case Kernel::ThreadWaitReasonForDebugging::Arbitration: | ||
| 404 | return "Arbitration"; | ||
| 405 | case Kernel::ThreadWaitReasonForDebugging::Suspended: | ||
| 406 | return "Suspended"; | ||
| 407 | default: | ||
| 408 | return "Unknown"; | ||
| 409 | } | ||
| 410 | } | ||
| 411 | |||
| 412 | static std::string GetThreadState(const Kernel::KThread* thread) { | ||
| 413 | switch (thread->GetState()) { | ||
| 414 | case Kernel::ThreadState::Initialized: | ||
| 415 | return "Initialized"; | ||
| 416 | case Kernel::ThreadState::Waiting: | ||
| 417 | return fmt::format("Waiting ({})", GetThreadWaitReason(thread)); | ||
| 418 | case Kernel::ThreadState::Runnable: | ||
| 419 | return "Runnable"; | ||
| 420 | case Kernel::ThreadState::Terminated: | ||
| 421 | return "Terminated"; | ||
| 422 | default: | ||
| 423 | return "Unknown"; | ||
| 424 | } | ||
| 425 | } | ||
| 426 | |||
| 427 | static std::string PaginateBuffer(std::string_view buffer, std::string_view request) { | ||
| 428 | const auto amount{request.substr(request.find(',') + 1)}; | ||
| 429 | const auto offset_val{static_cast<u64>(strtoll(request.data(), nullptr, 16))}; | ||
| 430 | const auto amount_val{static_cast<u64>(strtoll(amount.data(), nullptr, 16))}; | ||
| 431 | |||
| 432 | if (offset_val + amount_val > buffer.size()) { | ||
| 433 | return fmt::format("l{}", buffer.substr(offset_val)); | ||
| 434 | } else { | ||
| 435 | return fmt::format("m{}", buffer.substr(offset_val, amount_val)); | ||
| 436 | } | ||
| 437 | } | ||
| 438 | |||
| 439 | void GDBStub::HandleQuery(std::string_view command) { | ||
| 440 | if (command.starts_with("TStatus")) { | ||
| 441 | // no tracepoint support | ||
| 442 | SendReply("T0"); | ||
| 443 | } else if (command.starts_with("Supported")) { | ||
| 444 | SendReply("PacketSize=4000;qXfer:features:read+;qXfer:threads:read+;qXfer:libraries:read+;" | ||
| 445 | "vContSupported+;QStartNoAckMode+"); | ||
| 446 | } else if (command.starts_with("Xfer:features:read:target.xml:")) { | ||
| 447 | const auto target_xml{arch->GetTargetXML()}; | ||
| 448 | SendReply(PaginateBuffer(target_xml, command.substr(30))); | ||
| 449 | } else if (command.starts_with("Offsets")) { | ||
| 450 | Loader::AppLoader::Modules modules; | ||
| 451 | system.GetAppLoader().ReadNSOModules(modules); | ||
| 452 | |||
| 453 | const auto main = std::find_if(modules.begin(), modules.end(), | ||
| 454 | [](const auto& key) { return key.second == "main"; }); | ||
| 455 | if (main != modules.end()) { | ||
| 456 | SendReply(fmt::format("TextSeg={:x}", main->first)); | ||
| 457 | } else { | ||
| 458 | SendReply(fmt::format("TextSeg={:x}", | ||
| 459 | system.CurrentProcess()->PageTable().GetCodeRegionStart())); | ||
| 460 | } | ||
| 461 | } else if (command.starts_with("Xfer:libraries:read::")) { | ||
| 462 | Loader::AppLoader::Modules modules; | ||
| 463 | system.GetAppLoader().ReadNSOModules(modules); | ||
| 464 | |||
| 465 | std::string buffer; | ||
| 466 | buffer += R"(<?xml version="1.0"?>)"; | ||
| 467 | buffer += "<library-list>"; | ||
| 468 | for (const auto& [base, name] : modules) { | ||
| 469 | buffer += fmt::format(R"(<library name="{}"><segment address="{:#x}"/></library>)", | ||
| 470 | EscapeXML(name), base); | ||
| 471 | } | ||
| 472 | buffer += "</library-list>"; | ||
| 473 | |||
| 474 | SendReply(PaginateBuffer(buffer, command.substr(21))); | ||
| 475 | } else if (command.starts_with("fThreadInfo")) { | ||
| 476 | // beginning of list | ||
| 477 | const auto& threads = system.GlobalSchedulerContext().GetThreadList(); | ||
| 478 | std::vector<std::string> thread_ids; | ||
| 479 | for (const auto& thread : threads) { | ||
| 480 | thread_ids.push_back(fmt::format("{:x}", thread->GetThreadID())); | ||
| 481 | } | ||
| 482 | SendReply(fmt::format("m{}", fmt::join(thread_ids, ","))); | ||
| 483 | } else if (command.starts_with("sThreadInfo")) { | ||
| 484 | // end of list | ||
| 485 | SendReply("l"); | ||
| 486 | } else if (command.starts_with("Xfer:threads:read::")) { | ||
| 487 | std::string buffer; | ||
| 488 | buffer += R"(<?xml version="1.0"?>)"; | ||
| 489 | buffer += "<threads>"; | ||
| 490 | |||
| 491 | const auto& threads = system.GlobalSchedulerContext().GetThreadList(); | ||
| 492 | for (const auto* thread : threads) { | ||
| 493 | auto thread_name{GetThreadName(system, thread)}; | ||
| 494 | if (!thread_name) { | ||
| 495 | thread_name = fmt::format("Thread {:d}", thread->GetThreadID()); | ||
| 496 | } | ||
| 497 | |||
| 498 | buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)", | ||
| 499 | thread->GetThreadID(), thread->GetActiveCore(), | ||
| 500 | EscapeXML(*thread_name), GetThreadState(thread)); | ||
| 501 | } | ||
| 502 | |||
| 503 | buffer += "</threads>"; | ||
| 504 | |||
| 505 | SendReply(PaginateBuffer(buffer, command.substr(19))); | ||
| 506 | } else if (command.starts_with("Attached")) { | ||
| 507 | SendReply("0"); | ||
| 508 | } else if (command.starts_with("StartNoAckMode")) { | ||
| 509 | no_ack = true; | ||
| 510 | SendReply(GDB_STUB_REPLY_OK); | ||
| 511 | } else { | ||
| 512 | SendReply(GDB_STUB_REPLY_EMPTY); | ||
| 513 | } | ||
| 514 | } | ||
| 515 | |||
| 516 | void GDBStub::HandleVCont(std::string_view command, std::vector<DebuggerAction>& actions) { | ||
| 517 | if (command == "?") { | ||
| 518 | // Continuing and stepping are supported | ||
| 519 | // (signal is ignored, but required for GDB to use vCont) | ||
| 520 | SendReply("vCont;c;C;s;S"); | ||
| 521 | return; | ||
| 522 | } | ||
| 523 | |||
| 524 | Kernel::KThread* stepped_thread{nullptr}; | ||
| 525 | bool lock_execution{true}; | ||
| 526 | |||
| 527 | std::vector<std::string> entries; | ||
| 528 | boost::split(entries, command.substr(1), boost::is_any_of(";")); | ||
| 529 | for (const auto& thread_action : entries) { | ||
| 530 | std::vector<std::string> parts; | ||
| 531 | boost::split(parts, thread_action, boost::is_any_of(":")); | ||
| 532 | |||
| 533 | if (parts.size() == 1 && (parts[0] == "c" || parts[0].starts_with("C"))) { | ||
| 534 | lock_execution = false; | ||
| 535 | } | ||
| 536 | if (parts.size() == 2 && (parts[0] == "s" || parts[0].starts_with("S"))) { | ||
| 537 | stepped_thread = GetThreadByID(strtoll(parts[1].data(), nullptr, 16)); | ||
| 538 | } | ||
| 539 | } | ||
| 540 | |||
| 541 | if (stepped_thread) { | ||
| 542 | backend.SetActiveThread(stepped_thread); | ||
| 543 | actions.push_back(lock_execution ? DebuggerAction::StepThreadLocked | ||
| 544 | : DebuggerAction::StepThreadUnlocked); | ||
| 545 | } else { | ||
| 546 | actions.push_back(DebuggerAction::Continue); | ||
| 547 | } | ||
| 548 | } | ||
| 549 | |||
| 550 | Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { | ||
| 551 | const auto& threads{system.GlobalSchedulerContext().GetThreadList()}; | ||
| 552 | for (auto* thread : threads) { | ||
| 553 | if (thread->GetThreadID() == thread_id) { | ||
| 554 | return thread; | ||
| 555 | } | ||
| 556 | } | ||
| 557 | |||
| 558 | return nullptr; | ||
| 559 | } | ||
| 560 | |||
| 561 | std::vector<char>::const_iterator GDBStub::CommandEnd() const { | ||
| 562 | // Find the end marker | ||
| 563 | const auto end{std::find(current_command.begin(), current_command.end(), GDB_STUB_END)}; | ||
| 564 | |||
| 565 | // Require the checksum to be present | ||
| 566 | return std::min(end + 2, current_command.end()); | ||
| 567 | } | ||
| 568 | |||
| 569 | std::optional<std::string> GDBStub::DetachCommand() { | ||
| 570 | // Slice the string part from the beginning to the end marker | ||
| 571 | const auto end{CommandEnd()}; | ||
| 572 | |||
| 573 | // Extract possible command data | ||
| 574 | std::string data(current_command.data(), end - current_command.begin() + 1); | ||
| 575 | |||
| 576 | // Shift over the remaining contents | ||
| 577 | current_command.erase(current_command.begin(), end + 1); | ||
| 578 | |||
| 579 | // Validate received command | ||
| 580 | if (data[0] != GDB_STUB_START) { | ||
| 581 | LOG_ERROR(Debug_GDBStub, "Invalid start data: {}", data[0]); | ||
| 582 | return std::nullopt; | ||
| 583 | } | ||
| 584 | |||
| 585 | u8 calculated = CalculateChecksum(std::string_view(data).substr(1, data.size() - 4)); | ||
| 586 | u8 received = static_cast<u8>(strtoll(data.data() + data.size() - 2, nullptr, 16)); | ||
| 587 | |||
| 588 | // Verify checksum | ||
| 589 | if (calculated != received) { | ||
| 590 | LOG_ERROR(Debug_GDBStub, "Checksum mismatch: calculated {:02x}, received {:02x}", | ||
| 591 | calculated, received); | ||
| 592 | return std::nullopt; | ||
| 593 | } | ||
| 594 | |||
| 595 | return data.substr(1, data.size() - 4); | ||
| 596 | } | ||
| 597 | |||
| 598 | void GDBStub::SendReply(std::string_view data) { | ||
| 599 | const auto escaped{EscapeGDB(data)}; | ||
| 600 | const auto output{fmt::format("{}{}{}{:02x}", GDB_STUB_START, escaped, GDB_STUB_END, | ||
| 601 | CalculateChecksum(escaped))}; | ||
| 602 | LOG_TRACE(Debug_GDBStub, "Writing reply: {}", output); | ||
| 603 | |||
| 604 | // C++ string support is complete rubbish | ||
| 605 | const u8* output_begin = reinterpret_cast<const u8*>(output.data()); | ||
| 606 | const u8* output_end = output_begin + output.size(); | ||
| 607 | backend.WriteToClient(std::span<const u8>(output_begin, output_end)); | ||
| 608 | } | ||
| 609 | |||
| 610 | void GDBStub::SendStatus(char status) { | ||
| 611 | if (no_ack) { | ||
| 612 | return; | ||
| 613 | } | ||
| 614 | |||
| 615 | std::array<u8, 1> buf = {static_cast<u8>(status)}; | ||
| 616 | LOG_TRACE(Debug_GDBStub, "Writing status: {}", status); | ||
| 617 | backend.WriteToClient(buf); | ||
| 618 | } | ||
| 619 | |||
| 620 | } // namespace Core | ||
diff --git a/src/core/debugger/gdbstub.h b/src/core/debugger/gdbstub.h new file mode 100644 index 000000000..ec934c77e --- /dev/null +++ b/src/core/debugger/gdbstub.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <map> | ||
| 7 | #include <memory> | ||
| 8 | #include <optional> | ||
| 9 | #include <string_view> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | #include "core/debugger/debugger_interface.h" | ||
| 13 | #include "core/debugger/gdbstub_arch.h" | ||
| 14 | |||
| 15 | namespace Core { | ||
| 16 | |||
| 17 | class System; | ||
| 18 | |||
| 19 | class GDBStub : public DebuggerFrontend { | ||
| 20 | public: | ||
| 21 | explicit GDBStub(DebuggerBackend& backend, Core::System& system); | ||
| 22 | ~GDBStub() override; | ||
| 23 | |||
| 24 | void Connected() override; | ||
| 25 | void Stopped(Kernel::KThread* thread) override; | ||
| 26 | void ShuttingDown() override; | ||
| 27 | std::vector<DebuggerAction> ClientData(std::span<const u8> data) override; | ||
| 28 | |||
| 29 | private: | ||
| 30 | void ProcessData(std::vector<DebuggerAction>& actions); | ||
| 31 | void ExecuteCommand(std::string_view packet, std::vector<DebuggerAction>& actions); | ||
| 32 | void HandleVCont(std::string_view command, std::vector<DebuggerAction>& actions); | ||
| 33 | void HandleQuery(std::string_view command); | ||
| 34 | std::vector<char>::const_iterator CommandEnd() const; | ||
| 35 | std::optional<std::string> DetachCommand(); | ||
| 36 | Kernel::KThread* GetThreadByID(u64 thread_id); | ||
| 37 | |||
| 38 | void SendReply(std::string_view data); | ||
| 39 | void SendStatus(char status); | ||
| 40 | |||
| 41 | private: | ||
| 42 | Core::System& system; | ||
| 43 | std::unique_ptr<GDBStubArch> arch; | ||
| 44 | std::vector<char> current_command; | ||
| 45 | std::map<VAddr, u32> replaced_instructions; | ||
| 46 | bool no_ack{}; | ||
| 47 | }; | ||
| 48 | |||
| 49 | } // namespace Core | ||
diff --git a/src/core/debugger/gdbstub_arch.cpp b/src/core/debugger/gdbstub_arch.cpp new file mode 100644 index 000000000..750c353b9 --- /dev/null +++ b/src/core/debugger/gdbstub_arch.cpp | |||
| @@ -0,0 +1,483 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/hex_util.h" | ||
| 5 | #include "core/debugger/gdbstub_arch.h" | ||
| 6 | #include "core/hle/kernel/k_thread.h" | ||
| 7 | |||
| 8 | namespace Core { | ||
| 9 | |||
| 10 | template <typename T> | ||
| 11 | static T HexToValue(std::string_view hex) { | ||
| 12 | static_assert(std::is_trivially_copyable_v<T>); | ||
| 13 | T value{}; | ||
| 14 | const auto mem{Common::HexStringToVector(hex, false)}; | ||
| 15 | std::memcpy(&value, mem.data(), std::min(mem.size(), sizeof(T))); | ||
| 16 | return value; | ||
| 17 | } | ||
| 18 | |||
| 19 | template <typename T> | ||
| 20 | static std::string ValueToHex(const T value) { | ||
| 21 | static_assert(std::is_trivially_copyable_v<T>); | ||
| 22 | std::array<u8, sizeof(T)> mem{}; | ||
| 23 | std::memcpy(mem.data(), &value, sizeof(T)); | ||
| 24 | return Common::HexToString(mem); | ||
| 25 | } | ||
| 26 | |||
| 27 | template <typename T> | ||
| 28 | static T GetSIMDRegister(const std::array<u32, 64>& simd_regs, size_t offset) { | ||
| 29 | static_assert(std::is_trivially_copyable_v<T>); | ||
| 30 | T value{}; | ||
| 31 | std::memcpy(&value, reinterpret_cast<const u8*>(simd_regs.data()) + sizeof(T) * offset, | ||
| 32 | sizeof(T)); | ||
| 33 | return value; | ||
| 34 | } | ||
| 35 | |||
| 36 | template <typename T> | ||
| 37 | static void PutSIMDRegister(std::array<u32, 64>& simd_regs, size_t offset, const T value) { | ||
| 38 | static_assert(std::is_trivially_copyable_v<T>); | ||
| 39 | std::memcpy(reinterpret_cast<u8*>(simd_regs.data()) + sizeof(T) * offset, &value, sizeof(T)); | ||
| 40 | } | ||
| 41 | |||
| 42 | // For sample XML files see the GDB source /gdb/features | ||
| 43 | // This XML defines what the registers are for this specific ARM device | ||
| 44 | std::string GDBStubA64::GetTargetXML() const { | ||
| 45 | constexpr const char* target_xml = | ||
| 46 | R"(<?xml version="1.0"?> | ||
| 47 | <!DOCTYPE target SYSTEM "gdb-target.dtd"> | ||
| 48 | <target version="1.0"> | ||
| 49 | <architecture>aarch64</architecture> | ||
| 50 | <feature name="org.gnu.gdb.aarch64.core"> | ||
| 51 | <reg name="x0" bitsize="64"/> | ||
| 52 | <reg name="x1" bitsize="64"/> | ||
| 53 | <reg name="x2" bitsize="64"/> | ||
| 54 | <reg name="x3" bitsize="64"/> | ||
| 55 | <reg name="x4" bitsize="64"/> | ||
| 56 | <reg name="x5" bitsize="64"/> | ||
| 57 | <reg name="x6" bitsize="64"/> | ||
| 58 | <reg name="x7" bitsize="64"/> | ||
| 59 | <reg name="x8" bitsize="64"/> | ||
| 60 | <reg name="x9" bitsize="64"/> | ||
| 61 | <reg name="x10" bitsize="64"/> | ||
| 62 | <reg name="x11" bitsize="64"/> | ||
| 63 | <reg name="x12" bitsize="64"/> | ||
| 64 | <reg name="x13" bitsize="64"/> | ||
| 65 | <reg name="x14" bitsize="64"/> | ||
| 66 | <reg name="x15" bitsize="64"/> | ||
| 67 | <reg name="x16" bitsize="64"/> | ||
| 68 | <reg name="x17" bitsize="64"/> | ||
| 69 | <reg name="x18" bitsize="64"/> | ||
| 70 | <reg name="x19" bitsize="64"/> | ||
| 71 | <reg name="x20" bitsize="64"/> | ||
| 72 | <reg name="x21" bitsize="64"/> | ||
| 73 | <reg name="x22" bitsize="64"/> | ||
| 74 | <reg name="x23" bitsize="64"/> | ||
| 75 | <reg name="x24" bitsize="64"/> | ||
| 76 | <reg name="x25" bitsize="64"/> | ||
| 77 | <reg name="x26" bitsize="64"/> | ||
| 78 | <reg name="x27" bitsize="64"/> | ||
| 79 | <reg name="x28" bitsize="64"/> | ||
| 80 | <reg name="x29" bitsize="64"/> | ||
| 81 | <reg name="x30" bitsize="64"/> | ||
| 82 | <reg name="sp" bitsize="64" type="data_ptr"/> | ||
| 83 | <reg name="pc" bitsize="64" type="code_ptr"/> | ||
| 84 | <flags id="cpsr_flags" size="4"> | ||
| 85 | <field name="SP" start="0" end="0"/> | ||
| 86 | <field name="" start="1" end="1"/> | ||
| 87 | <field name="EL" start="2" end="3"/> | ||
| 88 | <field name="nRW" start="4" end="4"/> | ||
| 89 | <field name="" start="5" end="5"/> | ||
| 90 | <field name="F" start="6" end="6"/> | ||
| 91 | <field name="I" start="7" end="7"/> | ||
| 92 | <field name="A" start="8" end="8"/> | ||
| 93 | <field name="D" start="9" end="9"/> | ||
| 94 | <field name="IL" start="20" end="20"/> | ||
| 95 | <field name="SS" start="21" end="21"/> | ||
| 96 | <field name="V" start="28" end="28"/> | ||
| 97 | <field name="C" start="29" end="29"/> | ||
| 98 | <field name="Z" start="30" end="30"/> | ||
| 99 | <field name="N" start="31" end="31"/> | ||
| 100 | </flags> | ||
| 101 | <reg name="cpsr" bitsize="32" type="cpsr_flags"/> | ||
| 102 | </feature> | ||
| 103 | <feature name="org.gnu.gdb.aarch64.fpu"> | ||
| 104 | <vector id="v2d" type="ieee_double" count="2"/> | ||
| 105 | <vector id="v2u" type="uint64" count="2"/> | ||
| 106 | <vector id="v2i" type="int64" count="2"/> | ||
| 107 | <vector id="v4f" type="ieee_single" count="4"/> | ||
| 108 | <vector id="v4u" type="uint32" count="4"/> | ||
| 109 | <vector id="v4i" type="int32" count="4"/> | ||
| 110 | <vector id="v8u" type="uint16" count="8"/> | ||
| 111 | <vector id="v8i" type="int16" count="8"/> | ||
| 112 | <vector id="v16u" type="uint8" count="16"/> | ||
| 113 | <vector id="v16i" type="int8" count="16"/> | ||
| 114 | <vector id="v1u" type="uint128" count="1"/> | ||
| 115 | <vector id="v1i" type="int128" count="1"/> | ||
| 116 | <union id="vnd"> | ||
| 117 | <field name="f" type="v2d"/> | ||
| 118 | <field name="u" type="v2u"/> | ||
| 119 | <field name="s" type="v2i"/> | ||
| 120 | </union> | ||
| 121 | <union id="vns"> | ||
| 122 | <field name="f" type="v4f"/> | ||
| 123 | <field name="u" type="v4u"/> | ||
| 124 | <field name="s" type="v4i"/> | ||
| 125 | </union> | ||
| 126 | <union id="vnh"> | ||
| 127 | <field name="u" type="v8u"/> | ||
| 128 | <field name="s" type="v8i"/> | ||
| 129 | </union> | ||
| 130 | <union id="vnb"> | ||
| 131 | <field name="u" type="v16u"/> | ||
| 132 | <field name="s" type="v16i"/> | ||
| 133 | </union> | ||
| 134 | <union id="vnq"> | ||
| 135 | <field name="u" type="v1u"/> | ||
| 136 | <field name="s" type="v1i"/> | ||
| 137 | </union> | ||
| 138 | <union id="aarch64v"> | ||
| 139 | <field name="d" type="vnd"/> | ||
| 140 | <field name="s" type="vns"/> | ||
| 141 | <field name="h" type="vnh"/> | ||
| 142 | <field name="b" type="vnb"/> | ||
| 143 | <field name="q" type="vnq"/> | ||
| 144 | </union> | ||
| 145 | <reg name="v0" bitsize="128" type="aarch64v" regnum="34"/> | ||
| 146 | <reg name="v1" bitsize="128" type="aarch64v" /> | ||
| 147 | <reg name="v2" bitsize="128" type="aarch64v" /> | ||
| 148 | <reg name="v3" bitsize="128" type="aarch64v" /> | ||
| 149 | <reg name="v4" bitsize="128" type="aarch64v" /> | ||
| 150 | <reg name="v5" bitsize="128" type="aarch64v" /> | ||
| 151 | <reg name="v6" bitsize="128" type="aarch64v" /> | ||
| 152 | <reg name="v7" bitsize="128" type="aarch64v" /> | ||
| 153 | <reg name="v8" bitsize="128" type="aarch64v" /> | ||
| 154 | <reg name="v9" bitsize="128" type="aarch64v" /> | ||
| 155 | <reg name="v10" bitsize="128" type="aarch64v"/> | ||
| 156 | <reg name="v11" bitsize="128" type="aarch64v"/> | ||
| 157 | <reg name="v12" bitsize="128" type="aarch64v"/> | ||
| 158 | <reg name="v13" bitsize="128" type="aarch64v"/> | ||
| 159 | <reg name="v14" bitsize="128" type="aarch64v"/> | ||
| 160 | <reg name="v15" bitsize="128" type="aarch64v"/> | ||
| 161 | <reg name="v16" bitsize="128" type="aarch64v"/> | ||
| 162 | <reg name="v17" bitsize="128" type="aarch64v"/> | ||
| 163 | <reg name="v18" bitsize="128" type="aarch64v"/> | ||
| 164 | <reg name="v19" bitsize="128" type="aarch64v"/> | ||
| 165 | <reg name="v20" bitsize="128" type="aarch64v"/> | ||
| 166 | <reg name="v21" bitsize="128" type="aarch64v"/> | ||
| 167 | <reg name="v22" bitsize="128" type="aarch64v"/> | ||
| 168 | <reg name="v23" bitsize="128" type="aarch64v"/> | ||
| 169 | <reg name="v24" bitsize="128" type="aarch64v"/> | ||
| 170 | <reg name="v25" bitsize="128" type="aarch64v"/> | ||
| 171 | <reg name="v26" bitsize="128" type="aarch64v"/> | ||
| 172 | <reg name="v27" bitsize="128" type="aarch64v"/> | ||
| 173 | <reg name="v28" bitsize="128" type="aarch64v"/> | ||
| 174 | <reg name="v29" bitsize="128" type="aarch64v"/> | ||
| 175 | <reg name="v30" bitsize="128" type="aarch64v"/> | ||
| 176 | <reg name="v31" bitsize="128" type="aarch64v"/> | ||
| 177 | <reg name="fpsr" bitsize="32"/> | ||
| 178 | <reg name="fpcr" bitsize="32"/> | ||
| 179 | </feature> | ||
| 180 | </target>)"; | ||
| 181 | |||
| 182 | return target_xml; | ||
| 183 | } | ||
| 184 | |||
| 185 | std::string GDBStubA64::RegRead(const Kernel::KThread* thread, size_t id) const { | ||
| 186 | if (!thread) { | ||
| 187 | return ""; | ||
| 188 | } | ||
| 189 | |||
| 190 | const auto& context{thread->GetContext64()}; | ||
| 191 | const auto& gprs{context.cpu_registers}; | ||
| 192 | const auto& fprs{context.vector_registers}; | ||
| 193 | |||
| 194 | if (id <= SP_REGISTER) { | ||
| 195 | return ValueToHex(gprs[id]); | ||
| 196 | } else if (id == PC_REGISTER) { | ||
| 197 | return ValueToHex(context.pc); | ||
| 198 | } else if (id == PSTATE_REGISTER) { | ||
| 199 | return ValueToHex(context.pstate); | ||
| 200 | } else if (id >= Q0_REGISTER && id < FPSR_REGISTER) { | ||
| 201 | return ValueToHex(fprs[id - Q0_REGISTER]); | ||
| 202 | } else if (id == FPSR_REGISTER) { | ||
| 203 | return ValueToHex(context.fpsr); | ||
| 204 | } else if (id == FPCR_REGISTER) { | ||
| 205 | return ValueToHex(context.fpcr); | ||
| 206 | } else { | ||
| 207 | return ""; | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const { | ||
| 212 | if (!thread) { | ||
| 213 | return; | ||
| 214 | } | ||
| 215 | |||
| 216 | auto& context{thread->GetContext64()}; | ||
| 217 | |||
| 218 | if (id <= SP_REGISTER) { | ||
| 219 | context.cpu_registers[id] = HexToValue<u64>(value); | ||
| 220 | } else if (id == PC_REGISTER) { | ||
| 221 | context.pc = HexToValue<u64>(value); | ||
| 222 | } else if (id == PSTATE_REGISTER) { | ||
| 223 | context.pstate = HexToValue<u32>(value); | ||
| 224 | } else if (id >= Q0_REGISTER && id < FPSR_REGISTER) { | ||
| 225 | context.vector_registers[id - Q0_REGISTER] = HexToValue<u128>(value); | ||
| 226 | } else if (id == FPSR_REGISTER) { | ||
| 227 | context.fpsr = HexToValue<u32>(value); | ||
| 228 | } else if (id == FPCR_REGISTER) { | ||
| 229 | context.fpcr = HexToValue<u32>(value); | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | std::string GDBStubA64::ReadRegisters(const Kernel::KThread* thread) const { | ||
| 234 | std::string output; | ||
| 235 | |||
| 236 | for (size_t reg = 0; reg <= FPCR_REGISTER; reg++) { | ||
| 237 | output += RegRead(thread, reg); | ||
| 238 | } | ||
| 239 | |||
| 240 | return output; | ||
| 241 | } | ||
| 242 | |||
| 243 | void GDBStubA64::WriteRegisters(Kernel::KThread* thread, std::string_view register_data) const { | ||
| 244 | for (size_t i = 0, reg = 0; reg <= FPCR_REGISTER; reg++) { | ||
| 245 | if (reg <= SP_REGISTER || reg == PC_REGISTER) { | ||
| 246 | RegWrite(thread, reg, register_data.substr(i, 16)); | ||
| 247 | i += 16; | ||
| 248 | } else if (reg == PSTATE_REGISTER || reg == FPCR_REGISTER || reg == FPSR_REGISTER) { | ||
| 249 | RegWrite(thread, reg, register_data.substr(i, 8)); | ||
| 250 | i += 8; | ||
| 251 | } else if (reg >= Q0_REGISTER && reg < FPCR_REGISTER) { | ||
| 252 | RegWrite(thread, reg, register_data.substr(i, 32)); | ||
| 253 | i += 32; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | } | ||
| 257 | |||
| 258 | std::string GDBStubA64::ThreadStatus(const Kernel::KThread* thread, u8 signal) const { | ||
| 259 | return fmt::format("T{:02x}{:02x}:{};{:02x}:{};{:02x}:{};thread:{:x};", signal, PC_REGISTER, | ||
| 260 | RegRead(thread, PC_REGISTER), SP_REGISTER, RegRead(thread, SP_REGISTER), | ||
| 261 | LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadID()); | ||
| 262 | } | ||
| 263 | |||
| 264 | u32 GDBStubA64::BreakpointInstruction() const { | ||
| 265 | // A64: brk #0 | ||
| 266 | return 0xd4200000; | ||
| 267 | } | ||
| 268 | |||
| 269 | std::string GDBStubA32::GetTargetXML() const { | ||
| 270 | constexpr const char* target_xml = | ||
| 271 | R"(<?xml version="1.0"?> | ||
| 272 | <!DOCTYPE target SYSTEM "gdb-target.dtd"> | ||
| 273 | <target version="1.0"> | ||
| 274 | <architecture>arm</architecture> | ||
| 275 | <feature name="org.gnu.gdb.arm.core"> | ||
| 276 | <reg name="r0" bitsize="32" type="uint32"/> | ||
| 277 | <reg name="r1" bitsize="32" type="uint32"/> | ||
| 278 | <reg name="r2" bitsize="32" type="uint32"/> | ||
| 279 | <reg name="r3" bitsize="32" type="uint32"/> | ||
| 280 | <reg name="r4" bitsize="32" type="uint32"/> | ||
| 281 | <reg name="r5" bitsize="32" type="uint32"/> | ||
| 282 | <reg name="r6" bitsize="32" type="uint32"/> | ||
| 283 | <reg name="r7" bitsize="32" type="uint32"/> | ||
| 284 | <reg name="r8" bitsize="32" type="uint32"/> | ||
| 285 | <reg name="r9" bitsize="32" type="uint32"/> | ||
| 286 | <reg name="r10" bitsize="32" type="uint32"/> | ||
| 287 | <reg name="r11" bitsize="32" type="uint32"/> | ||
| 288 | <reg name="r12" bitsize="32" type="uint32"/> | ||
| 289 | <reg name="sp" bitsize="32" type="data_ptr"/> | ||
| 290 | <reg name="lr" bitsize="32" type="code_ptr"/> | ||
| 291 | <reg name="pc" bitsize="32" type="code_ptr"/> | ||
| 292 | <!-- The CPSR is register 25, rather than register 16, because | ||
| 293 | the FPA registers historically were placed between the PC | ||
| 294 | and the CPSR in the "g" packet. --> | ||
| 295 | <reg name="cpsr" bitsize="32" regnum="25"/> | ||
| 296 | </feature> | ||
| 297 | <feature name="org.gnu.gdb.arm.vfp"> | ||
| 298 | <vector id="neon_uint8x8" type="uint8" count="8"/> | ||
| 299 | <vector id="neon_uint16x4" type="uint16" count="4"/> | ||
| 300 | <vector id="neon_uint32x2" type="uint32" count="2"/> | ||
| 301 | <vector id="neon_float32x2" type="ieee_single" count="2"/> | ||
| 302 | <union id="neon_d"> | ||
| 303 | <field name="u8" type="neon_uint8x8"/> | ||
| 304 | <field name="u16" type="neon_uint16x4"/> | ||
| 305 | <field name="u32" type="neon_uint32x2"/> | ||
| 306 | <field name="u64" type="uint64"/> | ||
| 307 | <field name="f32" type="neon_float32x2"/> | ||
| 308 | <field name="f64" type="ieee_double"/> | ||
| 309 | </union> | ||
| 310 | <vector id="neon_uint8x16" type="uint8" count="16"/> | ||
| 311 | <vector id="neon_uint16x8" type="uint16" count="8"/> | ||
| 312 | <vector id="neon_uint32x4" type="uint32" count="4"/> | ||
| 313 | <vector id="neon_uint64x2" type="uint64" count="2"/> | ||
| 314 | <vector id="neon_float32x4" type="ieee_single" count="4"/> | ||
| 315 | <vector id="neon_float64x2" type="ieee_double" count="2"/> | ||
| 316 | <union id="neon_q"> | ||
| 317 | <field name="u8" type="neon_uint8x16"/> | ||
| 318 | <field name="u16" type="neon_uint16x8"/> | ||
| 319 | <field name="u32" type="neon_uint32x4"/> | ||
| 320 | <field name="u64" type="neon_uint64x2"/> | ||
| 321 | <field name="f32" type="neon_float32x4"/> | ||
| 322 | <field name="f64" type="neon_float64x2"/> | ||
| 323 | </union> | ||
| 324 | <reg name="d0" bitsize="64" type="neon_d" regnum="32"/> | ||
| 325 | <reg name="d1" bitsize="64" type="neon_d"/> | ||
| 326 | <reg name="d2" bitsize="64" type="neon_d"/> | ||
| 327 | <reg name="d3" bitsize="64" type="neon_d"/> | ||
| 328 | <reg name="d4" bitsize="64" type="neon_d"/> | ||
| 329 | <reg name="d5" bitsize="64" type="neon_d"/> | ||
| 330 | <reg name="d6" bitsize="64" type="neon_d"/> | ||
| 331 | <reg name="d7" bitsize="64" type="neon_d"/> | ||
| 332 | <reg name="d8" bitsize="64" type="neon_d"/> | ||
| 333 | <reg name="d9" bitsize="64" type="neon_d"/> | ||
| 334 | <reg name="d10" bitsize="64" type="neon_d"/> | ||
| 335 | <reg name="d11" bitsize="64" type="neon_d"/> | ||
| 336 | <reg name="d12" bitsize="64" type="neon_d"/> | ||
| 337 | <reg name="d13" bitsize="64" type="neon_d"/> | ||
| 338 | <reg name="d14" bitsize="64" type="neon_d"/> | ||
| 339 | <reg name="d15" bitsize="64" type="neon_d"/> | ||
| 340 | <reg name="d16" bitsize="64" type="neon_d"/> | ||
| 341 | <reg name="d17" bitsize="64" type="neon_d"/> | ||
| 342 | <reg name="d18" bitsize="64" type="neon_d"/> | ||
| 343 | <reg name="d19" bitsize="64" type="neon_d"/> | ||
| 344 | <reg name="d20" bitsize="64" type="neon_d"/> | ||
| 345 | <reg name="d21" bitsize="64" type="neon_d"/> | ||
| 346 | <reg name="d22" bitsize="64" type="neon_d"/> | ||
| 347 | <reg name="d23" bitsize="64" type="neon_d"/> | ||
| 348 | <reg name="d24" bitsize="64" type="neon_d"/> | ||
| 349 | <reg name="d25" bitsize="64" type="neon_d"/> | ||
| 350 | <reg name="d26" bitsize="64" type="neon_d"/> | ||
| 351 | <reg name="d27" bitsize="64" type="neon_d"/> | ||
| 352 | <reg name="d28" bitsize="64" type="neon_d"/> | ||
| 353 | <reg name="d29" bitsize="64" type="neon_d"/> | ||
| 354 | <reg name="d30" bitsize="64" type="neon_d"/> | ||
| 355 | <reg name="d31" bitsize="64" type="neon_d"/> | ||
| 356 | |||
| 357 | <reg name="q0" bitsize="128" type="neon_q" regnum="64"/> | ||
| 358 | <reg name="q1" bitsize="128" type="neon_q"/> | ||
| 359 | <reg name="q2" bitsize="128" type="neon_q"/> | ||
| 360 | <reg name="q3" bitsize="128" type="neon_q"/> | ||
| 361 | <reg name="q4" bitsize="128" type="neon_q"/> | ||
| 362 | <reg name="q5" bitsize="128" type="neon_q"/> | ||
| 363 | <reg name="q6" bitsize="128" type="neon_q"/> | ||
| 364 | <reg name="q7" bitsize="128" type="neon_q"/> | ||
| 365 | <reg name="q8" bitsize="128" type="neon_q"/> | ||
| 366 | <reg name="q9" bitsize="128" type="neon_q"/> | ||
| 367 | <reg name="q10" bitsize="128" type="neon_q"/> | ||
| 368 | <reg name="q10" bitsize="128" type="neon_q"/> | ||
| 369 | <reg name="q12" bitsize="128" type="neon_q"/> | ||
| 370 | <reg name="q13" bitsize="128" type="neon_q"/> | ||
| 371 | <reg name="q14" bitsize="128" type="neon_q"/> | ||
| 372 | <reg name="q15" bitsize="128" type="neon_q"/> | ||
| 373 | |||
| 374 | <reg name="fpscr" bitsize="32" type="int" group="float" regnum="80"/> | ||
| 375 | </feature> | ||
| 376 | </target>)"; | ||
| 377 | |||
| 378 | return target_xml; | ||
| 379 | } | ||
| 380 | |||
| 381 | std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const { | ||
| 382 | if (!thread) { | ||
| 383 | return ""; | ||
| 384 | } | ||
| 385 | |||
| 386 | const auto& context{thread->GetContext32()}; | ||
| 387 | const auto& gprs{context.cpu_registers}; | ||
| 388 | const auto& fprs{context.extension_registers}; | ||
| 389 | |||
| 390 | if (id <= PC_REGISTER) { | ||
| 391 | return ValueToHex(gprs[id]); | ||
| 392 | } else if (id == CPSR_REGISTER) { | ||
| 393 | return ValueToHex(context.cpsr); | ||
| 394 | } else if (id >= D0_REGISTER && id < Q0_REGISTER) { | ||
| 395 | const u64 dN{GetSIMDRegister<u64>(fprs, id - D0_REGISTER)}; | ||
| 396 | return ValueToHex(dN); | ||
| 397 | } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { | ||
| 398 | const u128 qN{GetSIMDRegister<u128>(fprs, id - Q0_REGISTER)}; | ||
| 399 | return ValueToHex(qN); | ||
| 400 | } else if (id == FPSCR_REGISTER) { | ||
| 401 | return ValueToHex(context.fpscr); | ||
| 402 | } else { | ||
| 403 | return ""; | ||
| 404 | } | ||
| 405 | } | ||
| 406 | |||
| 407 | void GDBStubA32::RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const { | ||
| 408 | if (!thread) { | ||
| 409 | return; | ||
| 410 | } | ||
| 411 | |||
| 412 | auto& context{thread->GetContext32()}; | ||
| 413 | auto& fprs{context.extension_registers}; | ||
| 414 | |||
| 415 | if (id <= PC_REGISTER) { | ||
| 416 | context.cpu_registers[id] = HexToValue<u32>(value); | ||
| 417 | } else if (id == CPSR_REGISTER) { | ||
| 418 | context.cpsr = HexToValue<u32>(value); | ||
| 419 | } else if (id >= D0_REGISTER && id < Q0_REGISTER) { | ||
| 420 | PutSIMDRegister(fprs, id - D0_REGISTER, HexToValue<u64>(value)); | ||
| 421 | } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { | ||
| 422 | PutSIMDRegister(fprs, id - Q0_REGISTER, HexToValue<u128>(value)); | ||
| 423 | } else if (id == FPSCR_REGISTER) { | ||
| 424 | context.fpscr = HexToValue<u32>(value); | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | std::string GDBStubA32::ReadRegisters(const Kernel::KThread* thread) const { | ||
| 429 | std::string output; | ||
| 430 | |||
| 431 | for (size_t reg = 0; reg <= FPSCR_REGISTER; reg++) { | ||
| 432 | const bool gpr{reg <= PC_REGISTER}; | ||
| 433 | const bool dfpr{reg >= D0_REGISTER && reg < Q0_REGISTER}; | ||
| 434 | const bool qfpr{reg >= Q0_REGISTER && reg < FPSCR_REGISTER}; | ||
| 435 | |||
| 436 | if (!(gpr || dfpr || qfpr || reg == CPSR_REGISTER || reg == FPSCR_REGISTER)) { | ||
| 437 | continue; | ||
| 438 | } | ||
| 439 | |||
| 440 | output += RegRead(thread, reg); | ||
| 441 | } | ||
| 442 | |||
| 443 | return output; | ||
| 444 | } | ||
| 445 | |||
| 446 | void GDBStubA32::WriteRegisters(Kernel::KThread* thread, std::string_view register_data) const { | ||
| 447 | for (size_t i = 0, reg = 0; reg <= FPSCR_REGISTER; reg++) { | ||
| 448 | const bool gpr{reg <= PC_REGISTER}; | ||
| 449 | const bool dfpr{reg >= D0_REGISTER && reg < Q0_REGISTER}; | ||
| 450 | const bool qfpr{reg >= Q0_REGISTER && reg < FPSCR_REGISTER}; | ||
| 451 | |||
| 452 | if (gpr || reg == CPSR_REGISTER || reg == FPSCR_REGISTER) { | ||
| 453 | RegWrite(thread, reg, register_data.substr(i, 8)); | ||
| 454 | i += 8; | ||
| 455 | } else if (dfpr) { | ||
| 456 | RegWrite(thread, reg, register_data.substr(i, 16)); | ||
| 457 | i += 16; | ||
| 458 | } else if (qfpr) { | ||
| 459 | RegWrite(thread, reg, register_data.substr(i, 32)); | ||
| 460 | i += 32; | ||
| 461 | } | ||
| 462 | |||
| 463 | if (reg == PC_REGISTER) { | ||
| 464 | reg = CPSR_REGISTER - 1; | ||
| 465 | } else if (reg == CPSR_REGISTER) { | ||
| 466 | reg = D0_REGISTER - 1; | ||
| 467 | } | ||
| 468 | } | ||
| 469 | } | ||
| 470 | |||
| 471 | std::string GDBStubA32::ThreadStatus(const Kernel::KThread* thread, u8 signal) const { | ||
| 472 | return fmt::format("T{:02x}{:02x}:{};{:02x}:{};{:02x}:{};thread:{:x};", signal, PC_REGISTER, | ||
| 473 | RegRead(thread, PC_REGISTER), SP_REGISTER, RegRead(thread, SP_REGISTER), | ||
| 474 | LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadID()); | ||
| 475 | } | ||
| 476 | |||
| 477 | u32 GDBStubA32::BreakpointInstruction() const { | ||
| 478 | // A32: trap | ||
| 479 | // T32: trap + b #4 | ||
| 480 | return 0xe7ffdefe; | ||
| 481 | } | ||
| 482 | |||
| 483 | } // namespace Core | ||
diff --git a/src/core/debugger/gdbstub_arch.h b/src/core/debugger/gdbstub_arch.h new file mode 100644 index 000000000..2540d6456 --- /dev/null +++ b/src/core/debugger/gdbstub_arch.h | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <string> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | class KThread; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Core { | ||
| 15 | |||
| 16 | class GDBStubArch { | ||
| 17 | public: | ||
| 18 | virtual ~GDBStubArch() = default; | ||
| 19 | virtual std::string GetTargetXML() const = 0; | ||
| 20 | virtual std::string RegRead(const Kernel::KThread* thread, size_t id) const = 0; | ||
| 21 | virtual void RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const = 0; | ||
| 22 | virtual std::string ReadRegisters(const Kernel::KThread* thread) const = 0; | ||
| 23 | virtual void WriteRegisters(Kernel::KThread* thread, std::string_view register_data) const = 0; | ||
| 24 | virtual std::string ThreadStatus(const Kernel::KThread* thread, u8 signal) const = 0; | ||
| 25 | virtual u32 BreakpointInstruction() const = 0; | ||
| 26 | }; | ||
| 27 | |||
| 28 | class GDBStubA64 final : public GDBStubArch { | ||
| 29 | public: | ||
| 30 | std::string GetTargetXML() const override; | ||
| 31 | std::string RegRead(const Kernel::KThread* thread, size_t id) const override; | ||
| 32 | void RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const override; | ||
| 33 | std::string ReadRegisters(const Kernel::KThread* thread) const override; | ||
| 34 | void WriteRegisters(Kernel::KThread* thread, std::string_view register_data) const override; | ||
| 35 | std::string ThreadStatus(const Kernel::KThread* thread, u8 signal) const override; | ||
| 36 | u32 BreakpointInstruction() const override; | ||
| 37 | |||
| 38 | private: | ||
| 39 | static constexpr u32 LR_REGISTER = 30; | ||
| 40 | static constexpr u32 SP_REGISTER = 31; | ||
| 41 | static constexpr u32 PC_REGISTER = 32; | ||
| 42 | static constexpr u32 PSTATE_REGISTER = 33; | ||
| 43 | static constexpr u32 Q0_REGISTER = 34; | ||
| 44 | static constexpr u32 FPSR_REGISTER = 66; | ||
| 45 | static constexpr u32 FPCR_REGISTER = 67; | ||
| 46 | }; | ||
| 47 | |||
| 48 | class GDBStubA32 final : public GDBStubArch { | ||
| 49 | public: | ||
| 50 | std::string GetTargetXML() const override; | ||
| 51 | std::string RegRead(const Kernel::KThread* thread, size_t id) const override; | ||
| 52 | void RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const override; | ||
| 53 | std::string ReadRegisters(const Kernel::KThread* thread) const override; | ||
| 54 | void WriteRegisters(Kernel::KThread* thread, std::string_view register_data) const override; | ||
| 55 | std::string ThreadStatus(const Kernel::KThread* thread, u8 signal) const override; | ||
| 56 | u32 BreakpointInstruction() const override; | ||
| 57 | |||
| 58 | private: | ||
| 59 | static constexpr u32 SP_REGISTER = 13; | ||
| 60 | static constexpr u32 LR_REGISTER = 14; | ||
| 61 | static constexpr u32 PC_REGISTER = 15; | ||
| 62 | static constexpr u32 CPSR_REGISTER = 25; | ||
| 63 | static constexpr u32 D0_REGISTER = 32; | ||
| 64 | static constexpr u32 Q0_REGISTER = 64; | ||
| 65 | static constexpr u32 FPSCR_REGISTER = 80; | ||
| 66 | }; | ||
| 67 | |||
| 68 | } // namespace Core | ||
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 93f784418..78e56bbbd 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp | |||
| @@ -419,7 +419,7 @@ std::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type | |||
| 419 | Core::Crypto::Mode::ECB); | 419 | Core::Crypto::Mode::ECB); |
| 420 | cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Core::Crypto::Op::Decrypt); | 420 | cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Core::Crypto::Op::Decrypt); |
| 421 | 421 | ||
| 422 | Core::Crypto::Key128 out; | 422 | Core::Crypto::Key128 out{}; |
| 423 | if (type == NCASectionCryptoType::XTS) { | 423 | if (type == NCASectionCryptoType::XTS) { |
| 424 | std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin()); | 424 | std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin()); |
| 425 | } else if (type == NCASectionCryptoType::CTR || type == NCASectionCryptoType::BKTR) { | 425 | } else if (type == NCASectionCryptoType::CTR || type == NCASectionCryptoType::BKTR) { |
diff --git a/src/core/file_sys/nca_patch.cpp b/src/core/file_sys/nca_patch.cpp index d4c0a974a..2735d053b 100644 --- a/src/core/file_sys/nca_patch.cpp +++ b/src/core/file_sys/nca_patch.cpp | |||
| @@ -50,7 +50,7 @@ std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, const BlockTyp | |||
| 50 | low = mid + 1; | 50 | low = mid + 1; |
| 51 | } | 51 | } |
| 52 | } | 52 | } |
| 53 | UNREACHABLE_MSG("Offset could not be found in BKTR block."); | 53 | ASSERT_MSG(false, "Offset could not be found in BKTR block."); |
| 54 | return {0, 0}; | 54 | return {0, 0}; |
| 55 | } | 55 | } |
| 56 | } // Anonymous namespace | 56 | } // Anonymous namespace |
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 2eaac73ef..878d832c2 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp | |||
| @@ -108,7 +108,7 @@ ContentRecordType GetCRTypeFromNCAType(NCAContentType type) { | |||
| 108 | // TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal. | 108 | // TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal. |
| 109 | return ContentRecordType::HtmlDocument; | 109 | return ContentRecordType::HtmlDocument; |
| 110 | default: | 110 | default: |
| 111 | UNREACHABLE_MSG("Invalid NCAContentType={:02X}", type); | 111 | ASSERT_MSG(false, "Invalid NCAContentType={:02X}", type); |
| 112 | return ContentRecordType{}; | 112 | return ContentRecordType{}; |
| 113 | } | 113 | } |
| 114 | } | 114 | } |
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index e42d7c9f6..cc0076238 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp | |||
| @@ -144,7 +144,7 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_ | |||
| 144 | LOG_ERROR(Service_FS, "Failed to open path {} in order to re-cache it", new_path); | 144 | LOG_ERROR(Service_FS, "Failed to open path {} in order to re-cache it", new_path); |
| 145 | } | 145 | } |
| 146 | } else { | 146 | } else { |
| 147 | UNREACHABLE(); | 147 | ASSERT(false); |
| 148 | return nullptr; | 148 | return nullptr; |
| 149 | } | 149 | } |
| 150 | 150 | ||
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 0ff2a338e..6c230f619 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp | |||
| @@ -65,7 +65,7 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb | |||
| 65 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); | 65 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); |
| 66 | controller->Connect(true); | 66 | controller->Connect(true); |
| 67 | } else { | 67 | } else { |
| 68 | UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); | 68 | ASSERT_MSG(false, "Unable to add a new controller based on the given parameters!"); |
| 69 | } | 69 | } |
| 70 | } | 70 | } |
| 71 | 71 | ||
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index fd220ccb5..aac45907d 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp | |||
| @@ -27,12 +27,19 @@ void EmulatedConsole::SetTouchParams() { | |||
| 27 | // We can't use mouse as touch if native mouse is enabled | 27 | // We can't use mouse as touch if native mouse is enabled |
| 28 | touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; | 28 | touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; |
| 29 | } | 29 | } |
| 30 | touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"}; | 30 | |
| 31 | touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"}; | 31 | touch_params[index++] = |
| 32 | Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0,touch_id:0"}; | ||
| 33 | touch_params[index++] = | ||
| 34 | Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1,touch_id:1"}; | ||
| 35 | touch_params[index++] = | ||
| 36 | Common::ParamPackage{"engine:touch,axis_x:4,axis_y:5,button:2,touch_id:2"}; | ||
| 37 | touch_params[index++] = | ||
| 38 | Common::ParamPackage{"engine:touch,axis_x:6,axis_y:7,button:3,touch_id:3"}; | ||
| 32 | touch_params[index++] = | 39 | touch_params[index++] = |
| 33 | Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"}; | 40 | Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536,touch_id:0"}; |
| 34 | touch_params[index++] = | 41 | touch_params[index++] = |
| 35 | Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"}; | 42 | Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072,touch_id:1"}; |
| 36 | 43 | ||
| 37 | const auto button_index = | 44 | const auto button_index = |
| 38 | static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue()); | 45 | static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue()); |
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index ba1dcd171..bd2384515 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -884,18 +884,42 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v | |||
| 884 | } | 884 | } |
| 885 | 885 | ||
| 886 | bool EmulatedController::TestVibration(std::size_t device_index) { | 886 | bool EmulatedController::TestVibration(std::size_t device_index) { |
| 887 | static constexpr VibrationValue test_vibration = { | 887 | if (device_index >= output_devices.size()) { |
| 888 | return false; | ||
| 889 | } | ||
| 890 | if (!output_devices[device_index]) { | ||
| 891 | return false; | ||
| 892 | } | ||
| 893 | |||
| 894 | const auto player_index = NpadIdTypeToIndex(npad_id_type); | ||
| 895 | const auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 896 | |||
| 897 | if (!player.vibration_enabled) { | ||
| 898 | return false; | ||
| 899 | } | ||
| 900 | |||
| 901 | const Common::Input::VibrationStatus test_vibration = { | ||
| 888 | .low_amplitude = 0.001f, | 902 | .low_amplitude = 0.001f, |
| 889 | .low_frequency = 160.0f, | 903 | .low_frequency = DEFAULT_VIBRATION_VALUE.low_frequency, |
| 890 | .high_amplitude = 0.001f, | 904 | .high_amplitude = 0.001f, |
| 891 | .high_frequency = 320.0f, | 905 | .high_frequency = DEFAULT_VIBRATION_VALUE.high_frequency, |
| 906 | .type = Common::Input::VibrationAmplificationType::Test, | ||
| 907 | }; | ||
| 908 | |||
| 909 | const Common::Input::VibrationStatus zero_vibration = { | ||
| 910 | .low_amplitude = DEFAULT_VIBRATION_VALUE.low_amplitude, | ||
| 911 | .low_frequency = DEFAULT_VIBRATION_VALUE.low_frequency, | ||
| 912 | .high_amplitude = DEFAULT_VIBRATION_VALUE.high_amplitude, | ||
| 913 | .high_frequency = DEFAULT_VIBRATION_VALUE.high_frequency, | ||
| 914 | .type = Common::Input::VibrationAmplificationType::Test, | ||
| 892 | }; | 915 | }; |
| 893 | 916 | ||
| 894 | // Send a slight vibration to test for rumble support | 917 | // Send a slight vibration to test for rumble support |
| 895 | SetVibration(device_index, test_vibration); | 918 | output_devices[device_index]->SetVibration(test_vibration); |
| 896 | 919 | ||
| 897 | // Stop any vibration and return the result | 920 | // Stop any vibration and return the result |
| 898 | return SetVibration(device_index, DEFAULT_VIBRATION_VALUE); | 921 | return output_devices[device_index]->SetVibration(zero_vibration) == |
| 922 | Common::Input::VibrationError::None; | ||
| 899 | } | 923 | } |
| 900 | 924 | ||
| 901 | bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) { | 925 | bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) { |
diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp index 7eed52593..7d6373414 100644 --- a/src/core/hid/hid_core.cpp +++ b/src/core/hid/hid_core.cpp | |||
| @@ -48,7 +48,7 @@ EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type) { | |||
| 48 | return handheld.get(); | 48 | return handheld.get(); |
| 49 | case NpadIdType::Invalid: | 49 | case NpadIdType::Invalid: |
| 50 | default: | 50 | default: |
| 51 | UNREACHABLE_MSG("Invalid NpadIdType={}", npad_id_type); | 51 | ASSERT_MSG(false, "Invalid NpadIdType={}", npad_id_type); |
| 52 | return nullptr; | 52 | return nullptr; |
| 53 | } | 53 | } |
| 54 | } | 54 | } |
| @@ -77,7 +77,7 @@ const EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type | |||
| 77 | return handheld.get(); | 77 | return handheld.get(); |
| 78 | case NpadIdType::Invalid: | 78 | case NpadIdType::Invalid: |
| 79 | default: | 79 | default: |
| 80 | UNREACHABLE_MSG("Invalid NpadIdType={}", npad_id_type); | 80 | ASSERT_MSG(false, "Invalid NpadIdType={}", npad_id_type); |
| 81 | return nullptr; | 81 | return nullptr; |
| 82 | } | 82 | } |
| 83 | } | 83 | } |
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 26ec1091b..9f76f9bcb 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h | |||
| @@ -498,6 +498,49 @@ struct SixAxisSensorFusionParameters { | |||
| 498 | static_assert(sizeof(SixAxisSensorFusionParameters) == 8, | 498 | static_assert(sizeof(SixAxisSensorFusionParameters) == 8, |
| 499 | "SixAxisSensorFusionParameters is an invalid size"); | 499 | "SixAxisSensorFusionParameters is an invalid size"); |
| 500 | 500 | ||
| 501 | // This is nn::hid::server::SixAxisSensorProperties | ||
| 502 | struct SixAxisSensorProperties { | ||
| 503 | union { | ||
| 504 | u8 raw{}; | ||
| 505 | BitField<0, 1, u8> is_newly_assigned; | ||
| 506 | BitField<1, 1, u8> is_firmware_update_available; | ||
| 507 | }; | ||
| 508 | }; | ||
| 509 | static_assert(sizeof(SixAxisSensorProperties) == 1, "SixAxisSensorProperties is an invalid size"); | ||
| 510 | |||
| 511 | // This is nn::hid::SixAxisSensorCalibrationParameter | ||
| 512 | struct SixAxisSensorCalibrationParameter { | ||
| 513 | std::array<u8, 0x744> unknown_data{}; | ||
| 514 | }; | ||
| 515 | static_assert(sizeof(SixAxisSensorCalibrationParameter) == 0x744, | ||
| 516 | "SixAxisSensorCalibrationParameter is an invalid size"); | ||
| 517 | |||
| 518 | // This is nn::hid::SixAxisSensorIcInformation | ||
| 519 | struct SixAxisSensorIcInformation { | ||
| 520 | f32 angular_rate{2000.0f}; // dps | ||
| 521 | std::array<f32, 6> unknown_gyro_data1{ | ||
| 522 | -10.0f, -10.0f, -10.0f, 10.0f, 10.0f, 10.0f, | ||
| 523 | }; // dps | ||
| 524 | std::array<f32, 9> unknown_gyro_data2{ | ||
| 525 | 0.95f, -0.003f, -0.003f, -0.003f, 0.95f, -0.003f, -0.003f, -0.003f, 0.95f, | ||
| 526 | }; | ||
| 527 | std::array<f32, 9> unknown_gyro_data3{ | ||
| 528 | 1.05f, 0.003f, 0.003f, 0.003f, 1.05f, 0.003f, 0.003f, 0.003f, 1.05f, | ||
| 529 | }; | ||
| 530 | f32 acceleration_range{8.0f}; // g force | ||
| 531 | std::array<f32, 6> unknown_accel_data1{ | ||
| 532 | -0.0612f, -0.0612f, -0.0612f, 0.0612f, 0.0612f, 0.0612f, | ||
| 533 | }; // g force | ||
| 534 | std::array<f32, 9> unknown_accel_data2{ | ||
| 535 | 0.95f, -0.003f, -0.003f, -0.003f, 0.95f, -0.003f, -0.003f, -0.003f, 0.95f, | ||
| 536 | }; | ||
| 537 | std::array<f32, 9> unknown_accel_data3{ | ||
| 538 | 1.05f, 0.003f, 0.003f, 0.003f, 1.05f, 0.003f, 0.003f, 0.003f, 1.05f, | ||
| 539 | }; | ||
| 540 | }; | ||
| 541 | static_assert(sizeof(SixAxisSensorIcInformation) == 0xC8, | ||
| 542 | "SixAxisSensorIcInformation is an invalid size"); | ||
| 543 | |||
| 501 | // This is nn::hid::VibrationDeviceHandle | 544 | // This is nn::hid::VibrationDeviceHandle |
| 502 | struct VibrationDeviceHandle { | 545 | struct VibrationDeviceHandle { |
| 503 | NpadStyleIndex npad_type{NpadStyleIndex::None}; | 546 | NpadStyleIndex npad_type{NpadStyleIndex::None}; |
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 3c26260f3..18d9f042d 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.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 <algorithm> | ||
| 4 | #include <random> | 5 | #include <random> |
| 5 | 6 | ||
| 6 | #include "common/input.h" | 7 | #include "common/input.h" |
| @@ -196,6 +197,9 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& | |||
| 196 | x = std::clamp(x, 0.0f, 1.0f); | 197 | x = std::clamp(x, 0.0f, 1.0f); |
| 197 | y = std::clamp(y, 0.0f, 1.0f); | 198 | y = std::clamp(y, 0.0f, 1.0f); |
| 198 | 199 | ||
| 200 | // Limit id to maximum number of fingers | ||
| 201 | status.id = std::clamp(status.id, 0, 16); | ||
| 202 | |||
| 199 | if (status.pressed.inverted) { | 203 | if (status.pressed.inverted) { |
| 200 | status.pressed.value = !status.pressed.value; | 204 | status.pressed.value = !status.pressed.value; |
| 201 | } | 205 | } |
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index a427cbc93..0ddc8df9e 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -141,7 +141,7 @@ public: | |||
| 141 | if (index < DomainHandlerCount()) { | 141 | if (index < DomainHandlerCount()) { |
| 142 | domain_handlers[index] = nullptr; | 142 | domain_handlers[index] = nullptr; |
| 143 | } else { | 143 | } else { |
| 144 | UNREACHABLE_MSG("Unexpected handler index {}", index); | 144 | ASSERT_MSG(false, "Unexpected handler index {}", index); |
| 145 | } | 145 | } |
| 146 | } | 146 | } |
| 147 | 147 | ||
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 34a8be052..9b6b284d0 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp | |||
| @@ -244,7 +244,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) { | |||
| 244 | FOREACH_SLAB_TYPE(INITIALIZE_SLAB_HEAP) | 244 | FOREACH_SLAB_TYPE(INITIALIZE_SLAB_HEAP) |
| 245 | // If we somehow get an invalid type, abort. | 245 | // If we somehow get an invalid type, abort. |
| 246 | default: | 246 | default: |
| 247 | UNREACHABLE_MSG("Unknown slab type: {}", slab_types[i]); | 247 | ASSERT_MSG(false, "Unknown slab type: {}", slab_types[i]); |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | // If we've hit the end of a gap, free it. | 250 | // If we've hit the end of a gap, free it. |
diff --git a/src/core/hle/kernel/k_address_arbiter.h b/src/core/hle/kernel/k_address_arbiter.h index e46e0d848..5fa19d386 100644 --- a/src/core/hle/kernel/k_address_arbiter.h +++ b/src/core/hle/kernel/k_address_arbiter.h | |||
| @@ -35,7 +35,7 @@ public: | |||
| 35 | case Svc::SignalType::SignalAndModifyByWaitingCountIfEqual: | 35 | case Svc::SignalType::SignalAndModifyByWaitingCountIfEqual: |
| 36 | return SignalAndModifyByWaitingCountIfEqual(addr, value, count); | 36 | return SignalAndModifyByWaitingCountIfEqual(addr, value, count); |
| 37 | } | 37 | } |
| 38 | UNREACHABLE(); | 38 | ASSERT(false); |
| 39 | return ResultUnknown; | 39 | return ResultUnknown; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| @@ -49,7 +49,7 @@ public: | |||
| 49 | case Svc::ArbitrationType::WaitIfEqual: | 49 | case Svc::ArbitrationType::WaitIfEqual: |
| 50 | return WaitIfEqual(addr, value, timeout); | 50 | return WaitIfEqual(addr, value, timeout); |
| 51 | } | 51 | } |
| 52 | UNREACHABLE(); | 52 | ASSERT(false); |
| 53 | return ResultUnknown; | 53 | return ResultUnknown; |
| 54 | } | 54 | } |
| 55 | 55 | ||
diff --git a/src/core/hle/kernel/k_address_space_info.cpp b/src/core/hle/kernel/k_address_space_info.cpp index bc37cadda..3e612a207 100644 --- a/src/core/hle/kernel/k_address_space_info.cpp +++ b/src/core/hle/kernel/k_address_space_info.cpp | |||
| @@ -84,7 +84,7 @@ u64 KAddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) { | |||
| 84 | ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[index])); | 84 | ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[index])); |
| 85 | return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address; | 85 | return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address; |
| 86 | } | 86 | } |
| 87 | UNREACHABLE(); | 87 | ASSERT(false); |
| 88 | return 0; | 88 | return 0; |
| 89 | } | 89 | } |
| 90 | 90 | ||
| @@ -101,7 +101,7 @@ std::size_t KAddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) | |||
| 101 | ASSERT(IsAllowed39BitType(type)); | 101 | ASSERT(IsAllowed39BitType(type)); |
| 102 | return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size; | 102 | return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size; |
| 103 | } | 103 | } |
| 104 | UNREACHABLE(); | 104 | ASSERT(false); |
| 105 | return 0; | 105 | return 0; |
| 106 | } | 106 | } |
| 107 | 107 | ||
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index ea47fc600..2827763d5 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h | |||
| @@ -18,7 +18,7 @@ namespace Kernel { | |||
| 18 | class KernelCore; | 18 | class KernelCore; |
| 19 | class KProcess; | 19 | class KProcess; |
| 20 | 20 | ||
| 21 | #define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \ | 21 | #define KERNEL_AUTOOBJECT_TRAITS_IMPL(CLASS, BASE_CLASS, ATTRIBUTE) \ |
| 22 | \ | 22 | \ |
| 23 | private: \ | 23 | private: \ |
| 24 | friend class ::Kernel::KClassTokenGenerator; \ | 24 | friend class ::Kernel::KClassTokenGenerator; \ |
| @@ -40,16 +40,19 @@ public: | |||
| 40 | static constexpr const char* GetStaticTypeName() { \ | 40 | static constexpr const char* GetStaticTypeName() { \ |
| 41 | return TypeName; \ | 41 | return TypeName; \ |
| 42 | } \ | 42 | } \ |
| 43 | virtual TypeObj GetTypeObj() const { \ | 43 | virtual TypeObj GetTypeObj() ATTRIBUTE { \ |
| 44 | return GetStaticTypeObj(); \ | 44 | return GetStaticTypeObj(); \ |
| 45 | } \ | 45 | } \ |
| 46 | virtual const char* GetTypeName() const { \ | 46 | virtual const char* GetTypeName() ATTRIBUTE { \ |
| 47 | return GetStaticTypeName(); \ | 47 | return GetStaticTypeName(); \ |
| 48 | } \ | 48 | } \ |
| 49 | \ | 49 | \ |
| 50 | private: \ | 50 | private: \ |
| 51 | constexpr bool operator!=(const TypeObj& rhs) | 51 | constexpr bool operator!=(const TypeObj& rhs) |
| 52 | 52 | ||
| 53 | #define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \ | ||
| 54 | KERNEL_AUTOOBJECT_TRAITS_IMPL(CLASS, BASE_CLASS, const override) | ||
| 55 | |||
| 53 | class KAutoObject { | 56 | class KAutoObject { |
| 54 | protected: | 57 | protected: |
| 55 | class TypeObj { | 58 | class TypeObj { |
| @@ -82,7 +85,7 @@ protected: | |||
| 82 | }; | 85 | }; |
| 83 | 86 | ||
| 84 | private: | 87 | private: |
| 85 | KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject); | 88 | KERNEL_AUTOOBJECT_TRAITS_IMPL(KAutoObject, KAutoObject, const); |
| 86 | 89 | ||
| 87 | public: | 90 | public: |
| 88 | explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) { | 91 | explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) { |
diff --git a/src/core/hle/kernel/k_class_token.h b/src/core/hle/kernel/k_class_token.h index be9e3c357..c9001ae3d 100644 --- a/src/core/hle/kernel/k_class_token.h +++ b/src/core/hle/kernel/k_class_token.h | |||
| @@ -49,6 +49,7 @@ private: | |||
| 49 | } | 49 | } |
| 50 | } | 50 | } |
| 51 | } | 51 | } |
| 52 | UNREACHABLE(); | ||
| 52 | }(); | 53 | }(); |
| 53 | 54 | ||
| 54 | template <typename T> | 55 | template <typename T> |
diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp index fd3cbfd94..4ae40ec8e 100644 --- a/src/core/hle/kernel/k_code_memory.cpp +++ b/src/core/hle/kernel/k_code_memory.cpp | |||
| @@ -27,23 +27,18 @@ ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr | |||
| 27 | auto& page_table = m_owner->PageTable(); | 27 | auto& page_table = m_owner->PageTable(); |
| 28 | 28 | ||
| 29 | // Construct the page group. | 29 | // Construct the page group. |
| 30 | m_page_group = | 30 | m_page_group = {}; |
| 31 | KPageLinkedList(page_table.GetPhysicalAddr(addr), Common::DivideUp(size, PageSize)); | ||
| 32 | 31 | ||
| 33 | // Lock the memory. | 32 | // Lock the memory. |
| 34 | R_TRY(page_table.LockForCodeMemory(addr, size)) | 33 | R_TRY(page_table.LockForCodeMemory(&m_page_group, addr, size)) |
| 35 | 34 | ||
| 36 | // Clear the memory. | 35 | // Clear the memory. |
| 37 | // | 36 | for (const auto& block : m_page_group.Nodes()) { |
| 38 | // FIXME: this ends up clobbering address ranges outside the scope of the mapping within | 37 | std::memset(device_memory.GetPointer(block.GetAddress()), 0xFF, block.GetSize()); |
| 39 | // guest memory, and is not specifically required if the guest program is correctly | 38 | } |
| 40 | // written, so disable until this is further investigated. | ||
| 41 | // | ||
| 42 | // for (const auto& block : m_page_group.Nodes()) { | ||
| 43 | // std::memset(device_memory.GetPointer(block.GetAddress()), 0xFF, block.GetSize()); | ||
| 44 | // } | ||
| 45 | 39 | ||
| 46 | // Set remaining tracking members. | 40 | // Set remaining tracking members. |
| 41 | m_owner->Open(); | ||
| 47 | m_address = addr; | 42 | m_address = addr; |
| 48 | m_is_initialized = true; | 43 | m_is_initialized = true; |
| 49 | m_is_owner_mapped = false; | 44 | m_is_owner_mapped = false; |
| @@ -57,8 +52,14 @@ void KCodeMemory::Finalize() { | |||
| 57 | // Unlock. | 52 | // Unlock. |
| 58 | if (!m_is_mapped && !m_is_owner_mapped) { | 53 | if (!m_is_mapped && !m_is_owner_mapped) { |
| 59 | const size_t size = m_page_group.GetNumPages() * PageSize; | 54 | const size_t size = m_page_group.GetNumPages() * PageSize; |
| 60 | m_owner->PageTable().UnlockForCodeMemory(m_address, size); | 55 | m_owner->PageTable().UnlockForCodeMemory(m_address, size, m_page_group); |
| 61 | } | 56 | } |
| 57 | |||
| 58 | // Close the page group. | ||
| 59 | m_page_group = {}; | ||
| 60 | |||
| 61 | // Close our reference to our owner. | ||
| 62 | m_owner->Close(); | ||
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | ResultCode KCodeMemory::Map(VAddr address, size_t size) { | 65 | ResultCode KCodeMemory::Map(VAddr address, size_t size) { |
| @@ -118,7 +119,8 @@ ResultCode KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermis | |||
| 118 | k_perm = KMemoryPermission::UserReadExecute; | 119 | k_perm = KMemoryPermission::UserReadExecute; |
| 119 | break; | 120 | break; |
| 120 | default: | 121 | default: |
| 121 | break; | 122 | // Already validated by ControlCodeMemory svc |
| 123 | UNREACHABLE(); | ||
| 122 | } | 124 | } |
| 123 | 125 | ||
| 124 | // Map the memory. | 126 | // Map the memory. |
diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp index a55db3088..58e540f31 100644 --- a/src/core/hle/kernel/k_memory_manager.cpp +++ b/src/core/hle/kernel/k_memory_manager.cpp | |||
| @@ -29,7 +29,7 @@ constexpr KMemoryManager::Pool GetPoolFromMemoryRegionType(u32 type) { | |||
| 29 | } else if ((type | KMemoryRegionType_DramSystemNonSecurePool) == type) { | 29 | } else if ((type | KMemoryRegionType_DramSystemNonSecurePool) == type) { |
| 30 | return KMemoryManager::Pool::SystemNonSecure; | 30 | return KMemoryManager::Pool::SystemNonSecure; |
| 31 | } else { | 31 | } else { |
| 32 | UNREACHABLE_MSG("InvalidMemoryRegionType for conversion to Pool"); | 32 | ASSERT_MSG(false, "InvalidMemoryRegionType for conversion to Pool"); |
| 33 | return {}; | 33 | return {}; |
| 34 | } | 34 | } |
| 35 | } | 35 | } |
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index b38ef333b..504e22cb9 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp | |||
| @@ -35,7 +35,7 @@ constexpr std::size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceT | |||
| 35 | case FileSys::ProgramAddressSpaceType::Is39Bit: | 35 | case FileSys::ProgramAddressSpaceType::Is39Bit: |
| 36 | return 39; | 36 | return 39; |
| 37 | default: | 37 | default: |
| 38 | UNREACHABLE(); | 38 | ASSERT(false); |
| 39 | return {}; | 39 | return {}; |
| 40 | } | 40 | } |
| 41 | } | 41 | } |
| @@ -128,7 +128,7 @@ ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_ | |||
| 128 | const std::size_t needed_size{ | 128 | const std::size_t needed_size{ |
| 129 | (alias_region_size + heap_region_size + stack_region_size + kernel_map_region_size)}; | 129 | (alias_region_size + heap_region_size + stack_region_size + kernel_map_region_size)}; |
| 130 | if (alloc_size < needed_size) { | 130 | if (alloc_size < needed_size) { |
| 131 | UNREACHABLE(); | 131 | ASSERT(false); |
| 132 | return ResultOutOfMemory; | 132 | return ResultOutOfMemory; |
| 133 | } | 133 | } |
| 134 | 134 | ||
| @@ -542,6 +542,95 @@ ResultCode KPageTable::MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num | |||
| 542 | return ResultSuccess; | 542 | return ResultSuccess; |
| 543 | } | 543 | } |
| 544 | 544 | ||
| 545 | bool KPageTable::IsValidPageGroup(const KPageLinkedList& pg_ll, VAddr addr, size_t num_pages) { | ||
| 546 | ASSERT(this->IsLockedByCurrentThread()); | ||
| 547 | |||
| 548 | const size_t size = num_pages * PageSize; | ||
| 549 | const auto& pg = pg_ll.Nodes(); | ||
| 550 | const auto& memory_layout = system.Kernel().MemoryLayout(); | ||
| 551 | |||
| 552 | // Empty groups are necessarily invalid. | ||
| 553 | if (pg.empty()) { | ||
| 554 | return false; | ||
| 555 | } | ||
| 556 | |||
| 557 | // We're going to validate that the group we'd expect is the group we see. | ||
| 558 | auto cur_it = pg.begin(); | ||
| 559 | PAddr cur_block_address = cur_it->GetAddress(); | ||
| 560 | size_t cur_block_pages = cur_it->GetNumPages(); | ||
| 561 | |||
| 562 | auto UpdateCurrentIterator = [&]() { | ||
| 563 | if (cur_block_pages == 0) { | ||
| 564 | if ((++cur_it) == pg.end()) { | ||
| 565 | return false; | ||
| 566 | } | ||
| 567 | |||
| 568 | cur_block_address = cur_it->GetAddress(); | ||
| 569 | cur_block_pages = cur_it->GetNumPages(); | ||
| 570 | } | ||
| 571 | return true; | ||
| 572 | }; | ||
| 573 | |||
| 574 | // Begin traversal. | ||
| 575 | Common::PageTable::TraversalContext context; | ||
| 576 | Common::PageTable::TraversalEntry next_entry; | ||
| 577 | if (!page_table_impl.BeginTraversal(next_entry, context, addr)) { | ||
| 578 | return false; | ||
| 579 | } | ||
| 580 | |||
| 581 | // Prepare tracking variables. | ||
| 582 | PAddr cur_addr = next_entry.phys_addr; | ||
| 583 | size_t cur_size = next_entry.block_size - (cur_addr & (next_entry.block_size - 1)); | ||
| 584 | size_t tot_size = cur_size; | ||
| 585 | |||
| 586 | // Iterate, comparing expected to actual. | ||
| 587 | while (tot_size < size) { | ||
| 588 | if (!page_table_impl.ContinueTraversal(next_entry, context)) { | ||
| 589 | return false; | ||
| 590 | } | ||
| 591 | |||
| 592 | if (next_entry.phys_addr != (cur_addr + cur_size)) { | ||
| 593 | const size_t cur_pages = cur_size / PageSize; | ||
| 594 | |||
| 595 | if (!IsHeapPhysicalAddress(memory_layout, cur_addr)) { | ||
| 596 | return false; | ||
| 597 | } | ||
| 598 | |||
| 599 | if (!UpdateCurrentIterator()) { | ||
| 600 | return false; | ||
| 601 | } | ||
| 602 | |||
| 603 | if (cur_block_address != cur_addr || cur_block_pages < cur_pages) { | ||
| 604 | return false; | ||
| 605 | } | ||
| 606 | |||
| 607 | cur_block_address += cur_size; | ||
| 608 | cur_block_pages -= cur_pages; | ||
| 609 | cur_addr = next_entry.phys_addr; | ||
| 610 | cur_size = next_entry.block_size; | ||
| 611 | } else { | ||
| 612 | cur_size += next_entry.block_size; | ||
| 613 | } | ||
| 614 | |||
| 615 | tot_size += next_entry.block_size; | ||
| 616 | } | ||
| 617 | |||
| 618 | // Ensure we compare the right amount for the last block. | ||
| 619 | if (tot_size > size) { | ||
| 620 | cur_size -= (tot_size - size); | ||
| 621 | } | ||
| 622 | |||
| 623 | if (!IsHeapPhysicalAddress(memory_layout, cur_addr)) { | ||
| 624 | return false; | ||
| 625 | } | ||
| 626 | |||
| 627 | if (!UpdateCurrentIterator()) { | ||
| 628 | return false; | ||
| 629 | } | ||
| 630 | |||
| 631 | return cur_block_address == cur_addr && cur_block_pages == (cur_size / PageSize); | ||
| 632 | } | ||
| 633 | |||
| 545 | ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size, | 634 | ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size, |
| 546 | KPageTable& src_page_table, VAddr src_addr) { | 635 | KPageTable& src_page_table, VAddr src_addr) { |
| 547 | KScopedLightLock lk(general_lock); | 636 | KScopedLightLock lk(general_lock); |
| @@ -1341,7 +1430,7 @@ ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size, | |||
| 1341 | new_state = KMemoryState::AliasCodeData; | 1430 | new_state = KMemoryState::AliasCodeData; |
| 1342 | break; | 1431 | break; |
| 1343 | default: | 1432 | default: |
| 1344 | UNREACHABLE(); | 1433 | ASSERT(false); |
| 1345 | } | 1434 | } |
| 1346 | } | 1435 | } |
| 1347 | 1436 | ||
| @@ -1687,22 +1776,22 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) | |||
| 1687 | return ResultSuccess; | 1776 | return ResultSuccess; |
| 1688 | } | 1777 | } |
| 1689 | 1778 | ||
| 1690 | ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) { | 1779 | ResultCode KPageTable::LockForCodeMemory(KPageLinkedList* out, VAddr addr, std::size_t size) { |
| 1691 | return this->LockMemoryAndOpen( | 1780 | return this->LockMemoryAndOpen( |
| 1692 | nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, | 1781 | out, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory, |
| 1693 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::All, KMemoryPermission::UserReadWrite, | 1782 | KMemoryPermission::All, KMemoryPermission::UserReadWrite, KMemoryAttribute::All, |
| 1694 | KMemoryAttribute::All, KMemoryAttribute::None, | 1783 | KMemoryAttribute::None, |
| 1695 | static_cast<KMemoryPermission>(KMemoryPermission::NotMapped | | 1784 | static_cast<KMemoryPermission>(KMemoryPermission::NotMapped | |
| 1696 | KMemoryPermission::KernelReadWrite), | 1785 | KMemoryPermission::KernelReadWrite), |
| 1697 | KMemoryAttribute::Locked); | 1786 | KMemoryAttribute::Locked); |
| 1698 | } | 1787 | } |
| 1699 | 1788 | ||
| 1700 | ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) { | 1789 | ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size, |
| 1701 | return this->UnlockMemory(addr, size, KMemoryState::FlagCanCodeMemory, | 1790 | const KPageLinkedList& pg) { |
| 1702 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, | 1791 | return this->UnlockMemory( |
| 1703 | KMemoryPermission::None, KMemoryAttribute::All, | 1792 | addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory, |
| 1704 | KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite, | 1793 | KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::All, |
| 1705 | KMemoryAttribute::Locked, nullptr); | 1794 | KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite, KMemoryAttribute::Locked, &pg); |
| 1706 | } | 1795 | } |
| 1707 | 1796 | ||
| 1708 | ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { | 1797 | ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { |
| @@ -1734,9 +1823,7 @@ void KPageTable::AddRegionToPages(VAddr start, std::size_t num_pages, | |||
| 1734 | VAddr addr{start}; | 1823 | VAddr addr{start}; |
| 1735 | while (addr < start + (num_pages * PageSize)) { | 1824 | while (addr < start + (num_pages * PageSize)) { |
| 1736 | const PAddr paddr{GetPhysicalAddr(addr)}; | 1825 | const PAddr paddr{GetPhysicalAddr(addr)}; |
| 1737 | if (!paddr) { | 1826 | ASSERT(paddr != 0); |
| 1738 | UNREACHABLE(); | ||
| 1739 | } | ||
| 1740 | page_linked_list.AddBlock(paddr, 1); | 1827 | page_linked_list.AddBlock(paddr, 1); |
| 1741 | addr += PageSize; | 1828 | addr += PageSize; |
| 1742 | } | 1829 | } |
| @@ -1767,7 +1854,7 @@ ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, const KPageLin | |||
| 1767 | system.Memory().MapMemoryRegion(page_table_impl, addr, size, node.GetAddress()); | 1854 | system.Memory().MapMemoryRegion(page_table_impl, addr, size, node.GetAddress()); |
| 1768 | break; | 1855 | break; |
| 1769 | default: | 1856 | default: |
| 1770 | UNREACHABLE(); | 1857 | ASSERT(false); |
| 1771 | } | 1858 | } |
| 1772 | 1859 | ||
| 1773 | addr += size; | 1860 | addr += size; |
| @@ -1798,7 +1885,7 @@ ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, KMemoryPermiss | |||
| 1798 | case OperationType::ChangePermissionsAndRefresh: | 1885 | case OperationType::ChangePermissionsAndRefresh: |
| 1799 | break; | 1886 | break; |
| 1800 | default: | 1887 | default: |
| 1801 | UNREACHABLE(); | 1888 | ASSERT(false); |
| 1802 | } | 1889 | } |
| 1803 | return ResultSuccess; | 1890 | return ResultSuccess; |
| 1804 | } | 1891 | } |
| @@ -1835,7 +1922,6 @@ VAddr KPageTable::GetRegionAddress(KMemoryState state) const { | |||
| 1835 | return code_region_start; | 1922 | return code_region_start; |
| 1836 | default: | 1923 | default: |
| 1837 | UNREACHABLE(); | 1924 | UNREACHABLE(); |
| 1838 | return {}; | ||
| 1839 | } | 1925 | } |
| 1840 | } | 1926 | } |
| 1841 | 1927 | ||
| @@ -1871,7 +1957,6 @@ std::size_t KPageTable::GetRegionSize(KMemoryState state) const { | |||
| 1871 | return code_region_end - code_region_start; | 1957 | return code_region_end - code_region_start; |
| 1872 | default: | 1958 | default: |
| 1873 | UNREACHABLE(); | 1959 | UNREACHABLE(); |
| 1874 | return {}; | ||
| 1875 | } | 1960 | } |
| 1876 | } | 1961 | } |
| 1877 | 1962 | ||
| @@ -2125,7 +2210,7 @@ ResultCode KPageTable::UnlockMemory(VAddr addr, size_t size, KMemoryState state_ | |||
| 2125 | 2210 | ||
| 2126 | // Check the page group. | 2211 | // Check the page group. |
| 2127 | if (pg != nullptr) { | 2212 | if (pg != nullptr) { |
| 2128 | UNIMPLEMENTED_MSG("PageGroup support is unimplemented!"); | 2213 | R_UNLESS(this->IsValidPageGroup(*pg, addr, num_pages), ResultInvalidMemoryRegion); |
| 2129 | } | 2214 | } |
| 2130 | 2215 | ||
| 2131 | // Decide on new perm and attr. | 2216 | // Decide on new perm and attr. |
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 52a93ce86..6312eb682 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h | |||
| @@ -72,8 +72,8 @@ public: | |||
| 72 | KMemoryPermission perm, PAddr map_addr = 0); | 72 | KMemoryPermission perm, PAddr map_addr = 0); |
| 73 | ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); | 73 | ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); |
| 74 | ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); | 74 | ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); |
| 75 | ResultCode LockForCodeMemory(VAddr addr, std::size_t size); | 75 | ResultCode LockForCodeMemory(KPageLinkedList* out, VAddr addr, std::size_t size); |
| 76 | ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size); | 76 | ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size, const KPageLinkedList& pg); |
| 77 | ResultCode MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address, size_t num_pages, | 77 | ResultCode MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address, size_t num_pages, |
| 78 | KMemoryState state_mask, KMemoryState state, | 78 | KMemoryState state_mask, KMemoryState state, |
| 79 | KMemoryPermission perm_mask, KMemoryPermission perm, | 79 | KMemoryPermission perm_mask, KMemoryPermission perm, |
| @@ -178,6 +178,7 @@ private: | |||
| 178 | const KPageLinkedList* pg); | 178 | const KPageLinkedList* pg); |
| 179 | 179 | ||
| 180 | ResultCode MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num_pages); | 180 | ResultCode MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num_pages); |
| 181 | bool IsValidPageGroup(const KPageLinkedList& pg, VAddr addr, size_t num_pages); | ||
| 181 | 182 | ||
| 182 | bool IsLockedByCurrentThread() const { | 183 | bool IsLockedByCurrentThread() const { |
| 183 | return general_lock.IsLockedByCurrentThread(); | 184 | return general_lock.IsLockedByCurrentThread(); |
diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp index a31861cdb..51c2cd1ef 100644 --- a/src/core/hle/kernel/k_port.cpp +++ b/src/core/hle/kernel/k_port.cpp | |||
| @@ -60,7 +60,7 @@ ResultCode KPort::EnqueueSession(KServerSession* session) { | |||
| 60 | if (auto session_ptr = server.GetSessionRequestHandler().lock()) { | 60 | if (auto session_ptr = server.GetSessionRequestHandler().lock()) { |
| 61 | session_ptr->ClientConnected(server.AcceptSession()); | 61 | session_ptr->ClientConnected(server.AcceptSession()); |
| 62 | } else { | 62 | } else { |
| 63 | UNREACHABLE(); | 63 | ASSERT(false); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | return ResultSuccess; | 66 | return ResultSuccess; |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 490e31fc7..8c79b4f0f 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -64,6 +64,10 @@ void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority | |||
| 64 | { | 64 | { |
| 65 | KScopedSchedulerLock lock{kernel}; | 65 | KScopedSchedulerLock lock{kernel}; |
| 66 | thread->SetState(ThreadState::Runnable); | 66 | thread->SetState(ThreadState::Runnable); |
| 67 | |||
| 68 | if (system.DebuggerEnabled()) { | ||
| 69 | thread->RequestSuspend(SuspendType::Debug); | ||
| 70 | } | ||
| 67 | } | 71 | } |
| 68 | } | 72 | } |
| 69 | } // Anonymous namespace | 73 | } // Anonymous namespace |
| @@ -346,7 +350,7 @@ ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, | |||
| 346 | break; | 350 | break; |
| 347 | 351 | ||
| 348 | default: | 352 | default: |
| 349 | UNREACHABLE(); | 353 | ASSERT(false); |
| 350 | } | 354 | } |
| 351 | 355 | ||
| 352 | // Create TLS region | 356 | // Create TLS region |
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 7e39f6d50..60f8ed470 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp | |||
| @@ -97,13 +97,13 @@ ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& co | |||
| 97 | "object_id {} is too big! This probably means a recent service call " | 97 | "object_id {} is too big! This probably means a recent service call " |
| 98 | "to {} needed to return a new interface!", | 98 | "to {} needed to return a new interface!", |
| 99 | object_id, name); | 99 | object_id, name); |
| 100 | UNREACHABLE(); | 100 | ASSERT(false); |
| 101 | return ResultSuccess; // Ignore error if asserts are off | 101 | return ResultSuccess; // Ignore error if asserts are off |
| 102 | } | 102 | } |
| 103 | if (auto strong_ptr = manager->DomainHandler(object_id - 1).lock()) { | 103 | if (auto strong_ptr = manager->DomainHandler(object_id - 1).lock()) { |
| 104 | return strong_ptr->HandleSyncRequest(*this, context); | 104 | return strong_ptr->HandleSyncRequest(*this, context); |
| 105 | } else { | 105 | } else { |
| 106 | UNREACHABLE(); | 106 | ASSERT(false); |
| 107 | return ResultSuccess; | 107 | return ResultSuccess; |
| 108 | } | 108 | } |
| 109 | 109 | ||
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index ab9ce6a86..ea2160099 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -133,7 +133,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s | |||
| 133 | UNIMPLEMENTED(); | 133 | UNIMPLEMENTED(); |
| 134 | break; | 134 | break; |
| 135 | default: | 135 | default: |
| 136 | UNREACHABLE_MSG("KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type)); | 136 | ASSERT_MSG(false, "KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type)); |
| 137 | break; | 137 | break; |
| 138 | } | 138 | } |
| 139 | thread_type = type; | 139 | thread_type = type; |
| @@ -198,6 +198,10 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s | |||
| 198 | resource_limit_release_hint = false; | 198 | resource_limit_release_hint = false; |
| 199 | cpu_time = 0; | 199 | cpu_time = 0; |
| 200 | 200 | ||
| 201 | // Set debug context. | ||
| 202 | stack_top = user_stack_top; | ||
| 203 | argument = arg; | ||
| 204 | |||
| 201 | // Clear our stack parameters. | 205 | // Clear our stack parameters. |
| 202 | std::memset(static_cast<void*>(std::addressof(GetStackParameters())), 0, | 206 | std::memset(static_cast<void*>(std::addressof(GetStackParameters())), 0, |
| 203 | sizeof(StackParameters)); | 207 | sizeof(StackParameters)); |
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index b55a922ab..f4d83f99a 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -100,6 +100,12 @@ enum class ThreadWaitReasonForDebugging : u32 { | |||
| 100 | Suspended, ///< Thread is waiting due to process suspension | 100 | Suspended, ///< Thread is waiting due to process suspension |
| 101 | }; | 101 | }; |
| 102 | 102 | ||
| 103 | enum class StepState : u32 { | ||
| 104 | NotStepping, ///< Thread is not currently stepping | ||
| 105 | StepPending, ///< Thread will step when next scheduled | ||
| 106 | StepPerformed, ///< Thread has stepped, waiting to be scheduled again | ||
| 107 | }; | ||
| 108 | |||
| 103 | [[nodiscard]] KThread* GetCurrentThreadPointer(KernelCore& kernel); | 109 | [[nodiscard]] KThread* GetCurrentThreadPointer(KernelCore& kernel); |
| 104 | [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); | 110 | [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); |
| 105 | [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); | 111 | [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); |
| @@ -267,6 +273,14 @@ public: | |||
| 267 | 273 | ||
| 268 | void SetState(ThreadState state); | 274 | void SetState(ThreadState state); |
| 269 | 275 | ||
| 276 | [[nodiscard]] StepState GetStepState() const { | ||
| 277 | return step_state; | ||
| 278 | } | ||
| 279 | |||
| 280 | void SetStepState(StepState state) { | ||
| 281 | step_state = state; | ||
| 282 | } | ||
| 283 | |||
| 270 | [[nodiscard]] s64 GetLastScheduledTick() const { | 284 | [[nodiscard]] s64 GetLastScheduledTick() const { |
| 271 | return last_scheduled_tick; | 285 | return last_scheduled_tick; |
| 272 | } | 286 | } |
| @@ -646,6 +660,14 @@ public: | |||
| 646 | void IfDummyThreadTryWait(); | 660 | void IfDummyThreadTryWait(); |
| 647 | void IfDummyThreadEndWait(); | 661 | void IfDummyThreadEndWait(); |
| 648 | 662 | ||
| 663 | [[nodiscard]] uintptr_t GetArgument() const { | ||
| 664 | return argument; | ||
| 665 | } | ||
| 666 | |||
| 667 | [[nodiscard]] VAddr GetUserStackTop() const { | ||
| 668 | return stack_top; | ||
| 669 | } | ||
| 670 | |||
| 649 | private: | 671 | private: |
| 650 | static constexpr size_t PriorityInheritanceCountMax = 10; | 672 | static constexpr size_t PriorityInheritanceCountMax = 10; |
| 651 | union SyncObjectBuffer { | 673 | union SyncObjectBuffer { |
| @@ -769,6 +791,7 @@ private: | |||
| 769 | std::shared_ptr<Common::Fiber> host_context{}; | 791 | std::shared_ptr<Common::Fiber> host_context{}; |
| 770 | bool is_single_core{}; | 792 | bool is_single_core{}; |
| 771 | ThreadType thread_type{}; | 793 | ThreadType thread_type{}; |
| 794 | StepState step_state{}; | ||
| 772 | std::mutex dummy_wait_lock; | 795 | std::mutex dummy_wait_lock; |
| 773 | std::condition_variable dummy_wait_cv; | 796 | std::condition_variable dummy_wait_cv; |
| 774 | 797 | ||
| @@ -776,6 +799,8 @@ private: | |||
| 776 | std::vector<KSynchronizationObject*> wait_objects_for_debugging; | 799 | std::vector<KSynchronizationObject*> wait_objects_for_debugging; |
| 777 | VAddr mutex_wait_address_for_debugging{}; | 800 | VAddr mutex_wait_address_for_debugging{}; |
| 778 | ThreadWaitReasonForDebugging wait_reason_for_debugging{}; | 801 | ThreadWaitReasonForDebugging wait_reason_for_debugging{}; |
| 802 | uintptr_t argument; | ||
| 803 | VAddr stack_top; | ||
| 779 | 804 | ||
| 780 | public: | 805 | public: |
| 781 | using ConditionVariableThreadTreeType = ConditionVariableThreadTree; | 806 | using ConditionVariableThreadTreeType = ConditionVariableThreadTree; |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 92f6d8c49..b2c4f12b4 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -212,7 +212,9 @@ struct KernelCore::Impl { | |||
| 212 | system_resource_limit = KResourceLimit::Create(system.Kernel()); | 212 | system_resource_limit = KResourceLimit::Create(system.Kernel()); |
| 213 | system_resource_limit->Initialize(&core_timing); | 213 | system_resource_limit->Initialize(&core_timing); |
| 214 | 214 | ||
| 215 | const auto [total_size, kernel_size] = memory_layout->GetTotalAndKernelMemorySizes(); | 215 | const auto sizes{memory_layout->GetTotalAndKernelMemorySizes()}; |
| 216 | const auto total_size{sizes.first}; | ||
| 217 | const auto kernel_size{sizes.second}; | ||
| 216 | 218 | ||
| 217 | // If setting the default system values fails, then something seriously wrong has occurred. | 219 | // If setting the default system values fails, then something seriously wrong has occurred. |
| 218 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, total_size) | 220 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, total_size) |
| @@ -252,6 +254,7 @@ struct KernelCore::Impl { | |||
| 252 | core_id) | 254 | core_id) |
| 253 | .IsSuccess()); | 255 | .IsSuccess()); |
| 254 | suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id)); | 256 | suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id)); |
| 257 | suspend_threads[core_id]->DisableDispatch(); | ||
| 255 | } | 258 | } |
| 256 | } | 259 | } |
| 257 | 260 | ||
| @@ -1073,9 +1076,6 @@ void KernelCore::Suspend(bool in_suspention) { | |||
| 1073 | impl->suspend_threads[core_id]->SetState(state); | 1076 | impl->suspend_threads[core_id]->SetState(state); |
| 1074 | impl->suspend_threads[core_id]->SetWaitReasonForDebugging( | 1077 | impl->suspend_threads[core_id]->SetWaitReasonForDebugging( |
| 1075 | ThreadWaitReasonForDebugging::Suspended); | 1078 | ThreadWaitReasonForDebugging::Suspended); |
| 1076 | if (!should_suspend) { | ||
| 1077 | impl->suspend_threads[core_id]->DisableDispatch(); | ||
| 1078 | } | ||
| 1079 | } | 1079 | } |
| 1080 | } | 1080 | } |
| 1081 | } | 1081 | } |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 66e0ce2d0..4f0a44363 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "common/scope_exit.h" | 15 | #include "common/scope_exit.h" |
| 16 | #include "core/core.h" | 16 | #include "core/core.h" |
| 17 | #include "core/core_timing.h" | 17 | #include "core/core_timing.h" |
| 18 | #include "core/debugger/debugger.h" | ||
| 18 | #include "core/hle/kernel/k_client_port.h" | 19 | #include "core/hle/kernel/k_client_port.h" |
| 19 | #include "core/hle/kernel/k_client_session.h" | 20 | #include "core/hle/kernel/k_client_session.h" |
| 20 | #include "core/hle/kernel/k_code_memory.h" | 21 | #include "core/hle/kernel/k_code_memory.h" |
| @@ -627,6 +628,12 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { | |||
| 627 | const auto thread_processor_id = current_thread->GetActiveCore(); | 628 | const auto thread_processor_id = current_thread->GetActiveCore(); |
| 628 | system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); | 629 | system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); |
| 629 | } | 630 | } |
| 631 | |||
| 632 | if (system.DebuggerEnabled()) { | ||
| 633 | auto* thread = system.Kernel().GetCurrentEmuThread(); | ||
| 634 | system.GetDebugger().NotifyThreadStopped(thread); | ||
| 635 | thread->RequestSuspend(Kernel::SuspendType::Debug); | ||
| 636 | } | ||
| 630 | } | 637 | } |
| 631 | 638 | ||
| 632 | static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) { | 639 | static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) { |
| @@ -1876,7 +1883,7 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { | |||
| 1876 | KScheduler::YieldToAnyThread(kernel); | 1883 | KScheduler::YieldToAnyThread(kernel); |
| 1877 | } else { | 1884 | } else { |
| 1878 | // Nintendo does nothing at all if an otherwise invalid value is passed. | 1885 | // Nintendo does nothing at all if an otherwise invalid value is passed. |
| 1879 | UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); | 1886 | ASSERT_MSG(false, "Unimplemented sleep yield type '{:016X}'!", nanoseconds); |
| 1880 | } | 1887 | } |
| 1881 | } | 1888 | } |
| 1882 | 1889 | ||
| @@ -2982,7 +2989,6 @@ static const FunctionDef* GetSVCInfo64(u32 func_num) { | |||
| 2982 | } | 2989 | } |
| 2983 | 2990 | ||
| 2984 | void Call(Core::System& system, u32 immediate) { | 2991 | void Call(Core::System& system, u32 immediate) { |
| 2985 | system.ExitDynarmicProfile(); | ||
| 2986 | auto& kernel = system.Kernel(); | 2992 | auto& kernel = system.Kernel(); |
| 2987 | kernel.EnterSVCProfile(); | 2993 | kernel.EnterSVCProfile(); |
| 2988 | 2994 | ||
| @@ -3007,8 +3013,6 @@ void Call(Core::System& system, u32 immediate) { | |||
| 3007 | auto* host_context = thread->GetHostContext().get(); | 3013 | auto* host_context = thread->GetHostContext().get(); |
| 3008 | host_context->Rewind(); | 3014 | host_context->Rewind(); |
| 3009 | } | 3015 | } |
| 3010 | |||
| 3011 | system.EnterDynarmicProfile(); | ||
| 3012 | } | 3016 | } |
| 3013 | 3017 | ||
| 3014 | } // namespace Kernel::Svc | 3018 | } // namespace Kernel::Svc |
diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp index 655f2e936..0a5603d18 100644 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/applets/applet_controller.cpp | |||
| @@ -178,7 +178,7 @@ ResultCode Controller::GetStatus() const { | |||
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | void Controller::ExecuteInteractive() { | 180 | void Controller::ExecuteInteractive() { |
| 181 | UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet."); | 181 | ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | void Controller::Execute() { | 184 | void Controller::Execute() { |
diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp index 911b2c229..0b87c60b9 100644 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ b/src/core/hle/service/am/applets/applet_error.cpp | |||
| @@ -156,7 +156,7 @@ ResultCode Error::GetStatus() const { | |||
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | void Error::ExecuteInteractive() { | 158 | void Error::ExecuteInteractive() { |
| 159 | UNREACHABLE_MSG("Unexpected interactive applet data!"); | 159 | ASSERT_MSG(false, "Unexpected interactive applet data!"); |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | void Error::Execute() { | 162 | void Error::Execute() { |
diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp index 3fe1a390a..41c002ef2 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.cpp +++ b/src/core/hle/service/am/applets/applet_general_backend.cpp | |||
| @@ -76,7 +76,7 @@ ResultCode Auth::GetStatus() const { | |||
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | void Auth::ExecuteInteractive() { | 78 | void Auth::ExecuteInteractive() { |
| 79 | UNREACHABLE_MSG("Unexpected interactive applet data."); | 79 | ASSERT_MSG(false, "Unexpected interactive applet data."); |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | void Auth::Execute() { | 82 | void Auth::Execute() { |
| @@ -175,7 +175,7 @@ ResultCode PhotoViewer::GetStatus() const { | |||
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | void PhotoViewer::ExecuteInteractive() { | 177 | void PhotoViewer::ExecuteInteractive() { |
| 178 | UNREACHABLE_MSG("Unexpected interactive applet data."); | 178 | ASSERT_MSG(false, "Unexpected interactive applet data."); |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | void PhotoViewer::Execute() { | 181 | void PhotoViewer::Execute() { |
diff --git a/src/core/hle/service/am/applets/applet_mii_edit.cpp b/src/core/hle/service/am/applets/applet_mii_edit.cpp index 3acde1630..8d847c3f6 100644 --- a/src/core/hle/service/am/applets/applet_mii_edit.cpp +++ b/src/core/hle/service/am/applets/applet_mii_edit.cpp | |||
| @@ -67,7 +67,7 @@ ResultCode MiiEdit::GetStatus() const { | |||
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | void MiiEdit::ExecuteInteractive() { | 69 | void MiiEdit::ExecuteInteractive() { |
| 70 | UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet."); | 70 | ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | void MiiEdit::Execute() { | 73 | void MiiEdit::Execute() { |
diff --git a/src/core/hle/service/am/applets/applet_profile_select.cpp b/src/core/hle/service/am/applets/applet_profile_select.cpp index fd16f2e49..02049fd9f 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.cpp +++ b/src/core/hle/service/am/applets/applet_profile_select.cpp | |||
| @@ -44,7 +44,7 @@ ResultCode ProfileSelect::GetStatus() const { | |||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | void ProfileSelect::ExecuteInteractive() { | 46 | void ProfileSelect::ExecuteInteractive() { |
| 47 | UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet."); | 47 | ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | void ProfileSelect::Execute() { | 50 | void ProfileSelect::Execute() { |
diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.cpp b/src/core/hle/service/am/applets/applet_software_keyboard.cpp index 7c21365e4..4116fbaa7 100644 --- a/src/core/hle/service/am/applets/applet_software_keyboard.cpp +++ b/src/core/hle/service/am/applets/applet_software_keyboard.cpp | |||
| @@ -71,7 +71,7 @@ void SoftwareKeyboard::Initialize() { | |||
| 71 | InitializeBackground(applet_mode); | 71 | InitializeBackground(applet_mode); |
| 72 | break; | 72 | break; |
| 73 | default: | 73 | default: |
| 74 | UNREACHABLE_MSG("Invalid LibraryAppletMode={}", applet_mode); | 74 | ASSERT_MSG(false, "Invalid LibraryAppletMode={}", applet_mode); |
| 75 | break; | 75 | break; |
| 76 | } | 76 | } |
| 77 | } | 77 | } |
diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp index 2aa4a00ad..7b3f77a51 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ b/src/core/hle/service/am/applets/applet_web_browser.cpp | |||
| @@ -279,7 +279,7 @@ void WebBrowser::Initialize() { | |||
| 279 | InitializeLobby(); | 279 | InitializeLobby(); |
| 280 | break; | 280 | break; |
| 281 | default: | 281 | default: |
| 282 | UNREACHABLE_MSG("Invalid ShimKind={}", web_arg_header.shim_kind); | 282 | ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind); |
| 283 | break; | 283 | break; |
| 284 | } | 284 | } |
| 285 | } | 285 | } |
| @@ -320,7 +320,7 @@ void WebBrowser::Execute() { | |||
| 320 | ExecuteLobby(); | 320 | ExecuteLobby(); |
| 321 | break; | 321 | break; |
| 322 | default: | 322 | default: |
| 323 | UNREACHABLE_MSG("Invalid ShimKind={}", web_arg_header.shim_kind); | 323 | ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind); |
| 324 | WebBrowserExit(WebExitReason::EndButtonPressed); | 324 | WebBrowserExit(WebExitReason::EndButtonPressed); |
| 325 | break; | 325 | break; |
| 326 | } | 326 | } |
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index ddfcba0f1..fae6e5aff 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -899,7 +899,7 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) { | |||
| 899 | case FileSys::SaveDataSpaceId::TemporaryStorage: | 899 | case FileSys::SaveDataSpaceId::TemporaryStorage: |
| 900 | case FileSys::SaveDataSpaceId::ProperSystem: | 900 | case FileSys::SaveDataSpaceId::ProperSystem: |
| 901 | case FileSys::SaveDataSpaceId::SafeMode: | 901 | case FileSys::SaveDataSpaceId::SafeMode: |
| 902 | UNREACHABLE(); | 902 | ASSERT(false); |
| 903 | } | 903 | } |
| 904 | 904 | ||
| 905 | auto filesystem = std::make_shared<IFileSystem>(system, std::move(dir.Unwrap()), | 905 | auto filesystem = std::make_shared<IFileSystem>(system, std::move(dir.Unwrap()), |
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 3eae1ae35..32e0708ba 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp | |||
| @@ -61,6 +61,7 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | |||
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | last_update_timestamp = shared_memory->gesture_lifo.timestamp; | 63 | last_update_timestamp = shared_memory->gesture_lifo.timestamp; |
| 64 | UpdateGestureSharedMemory(gesture, time_difference); | ||
| 64 | } | 65 | } |
| 65 | 66 | ||
| 66 | void Controller_Gesture::ReadTouchInput() { | 67 | void Controller_Gesture::ReadTouchInput() { |
| @@ -94,8 +95,7 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, | |||
| 94 | return false; | 95 | return false; |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, | 98 | void Controller_Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, |
| 98 | GestureProperties& gesture, | ||
| 99 | f32 time_difference) { | 99 | f32 time_difference) { |
| 100 | GestureType type = GestureType::Idle; | 100 | GestureType type = GestureType::Idle; |
| 101 | GestureAttribute attributes{}; | 101 | GestureAttribute attributes{}; |
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index c62a341bf..0d6099ea0 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h | |||
| @@ -107,8 +107,7 @@ private: | |||
| 107 | bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference); | 107 | bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference); |
| 108 | 108 | ||
| 109 | // Updates the shared memory to the next state | 109 | // Updates the shared memory to the next state |
| 110 | void UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture, | 110 | void UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference); |
| 111 | f32 time_difference); | ||
| 112 | 111 | ||
| 113 | // Initializes new gesture | 112 | // Initializes new gesture |
| 114 | void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes); | 113 | void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes); |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 17f71beaf..ac5c38cc6 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -3,7 +3,9 @@ | |||
| 3 | 3 | ||
| 4 | #include <algorithm> | 4 | #include <algorithm> |
| 5 | #include <array> | 5 | #include <array> |
| 6 | #include <chrono> | ||
| 6 | #include <cstring> | 7 | #include <cstring> |
| 8 | |||
| 7 | #include "common/assert.h" | 9 | #include "common/assert.h" |
| 8 | #include "common/bit_field.h" | 10 | #include "common/bit_field.h" |
| 9 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| @@ -54,11 +56,22 @@ bool Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle | |||
| 54 | return npad_id && npad_type && device_index; | 56 | return npad_id && npad_type && device_index; |
| 55 | } | 57 | } |
| 56 | 58 | ||
| 57 | bool Controller_NPad::IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle) { | 59 | ResultCode Controller_NPad::VerifyValidSixAxisSensorHandle( |
| 60 | const Core::HID::SixAxisSensorHandle& device_handle) { | ||
| 58 | const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id)); | 61 | const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id)); |
| 59 | const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType; | 62 | if (!npad_id) { |
| 63 | return InvalidNpadId; | ||
| 64 | } | ||
| 60 | const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; | 65 | const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; |
| 61 | return npad_id && npad_type && device_index; | 66 | if (!device_index) { |
| 67 | return NpadDeviceIndexOutOfRange; | ||
| 68 | } | ||
| 69 | // This doesn't get validated on nnsdk | ||
| 70 | const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType; | ||
| 71 | if (!npad_type) { | ||
| 72 | return NpadInvalidHandle; | ||
| 73 | } | ||
| 74 | return ResultSuccess; | ||
| 62 | } | 75 | } |
| 63 | 76 | ||
| 64 | Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, | 77 | Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, |
| @@ -147,7 +160,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | |||
| 147 | shared_memory->system_properties.raw = 0; | 160 | shared_memory->system_properties.raw = 0; |
| 148 | switch (controller_type) { | 161 | switch (controller_type) { |
| 149 | case Core::HID::NpadStyleIndex::None: | 162 | case Core::HID::NpadStyleIndex::None: |
| 150 | UNREACHABLE(); | 163 | ASSERT(false); |
| 151 | break; | 164 | break; |
| 152 | case Core::HID::NpadStyleIndex::ProController: | 165 | case Core::HID::NpadStyleIndex::ProController: |
| 153 | shared_memory->style_tag.fullkey.Assign(1); | 166 | shared_memory->style_tag.fullkey.Assign(1); |
| @@ -156,6 +169,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | |||
| 156 | shared_memory->system_properties.use_plus.Assign(1); | 169 | shared_memory->system_properties.use_plus.Assign(1); |
| 157 | shared_memory->system_properties.use_minus.Assign(1); | 170 | shared_memory->system_properties.use_minus.Assign(1); |
| 158 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController; | 171 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController; |
| 172 | shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1); | ||
| 159 | break; | 173 | break; |
| 160 | case Core::HID::NpadStyleIndex::Handheld: | 174 | case Core::HID::NpadStyleIndex::Handheld: |
| 161 | shared_memory->style_tag.handheld.Assign(1); | 175 | shared_memory->style_tag.handheld.Assign(1); |
| @@ -168,16 +182,19 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | |||
| 168 | shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; | 182 | shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; |
| 169 | shared_memory->applet_nfc_xcd.applet_footer.type = | 183 | shared_memory->applet_nfc_xcd.applet_footer.type = |
| 170 | AppletFooterUiType::HandheldJoyConLeftJoyConRight; | 184 | AppletFooterUiType::HandheldJoyConLeftJoyConRight; |
| 185 | shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1); | ||
| 171 | break; | 186 | break; |
| 172 | case Core::HID::NpadStyleIndex::JoyconDual: | 187 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 173 | shared_memory->style_tag.joycon_dual.Assign(1); | 188 | shared_memory->style_tag.joycon_dual.Assign(1); |
| 174 | if (controller.is_dual_left_connected) { | 189 | if (controller.is_dual_left_connected) { |
| 175 | shared_memory->device_type.joycon_left.Assign(1); | 190 | shared_memory->device_type.joycon_left.Assign(1); |
| 176 | shared_memory->system_properties.use_minus.Assign(1); | 191 | shared_memory->system_properties.use_minus.Assign(1); |
| 192 | shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1); | ||
| 177 | } | 193 | } |
| 178 | if (controller.is_dual_right_connected) { | 194 | if (controller.is_dual_right_connected) { |
| 179 | shared_memory->device_type.joycon_right.Assign(1); | 195 | shared_memory->device_type.joycon_right.Assign(1); |
| 180 | shared_memory->system_properties.use_plus.Assign(1); | 196 | shared_memory->system_properties.use_plus.Assign(1); |
| 197 | shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1); | ||
| 181 | } | 198 | } |
| 182 | shared_memory->system_properties.use_directional_buttons.Assign(1); | 199 | shared_memory->system_properties.use_directional_buttons.Assign(1); |
| 183 | shared_memory->system_properties.is_vertical.Assign(1); | 200 | shared_memory->system_properties.is_vertical.Assign(1); |
| @@ -196,6 +213,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | |||
| 196 | shared_memory->system_properties.is_horizontal.Assign(1); | 213 | shared_memory->system_properties.is_horizontal.Assign(1); |
| 197 | shared_memory->system_properties.use_minus.Assign(1); | 214 | shared_memory->system_properties.use_minus.Assign(1); |
| 198 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; | 215 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; |
| 216 | shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1); | ||
| 199 | break; | 217 | break; |
| 200 | case Core::HID::NpadStyleIndex::JoyconRight: | 218 | case Core::HID::NpadStyleIndex::JoyconRight: |
| 201 | shared_memory->style_tag.joycon_right.Assign(1); | 219 | shared_memory->style_tag.joycon_right.Assign(1); |
| @@ -203,6 +221,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | |||
| 203 | shared_memory->system_properties.is_horizontal.Assign(1); | 221 | shared_memory->system_properties.is_horizontal.Assign(1); |
| 204 | shared_memory->system_properties.use_plus.Assign(1); | 222 | shared_memory->system_properties.use_plus.Assign(1); |
| 205 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; | 223 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; |
| 224 | shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1); | ||
| 206 | break; | 225 | break; |
| 207 | case Core::HID::NpadStyleIndex::GameCube: | 226 | case Core::HID::NpadStyleIndex::GameCube: |
| 208 | shared_memory->style_tag.gamecube.Assign(1); | 227 | shared_memory->style_tag.gamecube.Assign(1); |
| @@ -213,6 +232,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | |||
| 213 | case Core::HID::NpadStyleIndex::Pokeball: | 232 | case Core::HID::NpadStyleIndex::Pokeball: |
| 214 | shared_memory->style_tag.palma.Assign(1); | 233 | shared_memory->style_tag.palma.Assign(1); |
| 215 | shared_memory->device_type.palma.Assign(1); | 234 | shared_memory->device_type.palma.Assign(1); |
| 235 | shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1); | ||
| 216 | break; | 236 | break; |
| 217 | case Core::HID::NpadStyleIndex::NES: | 237 | case Core::HID::NpadStyleIndex::NES: |
| 218 | shared_memory->style_tag.lark.Assign(1); | 238 | shared_memory->style_tag.lark.Assign(1); |
| @@ -402,7 +422,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | |||
| 402 | libnx_state.connection_status.is_connected.Assign(1); | 422 | libnx_state.connection_status.is_connected.Assign(1); |
| 403 | switch (controller_type) { | 423 | switch (controller_type) { |
| 404 | case Core::HID::NpadStyleIndex::None: | 424 | case Core::HID::NpadStyleIndex::None: |
| 405 | UNREACHABLE(); | 425 | ASSERT(false); |
| 406 | break; | 426 | break; |
| 407 | case Core::HID::NpadStyleIndex::ProController: | 427 | case Core::HID::NpadStyleIndex::ProController: |
| 408 | case Core::HID::NpadStyleIndex::NES: | 428 | case Core::HID::NpadStyleIndex::NES: |
| @@ -529,6 +549,14 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing | |||
| 529 | auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state; | 549 | auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state; |
| 530 | auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state; | 550 | auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state; |
| 531 | 551 | ||
| 552 | // Clear previous state | ||
| 553 | sixaxis_fullkey_state = {}; | ||
| 554 | sixaxis_handheld_state = {}; | ||
| 555 | sixaxis_dual_left_state = {}; | ||
| 556 | sixaxis_dual_right_state = {}; | ||
| 557 | sixaxis_left_lifo_state = {}; | ||
| 558 | sixaxis_right_lifo_state = {}; | ||
| 559 | |||
| 532 | if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) { | 560 | if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) { |
| 533 | controller.sixaxis_at_rest = true; | 561 | controller.sixaxis_at_rest = true; |
| 534 | for (std::size_t e = 0; e < motion_state.size(); ++e) { | 562 | for (std::size_t e = 0; e < motion_state.size(); ++e) { |
| @@ -537,69 +565,56 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing | |||
| 537 | } | 565 | } |
| 538 | } | 566 | } |
| 539 | 567 | ||
| 568 | const auto set_motion_state = [&](SixAxisSensorState& state, | ||
| 569 | const Core::HID::ControllerMotion& hid_state) { | ||
| 570 | using namespace std::literals::chrono_literals; | ||
| 571 | static constexpr SixAxisSensorState default_motion_state = { | ||
| 572 | .delta_time = std::chrono::nanoseconds(5ms).count(), | ||
| 573 | .accel = {0, 0, -1.0f}, | ||
| 574 | .orientation = | ||
| 575 | { | ||
| 576 | Common::Vec3f{1.0f, 0, 0}, | ||
| 577 | Common::Vec3f{0, 1.0f, 0}, | ||
| 578 | Common::Vec3f{0, 0, 1.0f}, | ||
| 579 | }, | ||
| 580 | .attribute = {1}, | ||
| 581 | }; | ||
| 582 | if (!controller.sixaxis_sensor_enabled) { | ||
| 583 | state = default_motion_state; | ||
| 584 | return; | ||
| 585 | } | ||
| 586 | if (!Settings::values.motion_enabled.GetValue()) { | ||
| 587 | state = default_motion_state; | ||
| 588 | return; | ||
| 589 | } | ||
| 590 | state.attribute.is_connected.Assign(1); | ||
| 591 | state.delta_time = std::chrono::nanoseconds(5ms).count(); | ||
| 592 | state.accel = hid_state.accel; | ||
| 593 | state.gyro = hid_state.gyro; | ||
| 594 | state.rotation = hid_state.rotation; | ||
| 595 | state.orientation = hid_state.orientation; | ||
| 596 | }; | ||
| 597 | |||
| 540 | switch (controller_type) { | 598 | switch (controller_type) { |
| 541 | case Core::HID::NpadStyleIndex::None: | 599 | case Core::HID::NpadStyleIndex::None: |
| 542 | UNREACHABLE(); | 600 | ASSERT(false); |
| 543 | break; | 601 | break; |
| 544 | case Core::HID::NpadStyleIndex::ProController: | 602 | case Core::HID::NpadStyleIndex::ProController: |
| 545 | sixaxis_fullkey_state.attribute.raw = 0; | 603 | case Core::HID::NpadStyleIndex::Pokeball: |
| 546 | if (controller.sixaxis_sensor_enabled) { | 604 | set_motion_state(sixaxis_fullkey_state, motion_state[0]); |
| 547 | sixaxis_fullkey_state.attribute.is_connected.Assign(1); | ||
| 548 | sixaxis_fullkey_state.accel = motion_state[0].accel; | ||
| 549 | sixaxis_fullkey_state.gyro = motion_state[0].gyro; | ||
| 550 | sixaxis_fullkey_state.rotation = motion_state[0].rotation; | ||
| 551 | sixaxis_fullkey_state.orientation = motion_state[0].orientation; | ||
| 552 | } | ||
| 553 | break; | 605 | break; |
| 554 | case Core::HID::NpadStyleIndex::Handheld: | 606 | case Core::HID::NpadStyleIndex::Handheld: |
| 555 | sixaxis_handheld_state.attribute.raw = 0; | 607 | set_motion_state(sixaxis_handheld_state, motion_state[0]); |
| 556 | if (controller.sixaxis_sensor_enabled) { | ||
| 557 | sixaxis_handheld_state.attribute.is_connected.Assign(1); | ||
| 558 | sixaxis_handheld_state.accel = motion_state[0].accel; | ||
| 559 | sixaxis_handheld_state.gyro = motion_state[0].gyro; | ||
| 560 | sixaxis_handheld_state.rotation = motion_state[0].rotation; | ||
| 561 | sixaxis_handheld_state.orientation = motion_state[0].orientation; | ||
| 562 | } | ||
| 563 | break; | 608 | break; |
| 564 | case Core::HID::NpadStyleIndex::JoyconDual: | 609 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 565 | sixaxis_dual_left_state.attribute.raw = 0; | 610 | set_motion_state(sixaxis_dual_left_state, motion_state[0]); |
| 566 | sixaxis_dual_right_state.attribute.raw = 0; | 611 | set_motion_state(sixaxis_dual_right_state, motion_state[1]); |
| 567 | if (controller.sixaxis_sensor_enabled) { | ||
| 568 | // Set motion for the left joycon | ||
| 569 | sixaxis_dual_left_state.attribute.is_connected.Assign(1); | ||
| 570 | sixaxis_dual_left_state.accel = motion_state[0].accel; | ||
| 571 | sixaxis_dual_left_state.gyro = motion_state[0].gyro; | ||
| 572 | sixaxis_dual_left_state.rotation = motion_state[0].rotation; | ||
| 573 | sixaxis_dual_left_state.orientation = motion_state[0].orientation; | ||
| 574 | } | ||
| 575 | if (controller.sixaxis_sensor_enabled) { | ||
| 576 | // Set motion for the right joycon | ||
| 577 | sixaxis_dual_right_state.attribute.is_connected.Assign(1); | ||
| 578 | sixaxis_dual_right_state.accel = motion_state[1].accel; | ||
| 579 | sixaxis_dual_right_state.gyro = motion_state[1].gyro; | ||
| 580 | sixaxis_dual_right_state.rotation = motion_state[1].rotation; | ||
| 581 | sixaxis_dual_right_state.orientation = motion_state[1].orientation; | ||
| 582 | } | ||
| 583 | break; | 612 | break; |
| 584 | case Core::HID::NpadStyleIndex::JoyconLeft: | 613 | case Core::HID::NpadStyleIndex::JoyconLeft: |
| 585 | sixaxis_left_lifo_state.attribute.raw = 0; | 614 | set_motion_state(sixaxis_left_lifo_state, motion_state[0]); |
| 586 | if (controller.sixaxis_sensor_enabled) { | ||
| 587 | sixaxis_left_lifo_state.attribute.is_connected.Assign(1); | ||
| 588 | sixaxis_left_lifo_state.accel = motion_state[0].accel; | ||
| 589 | sixaxis_left_lifo_state.gyro = motion_state[0].gyro; | ||
| 590 | sixaxis_left_lifo_state.rotation = motion_state[0].rotation; | ||
| 591 | sixaxis_left_lifo_state.orientation = motion_state[0].orientation; | ||
| 592 | } | ||
| 593 | break; | 615 | break; |
| 594 | case Core::HID::NpadStyleIndex::JoyconRight: | 616 | case Core::HID::NpadStyleIndex::JoyconRight: |
| 595 | sixaxis_right_lifo_state.attribute.raw = 0; | 617 | set_motion_state(sixaxis_right_lifo_state, motion_state[1]); |
| 596 | if (controller.sixaxis_sensor_enabled) { | ||
| 597 | sixaxis_right_lifo_state.attribute.is_connected.Assign(1); | ||
| 598 | sixaxis_right_lifo_state.accel = motion_state[1].accel; | ||
| 599 | sixaxis_right_lifo_state.gyro = motion_state[1].gyro; | ||
| 600 | sixaxis_right_lifo_state.rotation = motion_state[1].rotation; | ||
| 601 | sixaxis_right_lifo_state.orientation = motion_state[1].orientation; | ||
| 602 | } | ||
| 603 | break; | 618 | break; |
| 604 | default: | 619 | default: |
| 605 | break; | 620 | break; |
| @@ -676,6 +691,12 @@ std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const { | |||
| 676 | } | 691 | } |
| 677 | 692 | ||
| 678 | void Controller_NPad::SetHoldType(NpadJoyHoldType joy_hold_type) { | 693 | void Controller_NPad::SetHoldType(NpadJoyHoldType joy_hold_type) { |
| 694 | if (joy_hold_type != NpadJoyHoldType::Horizontal && | ||
| 695 | joy_hold_type != NpadJoyHoldType::Vertical) { | ||
| 696 | LOG_ERROR(Service_HID, "Npad joy hold type needs to be valid, joy_hold_type={}", | ||
| 697 | joy_hold_type); | ||
| 698 | return; | ||
| 699 | } | ||
| 679 | hold_type = joy_hold_type; | 700 | hold_type = joy_hold_type; |
| 680 | } | 701 | } |
| 681 | 702 | ||
| @@ -699,11 +720,12 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode | |||
| 699 | return communication_mode; | 720 | return communication_mode; |
| 700 | } | 721 | } |
| 701 | 722 | ||
| 702 | void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type, | 723 | ResultCode Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, |
| 703 | NpadJoyAssignmentMode assignment_mode) { | 724 | NpadJoyDeviceType npad_device_type, |
| 725 | NpadJoyAssignmentMode assignment_mode) { | ||
| 704 | if (!IsNpadIdValid(npad_id)) { | 726 | if (!IsNpadIdValid(npad_id)) { |
| 705 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 727 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 706 | return; | 728 | return InvalidNpadId; |
| 707 | } | 729 | } |
| 708 | 730 | ||
| 709 | auto& controller = GetControllerFromNpadIdType(npad_id); | 731 | auto& controller = GetControllerFromNpadIdType(npad_id); |
| @@ -712,7 +734,7 @@ void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceTy | |||
| 712 | } | 734 | } |
| 713 | 735 | ||
| 714 | if (!controller.device->IsConnected()) { | 736 | if (!controller.device->IsConnected()) { |
| 715 | return; | 737 | return ResultSuccess; |
| 716 | } | 738 | } |
| 717 | 739 | ||
| 718 | if (assignment_mode == NpadJoyAssignmentMode::Dual) { | 740 | if (assignment_mode == NpadJoyAssignmentMode::Dual) { |
| @@ -721,34 +743,34 @@ void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceTy | |||
| 721 | controller.is_dual_left_connected = true; | 743 | controller.is_dual_left_connected = true; |
| 722 | controller.is_dual_right_connected = false; | 744 | controller.is_dual_right_connected = false; |
| 723 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); | 745 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); |
| 724 | return; | 746 | return ResultSuccess; |
| 725 | } | 747 | } |
| 726 | if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) { | 748 | if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) { |
| 727 | DisconnectNpad(npad_id); | 749 | DisconnectNpad(npad_id); |
| 728 | controller.is_dual_left_connected = false; | 750 | controller.is_dual_left_connected = false; |
| 729 | controller.is_dual_right_connected = true; | 751 | controller.is_dual_right_connected = true; |
| 730 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); | 752 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); |
| 731 | return; | 753 | return ResultSuccess; |
| 732 | } | 754 | } |
| 733 | return; | 755 | return ResultSuccess; |
| 734 | } | 756 | } |
| 735 | 757 | ||
| 736 | // This is for NpadJoyAssignmentMode::Single | 758 | // This is for NpadJoyAssignmentMode::Single |
| 737 | 759 | ||
| 738 | // Only JoyconDual get affected by this function | 760 | // Only JoyconDual get affected by this function |
| 739 | if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) { | 761 | if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) { |
| 740 | return; | 762 | return ResultSuccess; |
| 741 | } | 763 | } |
| 742 | 764 | ||
| 743 | if (controller.is_dual_left_connected && !controller.is_dual_right_connected) { | 765 | if (controller.is_dual_left_connected && !controller.is_dual_right_connected) { |
| 744 | DisconnectNpad(npad_id); | 766 | DisconnectNpad(npad_id); |
| 745 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); | 767 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); |
| 746 | return; | 768 | return ResultSuccess; |
| 747 | } | 769 | } |
| 748 | if (!controller.is_dual_left_connected && controller.is_dual_right_connected) { | 770 | if (!controller.is_dual_left_connected && controller.is_dual_right_connected) { |
| 749 | DisconnectNpad(npad_id); | 771 | DisconnectNpad(npad_id); |
| 750 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); | 772 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); |
| 751 | return; | 773 | return ResultSuccess; |
| 752 | } | 774 | } |
| 753 | 775 | ||
| 754 | // We have two controllers connected to the same npad_id we need to split them | 776 | // We have two controllers connected to the same npad_id we need to split them |
| @@ -766,6 +788,7 @@ void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceTy | |||
| 766 | controller_2.is_dual_right_connected = false; | 788 | controller_2.is_dual_right_connected = false; |
| 767 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true); | 789 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true); |
| 768 | } | 790 | } |
| 791 | return ResultSuccess; | ||
| 769 | } | 792 | } |
| 770 | 793 | ||
| 771 | bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, | 794 | bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, |
| @@ -833,7 +856,7 @@ void Controller_NPad::VibrateController( | |||
| 833 | } | 856 | } |
| 834 | 857 | ||
| 835 | if (vibration_device_handle.device_index == Core::HID::DeviceIndex::None) { | 858 | if (vibration_device_handle.device_index == Core::HID::DeviceIndex::None) { |
| 836 | UNREACHABLE_MSG("DeviceIndex should never be None!"); | 859 | ASSERT_MSG(false, "DeviceIndex should never be None!"); |
| 837 | return; | 860 | return; |
| 838 | } | 861 | } |
| 839 | 862 | ||
| @@ -961,10 +984,10 @@ void Controller_NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, | |||
| 961 | InitNewlyAddedController(npad_id); | 984 | InitNewlyAddedController(npad_id); |
| 962 | } | 985 | } |
| 963 | 986 | ||
| 964 | void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { | 987 | ResultCode Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { |
| 965 | if (!IsNpadIdValid(npad_id)) { | 988 | if (!IsNpadIdValid(npad_id)) { |
| 966 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 989 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 967 | return; | 990 | return InvalidNpadId; |
| 968 | } | 991 | } |
| 969 | 992 | ||
| 970 | LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id); | 993 | LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id); |
| @@ -981,6 +1004,12 @@ void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { | |||
| 981 | shared_memory->device_type.raw = 0; | 1004 | shared_memory->device_type.raw = 0; |
| 982 | shared_memory->system_properties.raw = 0; | 1005 | shared_memory->system_properties.raw = 0; |
| 983 | shared_memory->button_properties.raw = 0; | 1006 | shared_memory->button_properties.raw = 0; |
| 1007 | shared_memory->sixaxis_fullkey_properties.raw = 0; | ||
| 1008 | shared_memory->sixaxis_handheld_properties.raw = 0; | ||
| 1009 | shared_memory->sixaxis_dual_left_properties.raw = 0; | ||
| 1010 | shared_memory->sixaxis_dual_right_properties.raw = 0; | ||
| 1011 | shared_memory->sixaxis_left_properties.raw = 0; | ||
| 1012 | shared_memory->sixaxis_right_properties.raw = 0; | ||
| 984 | shared_memory->battery_level_dual = 0; | 1013 | shared_memory->battery_level_dual = 0; |
| 985 | shared_memory->battery_level_left = 0; | 1014 | shared_memory->battery_level_left = 0; |
| 986 | shared_memory->battery_level_right = 0; | 1015 | shared_memory->battery_level_right = 0; |
| @@ -1001,346 +1030,268 @@ void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { | |||
| 1001 | controller.device->Disconnect(); | 1030 | controller.device->Disconnect(); |
| 1002 | SignalStyleSetChangedEvent(npad_id); | 1031 | SignalStyleSetChangedEvent(npad_id); |
| 1003 | WriteEmptyEntry(shared_memory); | 1032 | WriteEmptyEntry(shared_memory); |
| 1033 | return ResultSuccess; | ||
| 1004 | } | 1034 | } |
| 1005 | 1035 | ResultCode Controller_NPad::SetGyroscopeZeroDriftMode( | |
| 1006 | ResultCode Controller_NPad::SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, | 1036 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, GyroscopeZeroDriftMode drift_mode) { |
| 1007 | GyroscopeZeroDriftMode drift_mode) { | 1037 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); |
| 1008 | if (!IsDeviceHandleValid(sixaxis_handle)) { | 1038 | if (is_valid.IsError()) { |
| 1009 | LOG_ERROR(Service_HID, "Invalid handle"); | 1039 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); |
| 1010 | return NpadInvalidHandle; | 1040 | return is_valid; |
| 1011 | } | 1041 | } |
| 1012 | 1042 | ||
| 1013 | auto& controller = GetControllerFromHandle(sixaxis_handle); | 1043 | auto& sixaxis = GetSixaxisState(sixaxis_handle); |
| 1014 | switch (sixaxis_handle.npad_type) { | 1044 | sixaxis.gyroscope_zero_drift_mode = drift_mode; |
| 1015 | case Core::HID::NpadStyleIndex::ProController: | ||
| 1016 | controller.sixaxis_fullkey.gyroscope_zero_drift_mode = drift_mode; | ||
| 1017 | break; | ||
| 1018 | case Core::HID::NpadStyleIndex::Handheld: | ||
| 1019 | controller.sixaxis_handheld.gyroscope_zero_drift_mode = drift_mode; | ||
| 1020 | break; | ||
| 1021 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 1022 | case Core::HID::NpadStyleIndex::GameCube: | ||
| 1023 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 1024 | if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { | ||
| 1025 | controller.sixaxis_dual_left.gyroscope_zero_drift_mode = drift_mode; | ||
| 1026 | break; | ||
| 1027 | } | ||
| 1028 | controller.sixaxis_dual_right.gyroscope_zero_drift_mode = drift_mode; | ||
| 1029 | break; | ||
| 1030 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 1031 | controller.sixaxis_left.gyroscope_zero_drift_mode = drift_mode; | ||
| 1032 | break; | ||
| 1033 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 1034 | controller.sixaxis_right.gyroscope_zero_drift_mode = drift_mode; | ||
| 1035 | break; | ||
| 1036 | default: | ||
| 1037 | LOG_ERROR(Service_HID, "Invalid Npad type {}", sixaxis_handle.npad_type); | ||
| 1038 | return NpadInvalidHandle; | ||
| 1039 | } | ||
| 1040 | 1045 | ||
| 1041 | return ResultSuccess; | 1046 | return ResultSuccess; |
| 1042 | } | 1047 | } |
| 1043 | 1048 | ||
| 1044 | ResultCode Controller_NPad::GetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, | 1049 | ResultCode Controller_NPad::GetGyroscopeZeroDriftMode( |
| 1045 | GyroscopeZeroDriftMode& drift_mode) const { | 1050 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 1046 | if (!IsDeviceHandleValid(sixaxis_handle)) { | 1051 | GyroscopeZeroDriftMode& drift_mode) const { |
| 1047 | LOG_ERROR(Service_HID, "Invalid handle"); | 1052 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); |
| 1048 | return NpadInvalidHandle; | 1053 | if (is_valid.IsError()) { |
| 1054 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); | ||
| 1055 | return is_valid; | ||
| 1049 | } | 1056 | } |
| 1050 | 1057 | ||
| 1051 | auto& controller = GetControllerFromHandle(sixaxis_handle); | 1058 | const auto& sixaxis = GetSixaxisState(sixaxis_handle); |
| 1052 | switch (sixaxis_handle.npad_type) { | 1059 | drift_mode = sixaxis.gyroscope_zero_drift_mode; |
| 1053 | case Core::HID::NpadStyleIndex::ProController: | ||
| 1054 | drift_mode = controller.sixaxis_fullkey.gyroscope_zero_drift_mode; | ||
| 1055 | break; | ||
| 1056 | case Core::HID::NpadStyleIndex::Handheld: | ||
| 1057 | drift_mode = controller.sixaxis_handheld.gyroscope_zero_drift_mode; | ||
| 1058 | break; | ||
| 1059 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 1060 | case Core::HID::NpadStyleIndex::GameCube: | ||
| 1061 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 1062 | if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { | ||
| 1063 | drift_mode = controller.sixaxis_dual_left.gyroscope_zero_drift_mode; | ||
| 1064 | break; | ||
| 1065 | } | ||
| 1066 | drift_mode = controller.sixaxis_dual_right.gyroscope_zero_drift_mode; | ||
| 1067 | break; | ||
| 1068 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 1069 | drift_mode = controller.sixaxis_left.gyroscope_zero_drift_mode; | ||
| 1070 | break; | ||
| 1071 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 1072 | drift_mode = controller.sixaxis_right.gyroscope_zero_drift_mode; | ||
| 1073 | break; | ||
| 1074 | default: | ||
| 1075 | LOG_ERROR(Service_HID, "Invalid Npad type {}", sixaxis_handle.npad_type); | ||
| 1076 | return NpadInvalidHandle; | ||
| 1077 | } | ||
| 1078 | 1060 | ||
| 1079 | return ResultSuccess; | 1061 | return ResultSuccess; |
| 1080 | } | 1062 | } |
| 1081 | 1063 | ||
| 1082 | ResultCode Controller_NPad::IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle, | 1064 | ResultCode Controller_NPad::IsSixAxisSensorAtRest( |
| 1083 | bool& is_at_rest) const { | 1065 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_at_rest) const { |
| 1084 | if (!IsDeviceHandleValid(sixaxis_handle)) { | 1066 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); |
| 1085 | LOG_ERROR(Service_HID, "Invalid handle"); | 1067 | if (is_valid.IsError()) { |
| 1086 | return NpadInvalidHandle; | 1068 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); |
| 1069 | return is_valid; | ||
| 1087 | } | 1070 | } |
| 1071 | |||
| 1088 | const auto& controller = GetControllerFromHandle(sixaxis_handle); | 1072 | const auto& controller = GetControllerFromHandle(sixaxis_handle); |
| 1089 | is_at_rest = controller.sixaxis_at_rest; | 1073 | is_at_rest = controller.sixaxis_at_rest; |
| 1090 | return ResultSuccess; | 1074 | return ResultSuccess; |
| 1091 | } | 1075 | } |
| 1092 | 1076 | ||
| 1093 | ResultCode Controller_NPad::IsFirmwareUpdateAvailableForSixAxisSensor( | 1077 | ResultCode Controller_NPad::IsFirmwareUpdateAvailableForSixAxisSensor( |
| 1094 | Core::HID::SixAxisSensorHandle sixaxis_handle, bool& is_firmware_available) const { | 1078 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const { |
| 1095 | if (!IsDeviceHandleValid(sixaxis_handle)) { | 1079 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); |
| 1096 | LOG_ERROR(Service_HID, "Invalid handle"); | 1080 | if (is_valid.IsError()) { |
| 1097 | return NpadInvalidHandle; | 1081 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); |
| 1082 | return is_valid; | ||
| 1098 | } | 1083 | } |
| 1099 | 1084 | ||
| 1100 | // We don't support joycon firmware updates | 1085 | const auto& sixaxis_properties = GetSixaxisProperties(sixaxis_handle); |
| 1101 | is_firmware_available = false; | 1086 | is_firmware_available = sixaxis_properties.is_firmware_update_available != 0; |
| 1102 | return ResultSuccess; | 1087 | return ResultSuccess; |
| 1103 | } | 1088 | } |
| 1104 | 1089 | ||
| 1105 | ResultCode Controller_NPad::SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, | 1090 | ResultCode Controller_NPad::EnableSixAxisSensorUnalteredPassthrough( |
| 1091 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled) { | ||
| 1092 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); | ||
| 1093 | if (is_valid.IsError()) { | ||
| 1094 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); | ||
| 1095 | return is_valid; | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | auto& sixaxis = GetSixaxisState(sixaxis_handle); | ||
| 1099 | sixaxis.unaltered_passtrough = is_enabled; | ||
| 1100 | return ResultSuccess; | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | ResultCode Controller_NPad::IsSixAxisSensorUnalteredPassthroughEnabled( | ||
| 1104 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const { | ||
| 1105 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); | ||
| 1106 | if (is_valid.IsError()) { | ||
| 1107 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); | ||
| 1108 | return is_valid; | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | const auto& sixaxis = GetSixaxisState(sixaxis_handle); | ||
| 1112 | is_enabled = sixaxis.unaltered_passtrough; | ||
| 1113 | return ResultSuccess; | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | ResultCode Controller_NPad::LoadSixAxisSensorCalibrationParameter( | ||
| 1117 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, | ||
| 1118 | Core::HID::SixAxisSensorCalibrationParameter& calibration) const { | ||
| 1119 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); | ||
| 1120 | if (is_valid.IsError()) { | ||
| 1121 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); | ||
| 1122 | return is_valid; | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | // TODO: Request this data to the controller. On error return 0xd8ca | ||
| 1126 | const auto& sixaxis = GetSixaxisState(sixaxis_handle); | ||
| 1127 | calibration = sixaxis.calibration; | ||
| 1128 | return ResultSuccess; | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | ResultCode Controller_NPad::GetSixAxisSensorIcInformation( | ||
| 1132 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, | ||
| 1133 | Core::HID::SixAxisSensorIcInformation& ic_information) const { | ||
| 1134 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); | ||
| 1135 | if (is_valid.IsError()) { | ||
| 1136 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); | ||
| 1137 | return is_valid; | ||
| 1138 | } | ||
| 1139 | |||
| 1140 | // TODO: Request this data to the controller. On error return 0xd8ca | ||
| 1141 | const auto& sixaxis = GetSixaxisState(sixaxis_handle); | ||
| 1142 | ic_information = sixaxis.ic_information; | ||
| 1143 | return ResultSuccess; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | ResultCode Controller_NPad::ResetIsSixAxisSensorDeviceNewlyAssigned( | ||
| 1147 | const Core::HID::SixAxisSensorHandle& sixaxis_handle) { | ||
| 1148 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); | ||
| 1149 | if (is_valid.IsError()) { | ||
| 1150 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); | ||
| 1151 | return is_valid; | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | auto& sixaxis_properties = GetSixaxisProperties(sixaxis_handle); | ||
| 1155 | sixaxis_properties.is_newly_assigned.Assign(0); | ||
| 1156 | |||
| 1157 | return ResultSuccess; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | ResultCode Controller_NPad::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, | ||
| 1106 | bool sixaxis_status) { | 1161 | bool sixaxis_status) { |
| 1107 | if (!IsDeviceHandleValid(sixaxis_handle)) { | 1162 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); |
| 1108 | LOG_ERROR(Service_HID, "Invalid handle"); | 1163 | if (is_valid.IsError()) { |
| 1109 | return NpadInvalidHandle; | 1164 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); |
| 1165 | return is_valid; | ||
| 1110 | } | 1166 | } |
| 1167 | |||
| 1111 | auto& controller = GetControllerFromHandle(sixaxis_handle); | 1168 | auto& controller = GetControllerFromHandle(sixaxis_handle); |
| 1112 | controller.sixaxis_sensor_enabled = sixaxis_status; | 1169 | controller.sixaxis_sensor_enabled = sixaxis_status; |
| 1113 | return ResultSuccess; | 1170 | return ResultSuccess; |
| 1114 | } | 1171 | } |
| 1115 | 1172 | ||
| 1116 | ResultCode Controller_NPad::IsSixAxisSensorFusionEnabled( | 1173 | ResultCode Controller_NPad::IsSixAxisSensorFusionEnabled( |
| 1117 | Core::HID::SixAxisSensorHandle sixaxis_handle, bool& is_fusion_enabled) const { | 1174 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_fusion_enabled) const { |
| 1118 | if (!IsDeviceHandleValid(sixaxis_handle)) { | 1175 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); |
| 1119 | LOG_ERROR(Service_HID, "Invalid handle"); | 1176 | if (is_valid.IsError()) { |
| 1120 | return NpadInvalidHandle; | 1177 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); |
| 1178 | return is_valid; | ||
| 1121 | } | 1179 | } |
| 1122 | 1180 | ||
| 1123 | auto& controller = GetControllerFromHandle(sixaxis_handle); | 1181 | const auto& sixaxis = GetSixaxisState(sixaxis_handle); |
| 1124 | switch (sixaxis_handle.npad_type) { | 1182 | is_fusion_enabled = sixaxis.is_fusion_enabled; |
| 1125 | case Core::HID::NpadStyleIndex::ProController: | ||
| 1126 | is_fusion_enabled = controller.sixaxis_fullkey.is_fusion_enabled; | ||
| 1127 | break; | ||
| 1128 | case Core::HID::NpadStyleIndex::Handheld: | ||
| 1129 | is_fusion_enabled = controller.sixaxis_handheld.is_fusion_enabled; | ||
| 1130 | break; | ||
| 1131 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 1132 | case Core::HID::NpadStyleIndex::GameCube: | ||
| 1133 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 1134 | if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { | ||
| 1135 | is_fusion_enabled = controller.sixaxis_dual_left.is_fusion_enabled; | ||
| 1136 | break; | ||
| 1137 | } | ||
| 1138 | is_fusion_enabled = controller.sixaxis_dual_right.is_fusion_enabled; | ||
| 1139 | break; | ||
| 1140 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 1141 | is_fusion_enabled = controller.sixaxis_left.is_fusion_enabled; | ||
| 1142 | break; | ||
| 1143 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 1144 | is_fusion_enabled = controller.sixaxis_right.is_fusion_enabled; | ||
| 1145 | break; | ||
| 1146 | default: | ||
| 1147 | LOG_ERROR(Service_HID, "Invalid Npad type {}", sixaxis_handle.npad_type); | ||
| 1148 | return NpadInvalidHandle; | ||
| 1149 | } | ||
| 1150 | 1183 | ||
| 1151 | return ResultSuccess; | 1184 | return ResultSuccess; |
| 1152 | } | 1185 | } |
| 1153 | ResultCode Controller_NPad::SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, | 1186 | ResultCode Controller_NPad::SetSixAxisFusionEnabled( |
| 1154 | bool is_fusion_enabled) { | 1187 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_fusion_enabled) { |
| 1155 | if (!IsDeviceHandleValid(sixaxis_handle)) { | 1188 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); |
| 1156 | LOG_ERROR(Service_HID, "Invalid handle"); | 1189 | if (is_valid.IsError()) { |
| 1157 | return NpadInvalidHandle; | 1190 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); |
| 1191 | return is_valid; | ||
| 1158 | } | 1192 | } |
| 1159 | 1193 | ||
| 1160 | auto& controller = GetControllerFromHandle(sixaxis_handle); | 1194 | auto& sixaxis = GetSixaxisState(sixaxis_handle); |
| 1161 | switch (sixaxis_handle.npad_type) { | 1195 | sixaxis.is_fusion_enabled = is_fusion_enabled; |
| 1162 | case Core::HID::NpadStyleIndex::ProController: | ||
| 1163 | controller.sixaxis_fullkey.is_fusion_enabled = is_fusion_enabled; | ||
| 1164 | break; | ||
| 1165 | case Core::HID::NpadStyleIndex::Handheld: | ||
| 1166 | controller.sixaxis_handheld.is_fusion_enabled = is_fusion_enabled; | ||
| 1167 | break; | ||
| 1168 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 1169 | case Core::HID::NpadStyleIndex::GameCube: | ||
| 1170 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 1171 | if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { | ||
| 1172 | controller.sixaxis_dual_left.is_fusion_enabled = is_fusion_enabled; | ||
| 1173 | break; | ||
| 1174 | } | ||
| 1175 | controller.sixaxis_dual_right.is_fusion_enabled = is_fusion_enabled; | ||
| 1176 | break; | ||
| 1177 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 1178 | controller.sixaxis_left.is_fusion_enabled = is_fusion_enabled; | ||
| 1179 | break; | ||
| 1180 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 1181 | controller.sixaxis_right.is_fusion_enabled = is_fusion_enabled; | ||
| 1182 | break; | ||
| 1183 | default: | ||
| 1184 | LOG_ERROR(Service_HID, "Invalid Npad type {}", sixaxis_handle.npad_type); | ||
| 1185 | return NpadInvalidHandle; | ||
| 1186 | } | ||
| 1187 | 1196 | ||
| 1188 | return ResultSuccess; | 1197 | return ResultSuccess; |
| 1189 | } | 1198 | } |
| 1190 | 1199 | ||
| 1191 | ResultCode Controller_NPad::SetSixAxisFusionParameters( | 1200 | ResultCode Controller_NPad::SetSixAxisFusionParameters( |
| 1192 | Core::HID::SixAxisSensorHandle sixaxis_handle, | 1201 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 1193 | Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) { | 1202 | Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) { |
| 1194 | if (!IsDeviceHandleValid(sixaxis_handle)) { | 1203 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); |
| 1195 | LOG_ERROR(Service_HID, "Invalid handle"); | 1204 | if (is_valid.IsError()) { |
| 1196 | return NpadInvalidHandle; | 1205 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); |
| 1206 | return is_valid; | ||
| 1197 | } | 1207 | } |
| 1208 | |||
| 1198 | const auto param1 = sixaxis_fusion_parameters.parameter1; | 1209 | const auto param1 = sixaxis_fusion_parameters.parameter1; |
| 1199 | if (param1 < 0.0f || param1 > 1.0f) { | 1210 | if (param1 < 0.0f || param1 > 1.0f) { |
| 1200 | return InvalidSixAxisFusionRange; | 1211 | return InvalidSixAxisFusionRange; |
| 1201 | } | 1212 | } |
| 1202 | 1213 | ||
| 1203 | auto& controller = GetControllerFromHandle(sixaxis_handle); | 1214 | auto& sixaxis = GetSixaxisState(sixaxis_handle); |
| 1204 | switch (sixaxis_handle.npad_type) { | 1215 | sixaxis.fusion = sixaxis_fusion_parameters; |
| 1205 | case Core::HID::NpadStyleIndex::ProController: | ||
| 1206 | controller.sixaxis_fullkey.fusion = sixaxis_fusion_parameters; | ||
| 1207 | break; | ||
| 1208 | case Core::HID::NpadStyleIndex::Handheld: | ||
| 1209 | controller.sixaxis_handheld.fusion = sixaxis_fusion_parameters; | ||
| 1210 | break; | ||
| 1211 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 1212 | case Core::HID::NpadStyleIndex::GameCube: | ||
| 1213 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 1214 | if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { | ||
| 1215 | controller.sixaxis_dual_left.fusion = sixaxis_fusion_parameters; | ||
| 1216 | break; | ||
| 1217 | } | ||
| 1218 | controller.sixaxis_dual_right.fusion = sixaxis_fusion_parameters; | ||
| 1219 | break; | ||
| 1220 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 1221 | controller.sixaxis_left.fusion = sixaxis_fusion_parameters; | ||
| 1222 | break; | ||
| 1223 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 1224 | controller.sixaxis_right.fusion = sixaxis_fusion_parameters; | ||
| 1225 | break; | ||
| 1226 | default: | ||
| 1227 | LOG_ERROR(Service_HID, "Invalid Npad type {}", sixaxis_handle.npad_type); | ||
| 1228 | return NpadInvalidHandle; | ||
| 1229 | } | ||
| 1230 | 1216 | ||
| 1231 | return ResultSuccess; | 1217 | return ResultSuccess; |
| 1232 | } | 1218 | } |
| 1233 | 1219 | ||
| 1234 | ResultCode Controller_NPad::GetSixAxisFusionParameters( | 1220 | ResultCode Controller_NPad::GetSixAxisFusionParameters( |
| 1235 | Core::HID::SixAxisSensorHandle sixaxis_handle, | 1221 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 1236 | Core::HID::SixAxisSensorFusionParameters& parameters) const { | 1222 | Core::HID::SixAxisSensorFusionParameters& parameters) const { |
| 1237 | if (!IsDeviceHandleValid(sixaxis_handle)) { | 1223 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); |
| 1238 | LOG_ERROR(Service_HID, "Invalid handle"); | 1224 | if (is_valid.IsError()) { |
| 1239 | return NpadInvalidHandle; | 1225 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); |
| 1226 | return is_valid; | ||
| 1240 | } | 1227 | } |
| 1241 | 1228 | ||
| 1242 | const auto& controller = GetControllerFromHandle(sixaxis_handle); | 1229 | const auto& sixaxis = GetSixaxisState(sixaxis_handle); |
| 1243 | switch (sixaxis_handle.npad_type) { | 1230 | parameters = sixaxis.fusion; |
| 1244 | case Core::HID::NpadStyleIndex::ProController: | ||
| 1245 | parameters = controller.sixaxis_fullkey.fusion; | ||
| 1246 | break; | ||
| 1247 | case Core::HID::NpadStyleIndex::Handheld: | ||
| 1248 | parameters = controller.sixaxis_handheld.fusion; | ||
| 1249 | break; | ||
| 1250 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 1251 | case Core::HID::NpadStyleIndex::GameCube: | ||
| 1252 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 1253 | if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { | ||
| 1254 | parameters = controller.sixaxis_dual_left.fusion; | ||
| 1255 | break; | ||
| 1256 | } | ||
| 1257 | parameters = controller.sixaxis_dual_right.fusion; | ||
| 1258 | break; | ||
| 1259 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 1260 | parameters = controller.sixaxis_left.fusion; | ||
| 1261 | break; | ||
| 1262 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 1263 | parameters = controller.sixaxis_right.fusion; | ||
| 1264 | break; | ||
| 1265 | default: | ||
| 1266 | LOG_ERROR(Service_HID, "Invalid Npad type {}", sixaxis_handle.npad_type); | ||
| 1267 | return NpadInvalidHandle; | ||
| 1268 | } | ||
| 1269 | 1231 | ||
| 1270 | return ResultSuccess; | 1232 | return ResultSuccess; |
| 1271 | } | 1233 | } |
| 1272 | 1234 | ||
| 1273 | void Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, | 1235 | ResultCode Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, |
| 1274 | Core::HID::NpadIdType npad_id_2) { | 1236 | Core::HID::NpadIdType npad_id_2) { |
| 1275 | if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { | 1237 | if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { |
| 1276 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, | 1238 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, |
| 1277 | npad_id_2); | 1239 | npad_id_2); |
| 1278 | return; | 1240 | return InvalidNpadId; |
| 1279 | } | 1241 | } |
| 1280 | auto& controller_1 = GetControllerFromNpadIdType(npad_id_1); | 1242 | auto& controller_1 = GetControllerFromNpadIdType(npad_id_1); |
| 1281 | auto& controller_2 = GetControllerFromNpadIdType(npad_id_2); | 1243 | auto& controller_2 = GetControllerFromNpadIdType(npad_id_2); |
| 1282 | const auto controller_style_1 = controller_1.device->GetNpadStyleIndex(); | 1244 | auto controller_style_1 = controller_1.device->GetNpadStyleIndex(); |
| 1283 | const auto controller_style_2 = controller_2.device->GetNpadStyleIndex(); | 1245 | auto controller_style_2 = controller_2.device->GetNpadStyleIndex(); |
| 1284 | bool merge_controllers = false; | ||
| 1285 | 1246 | ||
| 1286 | // If the controllers at both npad indices form a pair of left and right joycons, merge them. | 1247 | // Simplify this code by converting dualjoycon with only a side connected to single joycons |
| 1287 | // Otherwise, do nothing. | 1248 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual) { |
| 1249 | if (controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) { | ||
| 1250 | controller_style_1 = Core::HID::NpadStyleIndex::JoyconLeft; | ||
| 1251 | } | ||
| 1252 | if (!controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) { | ||
| 1253 | controller_style_1 = Core::HID::NpadStyleIndex::JoyconRight; | ||
| 1254 | } | ||
| 1255 | } | ||
| 1256 | if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual) { | ||
| 1257 | if (controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) { | ||
| 1258 | controller_style_2 = Core::HID::NpadStyleIndex::JoyconLeft; | ||
| 1259 | } | ||
| 1260 | if (!controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) { | ||
| 1261 | controller_style_2 = Core::HID::NpadStyleIndex::JoyconRight; | ||
| 1262 | } | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | // Invalid merge errors | ||
| 1266 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual || | ||
| 1267 | controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual) { | ||
| 1268 | return NpadIsDualJoycon; | ||
| 1269 | } | ||
| 1288 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft && | 1270 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft && |
| 1271 | controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft) { | ||
| 1272 | return NpadIsSameType; | ||
| 1273 | } | ||
| 1274 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight && | ||
| 1289 | controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight) { | 1275 | controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight) { |
| 1290 | merge_controllers = true; | 1276 | return NpadIsSameType; |
| 1291 | } | 1277 | } |
| 1292 | if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft && | 1278 | |
| 1293 | controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight) { | 1279 | // These exceptions are handled as if they where dual joycon |
| 1294 | merge_controllers = true; | 1280 | if (controller_style_1 != Core::HID::NpadStyleIndex::JoyconLeft && |
| 1295 | } | 1281 | controller_style_1 != Core::HID::NpadStyleIndex::JoyconRight) { |
| 1296 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && | 1282 | return NpadIsDualJoycon; |
| 1297 | controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight && | 1283 | } |
| 1298 | controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) { | 1284 | if (controller_style_2 != Core::HID::NpadStyleIndex::JoyconLeft && |
| 1299 | merge_controllers = true; | 1285 | controller_style_2 != Core::HID::NpadStyleIndex::JoyconRight) { |
| 1300 | } | 1286 | return NpadIsDualJoycon; |
| 1301 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1302 | controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft && | ||
| 1303 | !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) { | ||
| 1304 | merge_controllers = true; | ||
| 1305 | } | ||
| 1306 | if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1307 | controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight && | ||
| 1308 | controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) { | ||
| 1309 | merge_controllers = true; | ||
| 1310 | } | ||
| 1311 | if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1312 | controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft && | ||
| 1313 | !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) { | ||
| 1314 | merge_controllers = true; | ||
| 1315 | } | ||
| 1316 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1317 | controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1318 | controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected && | ||
| 1319 | !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) { | ||
| 1320 | merge_controllers = true; | ||
| 1321 | } | ||
| 1322 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1323 | controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1324 | !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected && | ||
| 1325 | controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) { | ||
| 1326 | merge_controllers = true; | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | if (merge_controllers) { | ||
| 1330 | // Disconnect the joycon at the second id and connect the dual joycon at the first index. | ||
| 1331 | DisconnectNpad(npad_id_2); | ||
| 1332 | controller_1.is_dual_left_connected = true; | ||
| 1333 | controller_1.is_dual_right_connected = true; | ||
| 1334 | AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1); | ||
| 1335 | return; | ||
| 1336 | } | 1287 | } |
| 1337 | LOG_WARNING(Service_HID, | 1288 | |
| 1338 | "Controllers can't be merged npad_id_1:{}, npad_id_2:{}, type_1:{}, type_2:{}, " | 1289 | // Disconnect the joycon at the second id and connect the dual joycon at the first index. |
| 1339 | "dual_1(left/right):{}/{}, dual_2(left/right):{}/{}", | 1290 | DisconnectNpad(npad_id_2); |
| 1340 | npad_id_1, npad_id_2, controller_1.device->GetNpadStyleIndex(), | 1291 | controller_1.is_dual_left_connected = true; |
| 1341 | controller_2.device->GetNpadStyleIndex(), controller_1.is_dual_left_connected, | 1292 | controller_1.is_dual_right_connected = true; |
| 1342 | controller_1.is_dual_right_connected, controller_2.is_dual_left_connected, | 1293 | AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1); |
| 1343 | controller_2.is_dual_right_connected); | 1294 | return ResultSuccess; |
| 1344 | } | 1295 | } |
| 1345 | 1296 | ||
| 1346 | void Controller_NPad::StartLRAssignmentMode() { | 1297 | void Controller_NPad::StartLRAssignmentMode() { |
| @@ -1353,17 +1304,17 @@ void Controller_NPad::StopLRAssignmentMode() { | |||
| 1353 | is_in_lr_assignment_mode = false; | 1304 | is_in_lr_assignment_mode = false; |
| 1354 | } | 1305 | } |
| 1355 | 1306 | ||
| 1356 | bool Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, | 1307 | ResultCode Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, |
| 1357 | Core::HID::NpadIdType npad_id_2) { | 1308 | Core::HID::NpadIdType npad_id_2) { |
| 1358 | if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { | 1309 | if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { |
| 1359 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, | 1310 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, |
| 1360 | npad_id_2); | 1311 | npad_id_2); |
| 1361 | return false; | 1312 | return InvalidNpadId; |
| 1362 | } | 1313 | } |
| 1363 | if (npad_id_1 == Core::HID::NpadIdType::Handheld || | 1314 | if (npad_id_1 == Core::HID::NpadIdType::Handheld || |
| 1364 | npad_id_2 == Core::HID::NpadIdType::Handheld || npad_id_1 == Core::HID::NpadIdType::Other || | 1315 | npad_id_2 == Core::HID::NpadIdType::Handheld || npad_id_1 == Core::HID::NpadIdType::Other || |
| 1365 | npad_id_2 == Core::HID::NpadIdType::Other) { | 1316 | npad_id_2 == Core::HID::NpadIdType::Other) { |
| 1366 | return true; | 1317 | return ResultSuccess; |
| 1367 | } | 1318 | } |
| 1368 | const auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device; | 1319 | const auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device; |
| 1369 | const auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device; | 1320 | const auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device; |
| @@ -1373,46 +1324,49 @@ bool Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, | |||
| 1373 | const auto is_connected_2 = controller_2->IsConnected(); | 1324 | const auto is_connected_2 = controller_2->IsConnected(); |
| 1374 | 1325 | ||
| 1375 | if (!IsControllerSupported(type_index_1) && is_connected_1) { | 1326 | if (!IsControllerSupported(type_index_1) && is_connected_1) { |
| 1376 | return false; | 1327 | return NpadNotConnected; |
| 1377 | } | 1328 | } |
| 1378 | if (!IsControllerSupported(type_index_2) && is_connected_2) { | 1329 | if (!IsControllerSupported(type_index_2) && is_connected_2) { |
| 1379 | return false; | 1330 | return NpadNotConnected; |
| 1380 | } | 1331 | } |
| 1381 | 1332 | ||
| 1382 | UpdateControllerAt(type_index_2, npad_id_1, is_connected_2); | 1333 | UpdateControllerAt(type_index_2, npad_id_1, is_connected_2); |
| 1383 | UpdateControllerAt(type_index_1, npad_id_2, is_connected_1); | 1334 | UpdateControllerAt(type_index_1, npad_id_2, is_connected_1); |
| 1384 | 1335 | ||
| 1385 | return true; | 1336 | return ResultSuccess; |
| 1386 | } | 1337 | } |
| 1387 | 1338 | ||
| 1388 | Core::HID::LedPattern Controller_NPad::GetLedPattern(Core::HID::NpadIdType npad_id) { | 1339 | ResultCode Controller_NPad::GetLedPattern(Core::HID::NpadIdType npad_id, |
| 1340 | Core::HID::LedPattern& pattern) const { | ||
| 1389 | if (!IsNpadIdValid(npad_id)) { | 1341 | if (!IsNpadIdValid(npad_id)) { |
| 1390 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 1342 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 1391 | return Core::HID::LedPattern{0, 0, 0, 0}; | 1343 | return InvalidNpadId; |
| 1392 | } | 1344 | } |
| 1393 | const auto& controller = GetControllerFromNpadIdType(npad_id).device; | 1345 | const auto& controller = GetControllerFromNpadIdType(npad_id).device; |
| 1394 | return controller->GetLedPattern(); | 1346 | pattern = controller->GetLedPattern(); |
| 1347 | return ResultSuccess; | ||
| 1395 | } | 1348 | } |
| 1396 | 1349 | ||
| 1397 | bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled( | 1350 | ResultCode Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled( |
| 1398 | Core::HID::NpadIdType npad_id) const { | 1351 | Core::HID::NpadIdType npad_id, bool& is_valid) const { |
| 1399 | if (!IsNpadIdValid(npad_id)) { | 1352 | if (!IsNpadIdValid(npad_id)) { |
| 1400 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 1353 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 1401 | // Return the default value | 1354 | return InvalidNpadId; |
| 1402 | return false; | ||
| 1403 | } | 1355 | } |
| 1404 | const auto& controller = GetControllerFromNpadIdType(npad_id); | 1356 | const auto& controller = GetControllerFromNpadIdType(npad_id); |
| 1405 | return controller.unintended_home_button_input_protection; | 1357 | is_valid = controller.unintended_home_button_input_protection; |
| 1358 | return ResultSuccess; | ||
| 1406 | } | 1359 | } |
| 1407 | 1360 | ||
| 1408 | void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, | 1361 | ResultCode Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled( |
| 1409 | Core::HID::NpadIdType npad_id) { | 1362 | bool is_protection_enabled, Core::HID::NpadIdType npad_id) { |
| 1410 | if (!IsNpadIdValid(npad_id)) { | 1363 | if (!IsNpadIdValid(npad_id)) { |
| 1411 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 1364 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 1412 | return; | 1365 | return InvalidNpadId; |
| 1413 | } | 1366 | } |
| 1414 | auto& controller = GetControllerFromNpadIdType(npad_id); | 1367 | auto& controller = GetControllerFromNpadIdType(npad_id); |
| 1415 | controller.unintended_home_button_input_protection = is_protection_enabled; | 1368 | controller.unintended_home_button_input_protection = is_protection_enabled; |
| 1369 | return ResultSuccess; | ||
| 1416 | } | 1370 | } |
| 1417 | 1371 | ||
| 1418 | void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { | 1372 | void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { |
| @@ -1550,4 +1504,96 @@ const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpa | |||
| 1550 | return controller_data[npad_index]; | 1504 | return controller_data[npad_index]; |
| 1551 | } | 1505 | } |
| 1552 | 1506 | ||
| 1507 | Core::HID::SixAxisSensorProperties& Controller_NPad::GetSixaxisProperties( | ||
| 1508 | const Core::HID::SixAxisSensorHandle& sixaxis_handle) { | ||
| 1509 | auto& controller = GetControllerFromHandle(sixaxis_handle); | ||
| 1510 | switch (sixaxis_handle.npad_type) { | ||
| 1511 | case Core::HID::NpadStyleIndex::ProController: | ||
| 1512 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 1513 | return controller.shared_memory->sixaxis_fullkey_properties; | ||
| 1514 | case Core::HID::NpadStyleIndex::Handheld: | ||
| 1515 | return controller.shared_memory->sixaxis_handheld_properties; | ||
| 1516 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 1517 | if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { | ||
| 1518 | return controller.shared_memory->sixaxis_dual_left_properties; | ||
| 1519 | } | ||
| 1520 | return controller.shared_memory->sixaxis_dual_right_properties; | ||
| 1521 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 1522 | return controller.shared_memory->sixaxis_left_properties; | ||
| 1523 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 1524 | return controller.shared_memory->sixaxis_right_properties; | ||
| 1525 | default: | ||
| 1526 | return controller.shared_memory->sixaxis_fullkey_properties; | ||
| 1527 | } | ||
| 1528 | } | ||
| 1529 | |||
| 1530 | const Core::HID::SixAxisSensorProperties& Controller_NPad::GetSixaxisProperties( | ||
| 1531 | const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { | ||
| 1532 | const auto& controller = GetControllerFromHandle(sixaxis_handle); | ||
| 1533 | switch (sixaxis_handle.npad_type) { | ||
| 1534 | case Core::HID::NpadStyleIndex::ProController: | ||
| 1535 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 1536 | return controller.shared_memory->sixaxis_fullkey_properties; | ||
| 1537 | case Core::HID::NpadStyleIndex::Handheld: | ||
| 1538 | return controller.shared_memory->sixaxis_handheld_properties; | ||
| 1539 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 1540 | if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { | ||
| 1541 | return controller.shared_memory->sixaxis_dual_left_properties; | ||
| 1542 | } | ||
| 1543 | return controller.shared_memory->sixaxis_dual_right_properties; | ||
| 1544 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 1545 | return controller.shared_memory->sixaxis_left_properties; | ||
| 1546 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 1547 | return controller.shared_memory->sixaxis_right_properties; | ||
| 1548 | default: | ||
| 1549 | return controller.shared_memory->sixaxis_fullkey_properties; | ||
| 1550 | } | ||
| 1551 | } | ||
| 1552 | |||
| 1553 | Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState( | ||
| 1554 | const Core::HID::SixAxisSensorHandle& sixaxis_handle) { | ||
| 1555 | auto& controller = GetControllerFromHandle(sixaxis_handle); | ||
| 1556 | switch (sixaxis_handle.npad_type) { | ||
| 1557 | case Core::HID::NpadStyleIndex::ProController: | ||
| 1558 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 1559 | return controller.sixaxis_fullkey; | ||
| 1560 | case Core::HID::NpadStyleIndex::Handheld: | ||
| 1561 | return controller.sixaxis_handheld; | ||
| 1562 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 1563 | if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { | ||
| 1564 | return controller.sixaxis_dual_left; | ||
| 1565 | } | ||
| 1566 | return controller.sixaxis_dual_right; | ||
| 1567 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 1568 | return controller.sixaxis_left; | ||
| 1569 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 1570 | return controller.sixaxis_right; | ||
| 1571 | default: | ||
| 1572 | return controller.sixaxis_unknown; | ||
| 1573 | } | ||
| 1574 | } | ||
| 1575 | |||
| 1576 | const Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState( | ||
| 1577 | const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { | ||
| 1578 | const auto& controller = GetControllerFromHandle(sixaxis_handle); | ||
| 1579 | switch (sixaxis_handle.npad_type) { | ||
| 1580 | case Core::HID::NpadStyleIndex::ProController: | ||
| 1581 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 1582 | return controller.sixaxis_fullkey; | ||
| 1583 | case Core::HID::NpadStyleIndex::Handheld: | ||
| 1584 | return controller.sixaxis_handheld; | ||
| 1585 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 1586 | if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { | ||
| 1587 | return controller.sixaxis_dual_left; | ||
| 1588 | } | ||
| 1589 | return controller.sixaxis_dual_right; | ||
| 1590 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 1591 | return controller.sixaxis_left; | ||
| 1592 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 1593 | return controller.sixaxis_right; | ||
| 1594 | default: | ||
| 1595 | return controller.sixaxis_unknown; | ||
| 1596 | } | ||
| 1597 | } | ||
| 1598 | |||
| 1553 | } // namespace Service::HID | 1599 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 0a96825a5..0b662b7f8 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -107,8 +107,8 @@ public: | |||
| 107 | void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); | 107 | void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); |
| 108 | NpadCommunicationMode GetNpadCommunicationMode() const; | 108 | NpadCommunicationMode GetNpadCommunicationMode() const; |
| 109 | 109 | ||
| 110 | void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type, | 110 | ResultCode SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type, |
| 111 | NpadJoyAssignmentMode assignment_mode); | 111 | NpadJoyAssignmentMode assignment_mode); |
| 112 | 112 | ||
| 113 | bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, | 113 | bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, |
| 114 | const Core::HID::VibrationValue& vibration_value); | 114 | const Core::HID::VibrationValue& vibration_value); |
| @@ -141,50 +141,65 @@ public: | |||
| 141 | void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id, | 141 | void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id, |
| 142 | bool connected); | 142 | bool connected); |
| 143 | 143 | ||
| 144 | void DisconnectNpad(Core::HID::NpadIdType npad_id); | 144 | ResultCode DisconnectNpad(Core::HID::NpadIdType npad_id); |
| 145 | 145 | ||
| 146 | ResultCode SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, | 146 | ResultCode SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 147 | GyroscopeZeroDriftMode drift_mode); | 147 | GyroscopeZeroDriftMode drift_mode); |
| 148 | ResultCode GetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, | 148 | ResultCode GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 149 | GyroscopeZeroDriftMode& drift_mode) const; | 149 | GyroscopeZeroDriftMode& drift_mode) const; |
| 150 | ResultCode IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle, | 150 | ResultCode IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 151 | bool& is_at_rest) const; | 151 | bool& is_at_rest) const; |
| 152 | ResultCode IsFirmwareUpdateAvailableForSixAxisSensor( | 152 | ResultCode IsFirmwareUpdateAvailableForSixAxisSensor( |
| 153 | Core::HID::SixAxisSensorHandle sixaxis_handle, bool& is_firmware_available) const; | 153 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const; |
| 154 | ResultCode SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, | 154 | ResultCode EnableSixAxisSensorUnalteredPassthrough( |
| 155 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled); | ||
| 156 | ResultCode IsSixAxisSensorUnalteredPassthroughEnabled( | ||
| 157 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const; | ||
| 158 | ResultCode LoadSixAxisSensorCalibrationParameter( | ||
| 159 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, | ||
| 160 | Core::HID::SixAxisSensorCalibrationParameter& calibration) const; | ||
| 161 | ResultCode GetSixAxisSensorIcInformation( | ||
| 162 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, | ||
| 163 | Core::HID::SixAxisSensorIcInformation& ic_information) const; | ||
| 164 | ResultCode ResetIsSixAxisSensorDeviceNewlyAssigned( | ||
| 165 | const Core::HID::SixAxisSensorHandle& sixaxis_handle); | ||
| 166 | ResultCode SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, | ||
| 155 | bool sixaxis_status); | 167 | bool sixaxis_status); |
| 156 | ResultCode IsSixAxisSensorFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, | 168 | ResultCode IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 157 | bool& is_fusion_enabled) const; | 169 | bool& is_fusion_enabled) const; |
| 158 | ResultCode SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, | 170 | ResultCode SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 159 | bool is_fusion_enabled); | 171 | bool is_fusion_enabled); |
| 160 | ResultCode SetSixAxisFusionParameters( | 172 | ResultCode SetSixAxisFusionParameters( |
| 161 | Core::HID::SixAxisSensorHandle sixaxis_handle, | 173 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 162 | Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters); | 174 | Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters); |
| 163 | ResultCode GetSixAxisFusionParameters( | 175 | ResultCode GetSixAxisFusionParameters( |
| 164 | Core::HID::SixAxisSensorHandle sixaxis_handle, | 176 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 165 | Core::HID::SixAxisSensorFusionParameters& parameters) const; | 177 | Core::HID::SixAxisSensorFusionParameters& parameters) const; |
| 166 | Core::HID::LedPattern GetLedPattern(Core::HID::NpadIdType npad_id); | 178 | ResultCode GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const; |
| 167 | bool IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id) const; | 179 | ResultCode IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, |
| 168 | void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, | 180 | bool& is_enabled) const; |
| 169 | Core::HID::NpadIdType npad_id); | 181 | ResultCode SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, |
| 182 | Core::HID::NpadIdType npad_id); | ||
| 170 | void SetAnalogStickUseCenterClamp(bool use_center_clamp); | 183 | void SetAnalogStickUseCenterClamp(bool use_center_clamp); |
| 171 | void ClearAllConnectedControllers(); | 184 | void ClearAllConnectedControllers(); |
| 172 | void DisconnectAllConnectedControllers(); | 185 | void DisconnectAllConnectedControllers(); |
| 173 | void ConnectAllDisconnectedControllers(); | 186 | void ConnectAllDisconnectedControllers(); |
| 174 | void ClearAllControllers(); | 187 | void ClearAllControllers(); |
| 175 | 188 | ||
| 176 | void MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2); | 189 | ResultCode MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, |
| 190 | Core::HID::NpadIdType npad_id_2); | ||
| 177 | void StartLRAssignmentMode(); | 191 | void StartLRAssignmentMode(); |
| 178 | void StopLRAssignmentMode(); | 192 | void StopLRAssignmentMode(); |
| 179 | bool SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2); | 193 | ResultCode SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2); |
| 180 | 194 | ||
| 181 | // Logical OR for all buttons presses on all controllers | 195 | // Logical OR for all buttons presses on all controllers |
| 182 | // Specifically for cheat engine and other features. | 196 | // Specifically for cheat engine and other features. |
| 183 | Core::HID::NpadButton GetAndResetPressState(); | 197 | Core::HID::NpadButton GetAndResetPressState(); |
| 184 | 198 | ||
| 185 | static bool IsNpadIdValid(Core::HID::NpadIdType npad_id); | 199 | static bool IsNpadIdValid(Core::HID::NpadIdType npad_id); |
| 186 | static bool IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle); | ||
| 187 | static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle); | 200 | static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle); |
| 201 | static ResultCode VerifyValidSixAxisSensorHandle( | ||
| 202 | const Core::HID::SixAxisSensorHandle& device_handle); | ||
| 188 | 203 | ||
| 189 | private: | 204 | private: |
| 190 | static constexpr std::size_t NPAD_COUNT = 10; | 205 | static constexpr std::size_t NPAD_COUNT = 10; |
| @@ -451,9 +466,13 @@ private: | |||
| 451 | NpadLuciaType lucia_type{}; | 466 | NpadLuciaType lucia_type{}; |
| 452 | NpadLagonType lagon_type{}; | 467 | NpadLagonType lagon_type{}; |
| 453 | NpadLagerType lager_type{}; | 468 | NpadLagerType lager_type{}; |
| 454 | // FW 13.x Investigate there is some sort of bitflag related to joycons | 469 | Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties; |
| 455 | INSERT_PADDING_BYTES(0x4); | 470 | Core::HID::SixAxisSensorProperties sixaxis_handheld_properties; |
| 456 | INSERT_PADDING_BYTES(0xc08); // Unknown | 471 | Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties; |
| 472 | Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties; | ||
| 473 | Core::HID::SixAxisSensorProperties sixaxis_left_properties; | ||
| 474 | Core::HID::SixAxisSensorProperties sixaxis_right_properties; | ||
| 475 | INSERT_PADDING_BYTES(0xc06); // Unknown | ||
| 457 | }; | 476 | }; |
| 458 | static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size"); | 477 | static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size"); |
| 459 | 478 | ||
| @@ -465,7 +484,10 @@ private: | |||
| 465 | 484 | ||
| 466 | struct SixaxisParameters { | 485 | struct SixaxisParameters { |
| 467 | bool is_fusion_enabled{true}; | 486 | bool is_fusion_enabled{true}; |
| 487 | bool unaltered_passtrough{false}; | ||
| 468 | Core::HID::SixAxisSensorFusionParameters fusion{}; | 488 | Core::HID::SixAxisSensorFusionParameters fusion{}; |
| 489 | Core::HID::SixAxisSensorCalibrationParameter calibration{}; | ||
| 490 | Core::HID::SixAxisSensorIcInformation ic_information{}; | ||
| 469 | GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; | 491 | GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; |
| 470 | }; | 492 | }; |
| 471 | 493 | ||
| @@ -491,6 +513,7 @@ private: | |||
| 491 | SixaxisParameters sixaxis_dual_right{}; | 513 | SixaxisParameters sixaxis_dual_right{}; |
| 492 | SixaxisParameters sixaxis_left{}; | 514 | SixaxisParameters sixaxis_left{}; |
| 493 | SixaxisParameters sixaxis_right{}; | 515 | SixaxisParameters sixaxis_right{}; |
| 516 | SixaxisParameters sixaxis_unknown{}; | ||
| 494 | 517 | ||
| 495 | // Current pad state | 518 | // Current pad state |
| 496 | NPadGenericState npad_pad_state{}; | 519 | NPadGenericState npad_pad_state{}; |
| @@ -522,6 +545,14 @@ private: | |||
| 522 | NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id); | 545 | NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id); |
| 523 | const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const; | 546 | const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const; |
| 524 | 547 | ||
| 548 | Core::HID::SixAxisSensorProperties& GetSixaxisProperties( | ||
| 549 | const Core::HID::SixAxisSensorHandle& device_handle); | ||
| 550 | const Core::HID::SixAxisSensorProperties& GetSixaxisProperties( | ||
| 551 | const Core::HID::SixAxisSensorHandle& device_handle) const; | ||
| 552 | SixaxisParameters& GetSixaxisState(const Core::HID::SixAxisSensorHandle& device_handle); | ||
| 553 | const SixaxisParameters& GetSixaxisState( | ||
| 554 | const Core::HID::SixAxisSensorHandle& device_handle) const; | ||
| 555 | |||
| 525 | std::atomic<u64> press_state{}; | 556 | std::atomic<u64> press_state{}; |
| 526 | 557 | ||
| 527 | std::array<NpadControllerData, NPAD_COUNT> controller_data{}; | 558 | std::array<NpadControllerData, NPAD_COUNT> controller_data{}; |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 108ce5a41..1da8d3eb0 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp | |||
| @@ -44,7 +44,6 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin | |||
| 44 | for (std::size_t id = 0; id < MAX_FINGERS; id++) { | 44 | for (std::size_t id = 0; id < MAX_FINGERS; id++) { |
| 45 | const auto& current_touch = touch_status[id]; | 45 | const auto& current_touch = touch_status[id]; |
| 46 | auto& finger = fingers[id]; | 46 | auto& finger = fingers[id]; |
| 47 | finger.position = current_touch.position; | ||
| 48 | finger.id = current_touch.id; | 47 | finger.id = current_touch.id; |
| 49 | 48 | ||
| 50 | if (finger.attribute.start_touch) { | 49 | if (finger.attribute.start_touch) { |
| @@ -61,13 +60,18 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin | |||
| 61 | if (!finger.pressed && current_touch.pressed) { | 60 | if (!finger.pressed && current_touch.pressed) { |
| 62 | finger.attribute.start_touch.Assign(1); | 61 | finger.attribute.start_touch.Assign(1); |
| 63 | finger.pressed = true; | 62 | finger.pressed = true; |
| 63 | finger.position = current_touch.position; | ||
| 64 | continue; | 64 | continue; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | if (finger.pressed && !current_touch.pressed) { | 67 | if (finger.pressed && !current_touch.pressed) { |
| 68 | finger.attribute.raw = 0; | 68 | finger.attribute.raw = 0; |
| 69 | finger.attribute.end_touch.Assign(1); | 69 | finger.attribute.end_touch.Assign(1); |
| 70 | continue; | ||
| 70 | } | 71 | } |
| 72 | |||
| 73 | // Only update position if touch is not on a special frame | ||
| 74 | finger.position = current_touch.position; | ||
| 71 | } | 75 | } |
| 72 | 76 | ||
| 73 | std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers; | 77 | std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers; |
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h index b31834074..6c8ad04af 100644 --- a/src/core/hle/service/hid/errors.h +++ b/src/core/hle/service/hid/errors.h | |||
| @@ -8,7 +8,11 @@ | |||
| 8 | namespace Service::HID { | 8 | namespace Service::HID { |
| 9 | 9 | ||
| 10 | constexpr ResultCode NpadInvalidHandle{ErrorModule::HID, 100}; | 10 | constexpr ResultCode NpadInvalidHandle{ErrorModule::HID, 100}; |
| 11 | constexpr ResultCode NpadDeviceIndexOutOfRange{ErrorModule::HID, 107}; | ||
| 11 | constexpr ResultCode InvalidSixAxisFusionRange{ErrorModule::HID, 423}; | 12 | constexpr ResultCode InvalidSixAxisFusionRange{ErrorModule::HID, 423}; |
| 13 | constexpr ResultCode NpadIsDualJoycon{ErrorModule::HID, 601}; | ||
| 14 | constexpr ResultCode NpadIsSameType{ErrorModule::HID, 602}; | ||
| 15 | constexpr ResultCode InvalidNpadId{ErrorModule::HID, 709}; | ||
| 12 | constexpr ResultCode NpadNotConnected{ErrorModule::HID, 710}; | 16 | constexpr ResultCode NpadNotConnected{ErrorModule::HID, 710}; |
| 13 | 17 | ||
| 14 | } // namespace Service::HID | 18 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index eba44eda8..dc5d0366d 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -37,8 +37,7 @@ namespace Service::HID { | |||
| 37 | // Period time is obtained by measuring the number of samples in a second on HW using a homebrew | 37 | // Period time is obtained by measuring the number of samples in a second on HW using a homebrew |
| 38 | constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) | 38 | constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) |
| 39 | constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) | 39 | constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) |
| 40 | // TODO: Correct update rate for motion is 5ms. Check why some games don't behave at that speed | 40 | constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) |
| 41 | constexpr auto motion_update_ns = std::chrono::nanoseconds{10 * 1000 * 1000}; // (10ms, 100Hz) | ||
| 42 | 41 | ||
| 43 | IAppletResource::IAppletResource(Core::System& system_, | 42 | IAppletResource::IAppletResource(Core::System& system_, |
| 44 | KernelHelpers::ServiceContext& service_context_) | 43 | KernelHelpers::ServiceContext& service_context_) |
| @@ -258,12 +257,12 @@ Hid::Hid(Core::System& system_) | |||
| 258 | {81, &Hid::ResetGyroscopeZeroDriftMode, "ResetGyroscopeZeroDriftMode"}, | 257 | {81, &Hid::ResetGyroscopeZeroDriftMode, "ResetGyroscopeZeroDriftMode"}, |
| 259 | {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"}, | 258 | {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"}, |
| 260 | {83, &Hid::IsFirmwareUpdateAvailableForSixAxisSensor, "IsFirmwareUpdateAvailableForSixAxisSensor"}, | 259 | {83, &Hid::IsFirmwareUpdateAvailableForSixAxisSensor, "IsFirmwareUpdateAvailableForSixAxisSensor"}, |
| 261 | {84, nullptr, "EnableSixAxisSensorUnalteredPassthrough"}, | 260 | {84, &Hid::EnableSixAxisSensorUnalteredPassthrough, "EnableSixAxisSensorUnalteredPassthrough"}, |
| 262 | {85, nullptr, "IsSixAxisSensorUnalteredPassthroughEnabled"}, | 261 | {85, &Hid::IsSixAxisSensorUnalteredPassthroughEnabled, "IsSixAxisSensorUnalteredPassthroughEnabled"}, |
| 263 | {86, nullptr, "StoreSixAxisSensorCalibrationParameter"}, | 262 | {86, nullptr, "StoreSixAxisSensorCalibrationParameter"}, |
| 264 | {87, nullptr, "LoadSixAxisSensorCalibrationParameter"}, | 263 | {87, &Hid::LoadSixAxisSensorCalibrationParameter, "LoadSixAxisSensorCalibrationParameter"}, |
| 265 | {88, nullptr, "GetSixAxisSensorIcInformation"}, | 264 | {88, &Hid::GetSixAxisSensorIcInformation, "GetSixAxisSensorIcInformation"}, |
| 266 | {89, nullptr, "ResetIsSixAxisSensorDeviceNewlyAssigned"}, | 265 | {89, &Hid::ResetIsSixAxisSensorDeviceNewlyAssigned, "ResetIsSixAxisSensorDeviceNewlyAssigned"}, |
| 267 | {91, &Hid::ActivateGesture, "ActivateGesture"}, | 266 | {91, &Hid::ActivateGesture, "ActivateGesture"}, |
| 268 | {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, | 267 | {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, |
| 269 | {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, | 268 | {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, |
| @@ -695,11 +694,7 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { | |||
| 695 | rb.Push(result1); | 694 | rb.Push(result1); |
| 696 | return; | 695 | return; |
| 697 | } | 696 | } |
| 698 | if (result2.IsError()) { | 697 | rb.Push(result2); |
| 699 | rb.Push(result2); | ||
| 700 | return; | ||
| 701 | } | ||
| 702 | rb.Push(ResultSuccess); | ||
| 703 | } | 698 | } |
| 704 | 699 | ||
| 705 | void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 700 | void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| @@ -822,6 +817,144 @@ void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& c | |||
| 822 | rb.Push(is_firmware_available); | 817 | rb.Push(is_firmware_available); |
| 823 | } | 818 | } |
| 824 | 819 | ||
| 820 | void Hid::EnableSixAxisSensorUnalteredPassthrough(Kernel::HLERequestContext& ctx) { | ||
| 821 | IPC::RequestParser rp{ctx}; | ||
| 822 | struct Parameters { | ||
| 823 | bool enabled; | ||
| 824 | Core::HID::SixAxisSensorHandle sixaxis_handle; | ||
| 825 | u64 applet_resource_user_id; | ||
| 826 | }; | ||
| 827 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 828 | |||
| 829 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 830 | |||
| 831 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | ||
| 832 | const auto result = controller.EnableSixAxisSensorUnalteredPassthrough( | ||
| 833 | parameters.sixaxis_handle, parameters.enabled); | ||
| 834 | |||
| 835 | LOG_WARNING(Service_HID, | ||
| 836 | "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, " | ||
| 837 | "applet_resource_user_id={}", | ||
| 838 | parameters.enabled, parameters.sixaxis_handle.npad_type, | ||
| 839 | parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, | ||
| 840 | parameters.applet_resource_user_id); | ||
| 841 | |||
| 842 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 843 | rb.Push(result); | ||
| 844 | } | ||
| 845 | |||
| 846 | void Hid::IsSixAxisSensorUnalteredPassthroughEnabled(Kernel::HLERequestContext& ctx) { | ||
| 847 | IPC::RequestParser rp{ctx}; | ||
| 848 | struct Parameters { | ||
| 849 | Core::HID::SixAxisSensorHandle sixaxis_handle; | ||
| 850 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 851 | u64 applet_resource_user_id; | ||
| 852 | }; | ||
| 853 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 854 | |||
| 855 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 856 | |||
| 857 | bool is_unaltered_sisxaxis_enabled{}; | ||
| 858 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | ||
| 859 | const auto result = controller.IsSixAxisSensorUnalteredPassthroughEnabled( | ||
| 860 | parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled); | ||
| 861 | |||
| 862 | LOG_WARNING( | ||
| 863 | Service_HID, | ||
| 864 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 865 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 866 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 867 | |||
| 868 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 869 | rb.Push(result); | ||
| 870 | rb.Push(is_unaltered_sisxaxis_enabled); | ||
| 871 | } | ||
| 872 | |||
| 873 | void Hid::LoadSixAxisSensorCalibrationParameter(Kernel::HLERequestContext& ctx) { | ||
| 874 | IPC::RequestParser rp{ctx}; | ||
| 875 | struct Parameters { | ||
| 876 | Core::HID::SixAxisSensorHandle sixaxis_handle; | ||
| 877 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 878 | u64 applet_resource_user_id; | ||
| 879 | }; | ||
| 880 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 881 | |||
| 882 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 883 | |||
| 884 | Core::HID::SixAxisSensorCalibrationParameter calibration{}; | ||
| 885 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | ||
| 886 | const auto result = | ||
| 887 | controller.LoadSixAxisSensorCalibrationParameter(parameters.sixaxis_handle, calibration); | ||
| 888 | |||
| 889 | LOG_WARNING( | ||
| 890 | Service_HID, | ||
| 891 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 892 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 893 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 894 | |||
| 895 | if (result.IsSuccess()) { | ||
| 896 | ctx.WriteBuffer(calibration); | ||
| 897 | } | ||
| 898 | |||
| 899 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 900 | rb.Push(result); | ||
| 901 | } | ||
| 902 | |||
| 903 | void Hid::GetSixAxisSensorIcInformation(Kernel::HLERequestContext& ctx) { | ||
| 904 | IPC::RequestParser rp{ctx}; | ||
| 905 | struct Parameters { | ||
| 906 | Core::HID::SixAxisSensorHandle sixaxis_handle; | ||
| 907 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 908 | u64 applet_resource_user_id; | ||
| 909 | }; | ||
| 910 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 911 | |||
| 912 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 913 | |||
| 914 | Core::HID::SixAxisSensorIcInformation ic_information{}; | ||
| 915 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | ||
| 916 | const auto result = | ||
| 917 | controller.GetSixAxisSensorIcInformation(parameters.sixaxis_handle, ic_information); | ||
| 918 | |||
| 919 | LOG_WARNING( | ||
| 920 | Service_HID, | ||
| 921 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 922 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 923 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 924 | |||
| 925 | if (result.IsSuccess()) { | ||
| 926 | ctx.WriteBuffer(ic_information); | ||
| 927 | } | ||
| 928 | |||
| 929 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 930 | rb.Push(result); | ||
| 931 | } | ||
| 932 | |||
| 933 | void Hid::ResetIsSixAxisSensorDeviceNewlyAssigned(Kernel::HLERequestContext& ctx) { | ||
| 934 | IPC::RequestParser rp{ctx}; | ||
| 935 | struct Parameters { | ||
| 936 | Core::HID::SixAxisSensorHandle sixaxis_handle; | ||
| 937 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 938 | u64 applet_resource_user_id; | ||
| 939 | }; | ||
| 940 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 941 | |||
| 942 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 943 | |||
| 944 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | ||
| 945 | const auto result = | ||
| 946 | controller.ResetIsSixAxisSensorDeviceNewlyAssigned(parameters.sixaxis_handle); | ||
| 947 | |||
| 948 | LOG_WARNING( | ||
| 949 | Service_HID, | ||
| 950 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 951 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 952 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 953 | |||
| 954 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 955 | rb.Push(result); | ||
| 956 | } | ||
| 957 | |||
| 825 | void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { | 958 | void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { |
| 826 | IPC::RequestParser rp{ctx}; | 959 | IPC::RequestParser rp{ctx}; |
| 827 | struct Parameters { | 960 | struct Parameters { |
| @@ -949,27 +1082,29 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { | |||
| 949 | 1082 | ||
| 950 | const auto parameters{rp.PopRaw<Parameters>()}; | 1083 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 951 | 1084 | ||
| 952 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1085 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| 953 | .DisconnectNpad(parameters.npad_id); | 1086 | const auto result = controller.DisconnectNpad(parameters.npad_id); |
| 954 | 1087 | ||
| 955 | LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, | 1088 | LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, |
| 956 | parameters.applet_resource_user_id); | 1089 | parameters.applet_resource_user_id); |
| 957 | 1090 | ||
| 958 | IPC::ResponseBuilder rb{ctx, 2}; | 1091 | IPC::ResponseBuilder rb{ctx, 2}; |
| 959 | rb.Push(ResultSuccess); | 1092 | rb.Push(result); |
| 960 | } | 1093 | } |
| 961 | 1094 | ||
| 962 | void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { | 1095 | void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { |
| 963 | IPC::RequestParser rp{ctx}; | 1096 | IPC::RequestParser rp{ctx}; |
| 964 | const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()}; | 1097 | const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()}; |
| 965 | 1098 | ||
| 1099 | Core::HID::LedPattern pattern{0, 0, 0, 0}; | ||
| 1100 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | ||
| 1101 | const auto result = controller.GetLedPattern(npad_id, pattern); | ||
| 1102 | |||
| 966 | LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); | 1103 | LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); |
| 967 | 1104 | ||
| 968 | IPC::ResponseBuilder rb{ctx, 4}; | 1105 | IPC::ResponseBuilder rb{ctx, 4}; |
| 969 | rb.Push(ResultSuccess); | 1106 | rb.Push(result); |
| 970 | rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1107 | rb.Push(pattern.raw); |
| 971 | .GetLedPattern(npad_id) | ||
| 972 | .raw); | ||
| 973 | } | 1108 | } |
| 974 | 1109 | ||
| 975 | void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { | 1110 | void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { |
| @@ -1029,15 +1164,16 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx | |||
| 1029 | 1164 | ||
| 1030 | const auto parameters{rp.PopRaw<Parameters>()}; | 1165 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1031 | 1166 | ||
| 1032 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1167 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| 1033 | .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left, | 1168 | const auto result = |
| 1034 | Controller_NPad::NpadJoyAssignmentMode::Single); | 1169 | controller.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left, |
| 1170 | Controller_NPad::NpadJoyAssignmentMode::Single); | ||
| 1035 | 1171 | ||
| 1036 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, | 1172 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, |
| 1037 | parameters.applet_resource_user_id); | 1173 | parameters.applet_resource_user_id); |
| 1038 | 1174 | ||
| 1039 | IPC::ResponseBuilder rb{ctx, 2}; | 1175 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1040 | rb.Push(ResultSuccess); | 1176 | rb.Push(result); |
| 1041 | } | 1177 | } |
| 1042 | 1178 | ||
| 1043 | void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { | 1179 | void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { |
| @@ -1052,16 +1188,16 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { | |||
| 1052 | 1188 | ||
| 1053 | const auto parameters{rp.PopRaw<Parameters>()}; | 1189 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1054 | 1190 | ||
| 1055 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1191 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| 1056 | .SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type, | 1192 | const auto result = controller.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type, |
| 1057 | Controller_NPad::NpadJoyAssignmentMode::Single); | 1193 | Controller_NPad::NpadJoyAssignmentMode::Single); |
| 1058 | 1194 | ||
| 1059 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", | 1195 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", |
| 1060 | parameters.npad_id, parameters.applet_resource_user_id, | 1196 | parameters.npad_id, parameters.applet_resource_user_id, |
| 1061 | parameters.npad_joy_device_type); | 1197 | parameters.npad_joy_device_type); |
| 1062 | 1198 | ||
| 1063 | IPC::ResponseBuilder rb{ctx, 2}; | 1199 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1064 | rb.Push(ResultSuccess); | 1200 | rb.Push(result); |
| 1065 | } | 1201 | } |
| 1066 | 1202 | ||
| 1067 | void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { | 1203 | void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { |
| @@ -1075,14 +1211,15 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { | |||
| 1075 | 1211 | ||
| 1076 | const auto parameters{rp.PopRaw<Parameters>()}; | 1212 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1077 | 1213 | ||
| 1078 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1214 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| 1079 | .SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual); | 1215 | const auto result = controller.SetNpadMode(parameters.npad_id, {}, |
| 1216 | Controller_NPad::NpadJoyAssignmentMode::Dual); | ||
| 1080 | 1217 | ||
| 1081 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, | 1218 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, |
| 1082 | parameters.applet_resource_user_id); | 1219 | parameters.applet_resource_user_id); |
| 1083 | 1220 | ||
| 1084 | IPC::ResponseBuilder rb{ctx, 2}; | 1221 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1085 | rb.Push(ResultSuccess); | 1222 | rb.Push(result); |
| 1086 | } | 1223 | } |
| 1087 | 1224 | ||
| 1088 | void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { | 1225 | void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { |
| @@ -1091,14 +1228,14 @@ void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { | |||
| 1091 | const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; | 1228 | const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; |
| 1092 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1229 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 1093 | 1230 | ||
| 1094 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1231 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| 1095 | .MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2); | 1232 | const auto result = controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2); |
| 1096 | 1233 | ||
| 1097 | LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", | 1234 | LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", |
| 1098 | npad_id_1, npad_id_2, applet_resource_user_id); | 1235 | npad_id_1, npad_id_2, applet_resource_user_id); |
| 1099 | 1236 | ||
| 1100 | IPC::ResponseBuilder rb{ctx, 2}; | 1237 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1101 | rb.Push(ResultSuccess); | 1238 | rb.Push(result); |
| 1102 | } | 1239 | } |
| 1103 | 1240 | ||
| 1104 | void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) { | 1241 | void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) { |
| @@ -1158,19 +1295,14 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { | |||
| 1158 | const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; | 1295 | const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; |
| 1159 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1296 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 1160 | 1297 | ||
| 1161 | const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1298 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| 1162 | .SwapNpadAssignment(npad_id_1, npad_id_2); | 1299 | const auto result = controller.SwapNpadAssignment(npad_id_1, npad_id_2); |
| 1163 | 1300 | ||
| 1164 | LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", | 1301 | LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", |
| 1165 | npad_id_1, npad_id_2, applet_resource_user_id); | 1302 | npad_id_1, npad_id_2, applet_resource_user_id); |
| 1166 | 1303 | ||
| 1167 | IPC::ResponseBuilder rb{ctx, 2}; | 1304 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1168 | if (res) { | 1305 | rb.Push(result); |
| 1169 | rb.Push(ResultSuccess); | ||
| 1170 | } else { | ||
| 1171 | LOG_ERROR(Service_HID, "Npads are not connected!"); | ||
| 1172 | rb.Push(NpadNotConnected); | ||
| 1173 | } | ||
| 1174 | } | 1306 | } |
| 1175 | 1307 | ||
| 1176 | void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) { | 1308 | void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) { |
| @@ -1184,13 +1316,17 @@ void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext | |||
| 1184 | 1316 | ||
| 1185 | const auto parameters{rp.PopRaw<Parameters>()}; | 1317 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1186 | 1318 | ||
| 1319 | bool is_enabled = false; | ||
| 1320 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | ||
| 1321 | const auto result = | ||
| 1322 | controller.IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id, is_enabled); | ||
| 1323 | |||
| 1187 | LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", | 1324 | LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", |
| 1188 | parameters.npad_id, parameters.applet_resource_user_id); | 1325 | parameters.npad_id, parameters.applet_resource_user_id); |
| 1189 | 1326 | ||
| 1190 | IPC::ResponseBuilder rb{ctx, 3}; | 1327 | IPC::ResponseBuilder rb{ctx, 3}; |
| 1191 | rb.Push(ResultSuccess); | 1328 | rb.Push(result); |
| 1192 | rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1329 | rb.Push(is_enabled); |
| 1193 | .IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id)); | ||
| 1194 | } | 1330 | } |
| 1195 | 1331 | ||
| 1196 | void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) { | 1332 | void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) { |
| @@ -1205,9 +1341,9 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c | |||
| 1205 | 1341 | ||
| 1206 | const auto parameters{rp.PopRaw<Parameters>()}; | 1342 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1207 | 1343 | ||
| 1208 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1344 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| 1209 | .SetUnintendedHomeButtonInputProtectionEnabled( | 1345 | const auto result = controller.SetUnintendedHomeButtonInputProtectionEnabled( |
| 1210 | parameters.unintended_home_button_input_protection, parameters.npad_id); | 1346 | parameters.unintended_home_button_input_protection, parameters.npad_id); |
| 1211 | 1347 | ||
| 1212 | LOG_WARNING(Service_HID, | 1348 | LOG_WARNING(Service_HID, |
| 1213 | "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={}," | 1349 | "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={}," |
| @@ -1216,7 +1352,7 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c | |||
| 1216 | parameters.applet_resource_user_id); | 1352 | parameters.applet_resource_user_id); |
| 1217 | 1353 | ||
| 1218 | IPC::ResponseBuilder rb{ctx, 2}; | 1354 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1219 | rb.Push(ResultSuccess); | 1355 | rb.Push(result); |
| 1220 | } | 1356 | } |
| 1221 | 1357 | ||
| 1222 | void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) { | 1358 | void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) { |
| @@ -1305,7 +1441,7 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { | |||
| 1305 | break; | 1441 | break; |
| 1306 | case Core::HID::DeviceIndex::None: | 1442 | case Core::HID::DeviceIndex::None: |
| 1307 | default: | 1443 | default: |
| 1308 | UNREACHABLE_MSG("DeviceIndex should never be None!"); | 1444 | ASSERT_MSG(false, "DeviceIndex should never be None!"); |
| 1309 | vibration_device_info.position = Core::HID::VibrationDevicePosition::None; | 1445 | vibration_device_info.position = Core::HID::VibrationDevicePosition::None; |
| 1310 | break; | 1446 | break; |
| 1311 | } | 1447 | } |
| @@ -1378,6 +1514,8 @@ void Hid::PermitVibration(Kernel::HLERequestContext& ctx) { | |||
| 1378 | IPC::RequestParser rp{ctx}; | 1514 | IPC::RequestParser rp{ctx}; |
| 1379 | const auto can_vibrate{rp.Pop<bool>()}; | 1515 | const auto can_vibrate{rp.Pop<bool>()}; |
| 1380 | 1516 | ||
| 1517 | // nnSDK saves this value as a float. Since it can only be 1.0f or 0.0f we simplify this value | ||
| 1518 | // by converting it to a bool | ||
| 1381 | Settings::values.vibration_enabled.SetValue(can_vibrate); | 1519 | Settings::values.vibration_enabled.SetValue(can_vibrate); |
| 1382 | 1520 | ||
| 1383 | LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate); | 1521 | LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate); |
| @@ -1389,9 +1527,12 @@ void Hid::PermitVibration(Kernel::HLERequestContext& ctx) { | |||
| 1389 | void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) { | 1527 | void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) { |
| 1390 | LOG_DEBUG(Service_HID, "called"); | 1528 | LOG_DEBUG(Service_HID, "called"); |
| 1391 | 1529 | ||
| 1530 | // nnSDK checks if a float is greater than zero. We return the bool we stored earlier | ||
| 1531 | const auto is_enabled = Settings::values.vibration_enabled.GetValue(); | ||
| 1532 | |||
| 1392 | IPC::ResponseBuilder rb{ctx, 3}; | 1533 | IPC::ResponseBuilder rb{ctx, 3}; |
| 1393 | rb.Push(ResultSuccess); | 1534 | rb.Push(ResultSuccess); |
| 1394 | rb.Push(Settings::values.vibration_enabled.GetValue()); | 1535 | rb.Push(is_enabled); |
| 1395 | } | 1536 | } |
| 1396 | 1537 | ||
| 1397 | void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { | 1538 | void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 1be04c22b..ac4333022 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -113,6 +113,11 @@ private: | |||
| 113 | void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); | 113 | void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); |
| 114 | void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx); | 114 | void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx); |
| 115 | void IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx); | 115 | void IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx); |
| 116 | void EnableSixAxisSensorUnalteredPassthrough(Kernel::HLERequestContext& ctx); | ||
| 117 | void IsSixAxisSensorUnalteredPassthroughEnabled(Kernel::HLERequestContext& ctx); | ||
| 118 | void LoadSixAxisSensorCalibrationParameter(Kernel::HLERequestContext& ctx); | ||
| 119 | void GetSixAxisSensorIcInformation(Kernel::HLERequestContext& ctx); | ||
| 120 | void ResetIsSixAxisSensorDeviceNewlyAssigned(Kernel::HLERequestContext& ctx); | ||
| 116 | void ActivateGesture(Kernel::HLERequestContext& ctx); | 121 | void ActivateGesture(Kernel::HLERequestContext& ctx); |
| 117 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); | 122 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); |
| 118 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); | 123 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 9e32f3e60..d2a91d913 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp | |||
| @@ -5,7 +5,9 @@ | |||
| 5 | #include "core/core_timing.h" | 5 | #include "core/core_timing.h" |
| 6 | #include "core/hle/ipc_helpers.h" | 6 | #include "core/hle/ipc_helpers.h" |
| 7 | #include "core/hle/kernel/k_shared_memory.h" | 7 | #include "core/hle/kernel/k_shared_memory.h" |
| 8 | #include "core/hle/kernel/k_transfer_memory.h" | ||
| 8 | #include "core/hle/kernel/kernel.h" | 9 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/hle/service/hid/errors.h" | ||
| 9 | #include "core/hle/service/hid/irs.h" | 11 | #include "core/hle/service/hid/irs.h" |
| 10 | 12 | ||
| 11 | namespace Service::HID { | 13 | namespace Service::HID { |
| @@ -38,21 +40,32 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} { | |||
| 38 | } | 40 | } |
| 39 | 41 | ||
| 40 | void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { | 42 | void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { |
| 41 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 43 | IPC::RequestParser rp{ctx}; |
| 44 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 45 | |||
| 46 | LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", | ||
| 47 | applet_resource_user_id); | ||
| 42 | 48 | ||
| 43 | IPC::ResponseBuilder rb{ctx, 2}; | 49 | IPC::ResponseBuilder rb{ctx, 2}; |
| 44 | rb.Push(ResultSuccess); | 50 | rb.Push(ResultSuccess); |
| 45 | } | 51 | } |
| 46 | 52 | ||
| 47 | void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { | 53 | void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { |
| 48 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 54 | IPC::RequestParser rp{ctx}; |
| 55 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 56 | |||
| 57 | LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", | ||
| 58 | applet_resource_user_id); | ||
| 49 | 59 | ||
| 50 | IPC::ResponseBuilder rb{ctx, 2}; | 60 | IPC::ResponseBuilder rb{ctx, 2}; |
| 51 | rb.Push(ResultSuccess); | 61 | rb.Push(ResultSuccess); |
| 52 | } | 62 | } |
| 53 | 63 | ||
| 54 | void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | 64 | void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { |
| 55 | LOG_DEBUG(Service_IRS, "called"); | 65 | IPC::RequestParser rp{ctx}; |
| 66 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 67 | |||
| 68 | LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", applet_resource_user_id); | ||
| 56 | 69 | ||
| 57 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 70 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 58 | rb.Push(ResultSuccess); | 71 | rb.Push(ResultSuccess); |
| @@ -60,35 +73,109 @@ void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | |||
| 60 | } | 73 | } |
| 61 | 74 | ||
| 62 | void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { | 75 | void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { |
| 63 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 76 | IPC::RequestParser rp{ctx}; |
| 77 | struct Parameters { | ||
| 78 | IrCameraHandle camera_handle; | ||
| 79 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 80 | u64 applet_resource_user_id; | ||
| 81 | }; | ||
| 82 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 83 | |||
| 84 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 85 | |||
| 86 | LOG_WARNING(Service_IRS, | ||
| 87 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 88 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 89 | parameters.applet_resource_user_id); | ||
| 64 | 90 | ||
| 65 | IPC::ResponseBuilder rb{ctx, 2}; | 91 | IPC::ResponseBuilder rb{ctx, 2}; |
| 66 | rb.Push(ResultSuccess); | 92 | rb.Push(ResultSuccess); |
| 67 | } | 93 | } |
| 68 | 94 | ||
| 69 | void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { | 95 | void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { |
| 70 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 96 | IPC::RequestParser rp{ctx}; |
| 97 | struct Parameters { | ||
| 98 | IrCameraHandle camera_handle; | ||
| 99 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 100 | u64 applet_resource_user_id; | ||
| 101 | PackedMomentProcessorConfig processor_config; | ||
| 102 | }; | ||
| 103 | static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size."); | ||
| 104 | |||
| 105 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 106 | |||
| 107 | LOG_WARNING(Service_IRS, | ||
| 108 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 109 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 110 | parameters.applet_resource_user_id); | ||
| 71 | 111 | ||
| 72 | IPC::ResponseBuilder rb{ctx, 2}; | 112 | IPC::ResponseBuilder rb{ctx, 2}; |
| 73 | rb.Push(ResultSuccess); | 113 | rb.Push(ResultSuccess); |
| 74 | } | 114 | } |
| 75 | 115 | ||
| 76 | void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { | 116 | void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { |
| 77 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 117 | IPC::RequestParser rp{ctx}; |
| 118 | struct Parameters { | ||
| 119 | IrCameraHandle camera_handle; | ||
| 120 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 121 | u64 applet_resource_user_id; | ||
| 122 | PackedClusteringProcessorConfig processor_config; | ||
| 123 | }; | ||
| 124 | static_assert(sizeof(Parameters) == 0x40, "Parameters has incorrect size."); | ||
| 125 | |||
| 126 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 127 | |||
| 128 | LOG_WARNING(Service_IRS, | ||
| 129 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 130 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 131 | parameters.applet_resource_user_id); | ||
| 78 | 132 | ||
| 79 | IPC::ResponseBuilder rb{ctx, 2}; | 133 | IPC::ResponseBuilder rb{ctx, 2}; |
| 80 | rb.Push(ResultSuccess); | 134 | rb.Push(ResultSuccess); |
| 81 | } | 135 | } |
| 82 | 136 | ||
| 83 | void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { | 137 | void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { |
| 84 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 138 | IPC::RequestParser rp{ctx}; |
| 139 | struct Parameters { | ||
| 140 | IrCameraHandle camera_handle; | ||
| 141 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 142 | u64 applet_resource_user_id; | ||
| 143 | PackedImageTransferProcessorConfig processor_config; | ||
| 144 | u32 transfer_memory_size; | ||
| 145 | }; | ||
| 146 | static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size."); | ||
| 147 | |||
| 148 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 149 | const auto t_mem_handle{ctx.GetCopyHandle(0)}; | ||
| 150 | |||
| 151 | auto t_mem = | ||
| 152 | system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle); | ||
| 153 | |||
| 154 | LOG_WARNING(Service_IRS, | ||
| 155 | "(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, " | ||
| 156 | "applet_resource_user_id={}", | ||
| 157 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 158 | parameters.transfer_memory_size, parameters.applet_resource_user_id); | ||
| 85 | 159 | ||
| 86 | IPC::ResponseBuilder rb{ctx, 2}; | 160 | IPC::ResponseBuilder rb{ctx, 2}; |
| 87 | rb.Push(ResultSuccess); | 161 | rb.Push(ResultSuccess); |
| 88 | } | 162 | } |
| 89 | 163 | ||
| 90 | void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { | 164 | void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { |
| 91 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 165 | IPC::RequestParser rp{ctx}; |
| 166 | struct Parameters { | ||
| 167 | IrCameraHandle camera_handle; | ||
| 168 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 169 | u64 applet_resource_user_id; | ||
| 170 | }; | ||
| 171 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 172 | |||
| 173 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 174 | |||
| 175 | LOG_WARNING(Service_IRS, | ||
| 176 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 177 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 178 | parameters.applet_resource_user_id); | ||
| 92 | 179 | ||
| 93 | IPC::ResponseBuilder rb{ctx, 5}; | 180 | IPC::ResponseBuilder rb{ctx, 5}; |
| 94 | rb.Push(ResultSuccess); | 181 | rb.Push(ResultSuccess); |
| @@ -97,71 +184,195 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { | |||
| 97 | } | 184 | } |
| 98 | 185 | ||
| 99 | void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { | 186 | void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { |
| 100 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 187 | IPC::RequestParser rp{ctx}; |
| 188 | const auto camera_handle{rp.PopRaw<IrCameraHandle>()}; | ||
| 189 | const auto processor_config{rp.PopRaw<PackedTeraPluginProcessorConfig>()}; | ||
| 190 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 191 | |||
| 192 | LOG_WARNING(Service_IRS, | ||
| 193 | "(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, " | ||
| 194 | "applet_resource_user_id={}", | ||
| 195 | camera_handle.npad_type, camera_handle.npad_id, processor_config.mode, | ||
| 196 | processor_config.required_mcu_version.major, | ||
| 197 | processor_config.required_mcu_version.minor, applet_resource_user_id); | ||
| 101 | 198 | ||
| 102 | IPC::ResponseBuilder rb{ctx, 2}; | 199 | IPC::ResponseBuilder rb{ctx, 2}; |
| 103 | rb.Push(ResultSuccess); | 200 | rb.Push(ResultSuccess); |
| 104 | } | 201 | } |
| 105 | 202 | ||
| 106 | void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { | 203 | void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { |
| 107 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 204 | IPC::RequestParser rp{ctx}; |
| 205 | const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()}; | ||
| 206 | |||
| 207 | if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid && | ||
| 208 | npad_id != Core::HID::NpadIdType::Handheld) { | ||
| 209 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 210 | rb.Push(InvalidNpadId); | ||
| 211 | return; | ||
| 212 | } | ||
| 213 | |||
| 214 | IrCameraHandle camera_handle{ | ||
| 215 | .npad_id = static_cast<u8>(NpadIdTypeToIndex(npad_id)), | ||
| 216 | .npad_type = Core::HID::NpadStyleIndex::None, | ||
| 217 | }; | ||
| 218 | |||
| 219 | LOG_WARNING(Service_IRS, "(STUBBED) called, npad_id={}, camera_npad_id={}, camera_npad_type={}", | ||
| 220 | npad_id, camera_handle.npad_id, camera_handle.npad_type); | ||
| 108 | 221 | ||
| 109 | IPC::ResponseBuilder rb{ctx, 3}; | 222 | IPC::ResponseBuilder rb{ctx, 3}; |
| 110 | rb.Push(ResultSuccess); | 223 | rb.Push(ResultSuccess); |
| 111 | rb.PushRaw<u32>(device_handle); | 224 | rb.PushRaw(camera_handle); |
| 112 | } | 225 | } |
| 113 | 226 | ||
| 114 | void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { | 227 | void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { |
| 115 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 228 | IPC::RequestParser rp{ctx}; |
| 229 | const auto camera_handle{rp.PopRaw<IrCameraHandle>()}; | ||
| 230 | const auto processor_config{rp.PopRaw<PackedPointingProcessorConfig>()}; | ||
| 231 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 232 | |||
| 233 | LOG_WARNING( | ||
| 234 | Service_IRS, | ||
| 235 | "(STUBBED) called, npad_type={}, npad_id={}, mcu_version={}.{}, applet_resource_user_id={}", | ||
| 236 | camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major, | ||
| 237 | processor_config.required_mcu_version.minor, applet_resource_user_id); | ||
| 116 | 238 | ||
| 117 | IPC::ResponseBuilder rb{ctx, 2}; | 239 | IPC::ResponseBuilder rb{ctx, 2}; |
| 118 | rb.Push(ResultSuccess); | 240 | rb.Push(ResultSuccess); |
| 119 | } | 241 | } |
| 120 | 242 | ||
| 121 | void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { | 243 | void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { |
| 122 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 244 | IPC::RequestParser rp{ctx}; |
| 245 | struct Parameters { | ||
| 246 | IrCameraHandle camera_handle; | ||
| 247 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 248 | u64 applet_resource_user_id; | ||
| 249 | }; | ||
| 250 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 251 | |||
| 252 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 253 | |||
| 254 | LOG_WARNING(Service_IRS, | ||
| 255 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 256 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 257 | parameters.applet_resource_user_id); | ||
| 123 | 258 | ||
| 124 | IPC::ResponseBuilder rb{ctx, 2}; | 259 | IPC::ResponseBuilder rb{ctx, 2}; |
| 125 | rb.Push(ResultSuccess); | 260 | rb.Push(ResultSuccess); |
| 126 | } | 261 | } |
| 127 | 262 | ||
| 128 | void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { | 263 | void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { |
| 129 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 264 | IPC::RequestParser rp{ctx}; |
| 265 | const auto camera_handle{rp.PopRaw<IrCameraHandle>()}; | ||
| 266 | const auto mcu_version{rp.PopRaw<PackedMcuVersion>()}; | ||
| 267 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 268 | |||
| 269 | LOG_WARNING( | ||
| 270 | Service_IRS, | ||
| 271 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}, mcu_version={}.{}", | ||
| 272 | camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major, | ||
| 273 | mcu_version.minor); | ||
| 130 | 274 | ||
| 131 | IPC::ResponseBuilder rb{ctx, 2}; | 275 | IPC::ResponseBuilder rb{ctx, 2}; |
| 132 | rb.Push(ResultSuccess); | 276 | rb.Push(ResultSuccess); |
| 133 | } | 277 | } |
| 134 | 278 | ||
| 135 | void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { | 279 | void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { |
| 136 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 280 | IPC::RequestParser rp{ctx}; |
| 281 | struct Parameters { | ||
| 282 | IrCameraHandle camera_handle; | ||
| 283 | PackedFunctionLevel function_level; | ||
| 284 | u64 applet_resource_user_id; | ||
| 285 | }; | ||
| 286 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 287 | |||
| 288 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 289 | |||
| 290 | LOG_WARNING(Service_IRS, | ||
| 291 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 292 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 293 | parameters.applet_resource_user_id); | ||
| 137 | 294 | ||
| 138 | IPC::ResponseBuilder rb{ctx, 2}; | 295 | IPC::ResponseBuilder rb{ctx, 2}; |
| 139 | rb.Push(ResultSuccess); | 296 | rb.Push(ResultSuccess); |
| 140 | } | 297 | } |
| 141 | 298 | ||
| 142 | void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { | 299 | void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { |
| 143 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 300 | IPC::RequestParser rp{ctx}; |
| 301 | struct Parameters { | ||
| 302 | IrCameraHandle camera_handle; | ||
| 303 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 304 | u64 applet_resource_user_id; | ||
| 305 | PackedImageTransferProcessorExConfig processor_config; | ||
| 306 | u64 transfer_memory_size; | ||
| 307 | }; | ||
| 308 | static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size."); | ||
| 309 | |||
| 310 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 311 | const auto t_mem_handle{ctx.GetCopyHandle(0)}; | ||
| 312 | |||
| 313 | auto t_mem = | ||
| 314 | system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle); | ||
| 315 | |||
| 316 | LOG_WARNING(Service_IRS, | ||
| 317 | "(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, " | ||
| 318 | "applet_resource_user_id={}", | ||
| 319 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 320 | parameters.transfer_memory_size, parameters.applet_resource_user_id); | ||
| 144 | 321 | ||
| 145 | IPC::ResponseBuilder rb{ctx, 2}; | 322 | IPC::ResponseBuilder rb{ctx, 2}; |
| 146 | rb.Push(ResultSuccess); | 323 | rb.Push(ResultSuccess); |
| 147 | } | 324 | } |
| 148 | 325 | ||
| 149 | void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { | 326 | void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { |
| 150 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 327 | IPC::RequestParser rp{ctx}; |
| 328 | const auto camera_handle{rp.PopRaw<IrCameraHandle>()}; | ||
| 329 | const auto processor_config{rp.PopRaw<PackedIrLedProcessorConfig>()}; | ||
| 330 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 331 | |||
| 332 | LOG_WARNING(Service_IRS, | ||
| 333 | "(STUBBED) called, npad_type={}, npad_id={}, light_target={}, mcu_version={}.{} " | ||
| 334 | "applet_resource_user_id={}", | ||
| 335 | camera_handle.npad_type, camera_handle.npad_id, processor_config.light_target, | ||
| 336 | processor_config.required_mcu_version.major, | ||
| 337 | processor_config.required_mcu_version.minor, applet_resource_user_id); | ||
| 151 | 338 | ||
| 152 | IPC::ResponseBuilder rb{ctx, 2}; | 339 | IPC::ResponseBuilder rb{ctx, 2}; |
| 153 | rb.Push(ResultSuccess); | 340 | rb.Push(ResultSuccess); |
| 154 | } | 341 | } |
| 155 | 342 | ||
| 156 | void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { | 343 | void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { |
| 157 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 344 | IPC::RequestParser rp{ctx}; |
| 345 | struct Parameters { | ||
| 346 | IrCameraHandle camera_handle; | ||
| 347 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 348 | u64 applet_resource_user_id; | ||
| 349 | }; | ||
| 350 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 351 | |||
| 352 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 353 | |||
| 354 | LOG_WARNING(Service_IRS, | ||
| 355 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 356 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 357 | parameters.applet_resource_user_id); | ||
| 158 | 358 | ||
| 159 | IPC::ResponseBuilder rb{ctx, 2}; | 359 | IPC::ResponseBuilder rb{ctx, 2}; |
| 160 | rb.Push(ResultSuccess); | 360 | rb.Push(ResultSuccess); |
| 161 | } | 361 | } |
| 162 | 362 | ||
| 163 | void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { | 363 | void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { |
| 164 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 364 | IPC::RequestParser rp{ctx}; |
| 365 | struct Parameters { | ||
| 366 | PackedFunctionLevel function_level; | ||
| 367 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 368 | u64 applet_resource_user_id; | ||
| 369 | }; | ||
| 370 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 371 | |||
| 372 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 373 | |||
| 374 | LOG_WARNING(Service_IRS, "(STUBBED) called, function_level={}, applet_resource_user_id={}", | ||
| 375 | parameters.function_level.function_level, parameters.applet_resource_user_id); | ||
| 165 | 376 | ||
| 166 | IPC::ResponseBuilder rb{ctx, 2}; | 377 | IPC::ResponseBuilder rb{ctx, 2}; |
| 167 | rb.Push(ResultSuccess); | 378 | rb.Push(ResultSuccess); |
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index efb29d3fd..361dc2213 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "core/hid/hid_types.h" | ||
| 6 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 7 | 8 | ||
| 8 | namespace Core { | 9 | namespace Core { |
| @@ -17,6 +18,235 @@ public: | |||
| 17 | ~IRS() override; | 18 | ~IRS() override; |
| 18 | 19 | ||
| 19 | private: | 20 | private: |
| 21 | // This is nn::irsensor::IrCameraStatus | ||
| 22 | enum IrCameraStatus : u32 { | ||
| 23 | Available, | ||
| 24 | Unsupported, | ||
| 25 | Unconnected, | ||
| 26 | }; | ||
| 27 | |||
| 28 | // This is nn::irsensor::IrCameraInternalStatus | ||
| 29 | enum IrCameraInternalStatus : u32 { | ||
| 30 | Stopped, | ||
| 31 | FirmwareUpdateNeeded, | ||
| 32 | Unkown2, | ||
| 33 | Unkown3, | ||
| 34 | Unkown4, | ||
| 35 | FirmwareVersionRequested, | ||
| 36 | FirmwareVersionIsInvalid, | ||
| 37 | Ready, | ||
| 38 | Setting, | ||
| 39 | }; | ||
| 40 | |||
| 41 | // This is nn::irsensor::detail::StatusManager::IrSensorMode | ||
| 42 | enum IrSensorMode : u64 { | ||
| 43 | None, | ||
| 44 | MomentProcessor, | ||
| 45 | ClusteringProcessor, | ||
| 46 | ImageTransferProcessor, | ||
| 47 | PointingProcessorMarker, | ||
| 48 | TeraPluginProcessor, | ||
| 49 | IrLedProcessor, | ||
| 50 | }; | ||
| 51 | |||
| 52 | // This is nn::irsensor::ImageProcessorStatus | ||
| 53 | enum ImageProcessorStatus : u8 { | ||
| 54 | stopped, | ||
| 55 | running, | ||
| 56 | }; | ||
| 57 | |||
| 58 | // This is nn::irsensor::ImageTransferProcessorFormat | ||
| 59 | enum ImageTransferProcessorFormat : u8 { | ||
| 60 | Size320x240, | ||
| 61 | Size160x120, | ||
| 62 | Size80x60, | ||
| 63 | Size40x30, | ||
| 64 | Size20x15, | ||
| 65 | }; | ||
| 66 | |||
| 67 | // This is nn::irsensor::AdaptiveClusteringMode | ||
| 68 | enum AdaptiveClusteringMode : u8 { | ||
| 69 | StaticFov, | ||
| 70 | DynamicFov, | ||
| 71 | }; | ||
| 72 | |||
| 73 | // This is nn::irsensor::AdaptiveClusteringTargetDistance | ||
| 74 | enum AdaptiveClusteringTargetDistance : u8 { | ||
| 75 | Near, | ||
| 76 | Middle, | ||
| 77 | Far, | ||
| 78 | }; | ||
| 79 | |||
| 80 | // This is nn::irsensor::IrsHandAnalysisMode | ||
| 81 | enum IrsHandAnalysisMode : u8 { | ||
| 82 | Silhouette, | ||
| 83 | Image, | ||
| 84 | SilhoueteAndImage, | ||
| 85 | SilhuetteOnly, | ||
| 86 | }; | ||
| 87 | |||
| 88 | // This is nn::irsensor::IrSensorFunctionLevel | ||
| 89 | enum IrSensorFunctionLevel : u8 { | ||
| 90 | unknown0, | ||
| 91 | unknown1, | ||
| 92 | unknown2, | ||
| 93 | unknown3, | ||
| 94 | unknown4, | ||
| 95 | }; | ||
| 96 | |||
| 97 | // This is nn::irsensor::IrCameraHandle | ||
| 98 | struct IrCameraHandle { | ||
| 99 | u8 npad_id{}; | ||
| 100 | Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None}; | ||
| 101 | INSERT_PADDING_BYTES(2); | ||
| 102 | }; | ||
| 103 | static_assert(sizeof(IrCameraHandle) == 4, "IrCameraHandle is an invalid size"); | ||
| 104 | |||
| 105 | struct IrsRect { | ||
| 106 | s16 x; | ||
| 107 | s16 y; | ||
| 108 | s16 width; | ||
| 109 | s16 height; | ||
| 110 | }; | ||
| 111 | |||
| 112 | // This is nn::irsensor::PackedMcuVersion | ||
| 113 | struct PackedMcuVersion { | ||
| 114 | u16 major; | ||
| 115 | u16 minor; | ||
| 116 | }; | ||
| 117 | static_assert(sizeof(PackedMcuVersion) == 4, "PackedMcuVersion is an invalid size"); | ||
| 118 | |||
| 119 | // This is nn::irsensor::MomentProcessorConfig | ||
| 120 | struct MomentProcessorConfig { | ||
| 121 | u64 exposire_time; | ||
| 122 | u8 light_target; | ||
| 123 | u8 gain; | ||
| 124 | u8 is_negative_used; | ||
| 125 | INSERT_PADDING_BYTES(7); | ||
| 126 | IrsRect window_of_interest; | ||
| 127 | u8 preprocess; | ||
| 128 | u8 preprocess_intensity_threshold; | ||
| 129 | INSERT_PADDING_BYTES(5); | ||
| 130 | }; | ||
| 131 | static_assert(sizeof(MomentProcessorConfig) == 0x28, | ||
| 132 | "MomentProcessorConfig is an invalid size"); | ||
| 133 | |||
| 134 | // This is nn::irsensor::PackedMomentProcessorConfig | ||
| 135 | struct PackedMomentProcessorConfig { | ||
| 136 | u64 exposire_time; | ||
| 137 | u8 light_target; | ||
| 138 | u8 gain; | ||
| 139 | u8 is_negative_used; | ||
| 140 | INSERT_PADDING_BYTES(5); | ||
| 141 | IrsRect window_of_interest; | ||
| 142 | PackedMcuVersion required_mcu_version; | ||
| 143 | u8 preprocess; | ||
| 144 | u8 preprocess_intensity_threshold; | ||
| 145 | INSERT_PADDING_BYTES(2); | ||
| 146 | }; | ||
| 147 | static_assert(sizeof(PackedMomentProcessorConfig) == 0x20, | ||
| 148 | "PackedMomentProcessorConfig is an invalid size"); | ||
| 149 | |||
| 150 | // This is nn::irsensor::ClusteringProcessorConfig | ||
| 151 | struct ClusteringProcessorConfig { | ||
| 152 | u64 exposire_time; | ||
| 153 | u32 light_target; | ||
| 154 | u32 gain; | ||
| 155 | u8 is_negative_used; | ||
| 156 | INSERT_PADDING_BYTES(7); | ||
| 157 | IrsRect window_of_interest; | ||
| 158 | u32 pixel_count_min; | ||
| 159 | u32 pixel_count_max; | ||
| 160 | u32 object_intensity_min; | ||
| 161 | u8 is_external_light_filter_enabled; | ||
| 162 | INSERT_PADDING_BYTES(3); | ||
| 163 | }; | ||
| 164 | static_assert(sizeof(ClusteringProcessorConfig) == 0x30, | ||
| 165 | "ClusteringProcessorConfig is an invalid size"); | ||
| 166 | |||
| 167 | // This is nn::irsensor::PackedClusteringProcessorConfig | ||
| 168 | struct PackedClusteringProcessorConfig { | ||
| 169 | u64 exposire_time; | ||
| 170 | u8 light_target; | ||
| 171 | u8 gain; | ||
| 172 | u8 is_negative_used; | ||
| 173 | INSERT_PADDING_BYTES(5); | ||
| 174 | IrsRect window_of_interest; | ||
| 175 | PackedMcuVersion required_mcu_version; | ||
| 176 | u32 pixel_count_min; | ||
| 177 | u32 pixel_count_max; | ||
| 178 | u32 object_intensity_min; | ||
| 179 | u8 is_external_light_filter_enabled; | ||
| 180 | INSERT_PADDING_BYTES(2); | ||
| 181 | }; | ||
| 182 | static_assert(sizeof(PackedClusteringProcessorConfig) == 0x30, | ||
| 183 | "PackedClusteringProcessorConfig is an invalid size"); | ||
| 184 | |||
| 185 | // This is nn::irsensor::PackedImageTransferProcessorConfig | ||
| 186 | struct PackedImageTransferProcessorConfig { | ||
| 187 | u64 exposire_time; | ||
| 188 | u8 light_target; | ||
| 189 | u8 gain; | ||
| 190 | u8 is_negative_used; | ||
| 191 | INSERT_PADDING_BYTES(5); | ||
| 192 | PackedMcuVersion required_mcu_version; | ||
| 193 | u8 format; | ||
| 194 | INSERT_PADDING_BYTES(3); | ||
| 195 | }; | ||
| 196 | static_assert(sizeof(PackedImageTransferProcessorConfig) == 0x18, | ||
| 197 | "PackedImageTransferProcessorConfig is an invalid size"); | ||
| 198 | |||
| 199 | // This is nn::irsensor::PackedTeraPluginProcessorConfig | ||
| 200 | struct PackedTeraPluginProcessorConfig { | ||
| 201 | PackedMcuVersion required_mcu_version; | ||
| 202 | u8 mode; | ||
| 203 | INSERT_PADDING_BYTES(3); | ||
| 204 | }; | ||
| 205 | static_assert(sizeof(PackedTeraPluginProcessorConfig) == 0x8, | ||
| 206 | "PackedTeraPluginProcessorConfig is an invalid size"); | ||
| 207 | |||
| 208 | // This is nn::irsensor::PackedPointingProcessorConfig | ||
| 209 | struct PackedPointingProcessorConfig { | ||
| 210 | IrsRect window_of_interest; | ||
| 211 | PackedMcuVersion required_mcu_version; | ||
| 212 | }; | ||
| 213 | static_assert(sizeof(PackedPointingProcessorConfig) == 0xC, | ||
| 214 | "PackedPointingProcessorConfig is an invalid size"); | ||
| 215 | |||
| 216 | // This is nn::irsensor::PackedFunctionLevel | ||
| 217 | struct PackedFunctionLevel { | ||
| 218 | IrSensorFunctionLevel function_level; | ||
| 219 | INSERT_PADDING_BYTES(3); | ||
| 220 | }; | ||
| 221 | static_assert(sizeof(PackedFunctionLevel) == 0x4, "PackedFunctionLevel is an invalid size"); | ||
| 222 | |||
| 223 | // This is nn::irsensor::PackedImageTransferProcessorExConfig | ||
| 224 | struct PackedImageTransferProcessorExConfig { | ||
| 225 | u64 exposire_time; | ||
| 226 | u8 light_target; | ||
| 227 | u8 gain; | ||
| 228 | u8 is_negative_used; | ||
| 229 | INSERT_PADDING_BYTES(5); | ||
| 230 | PackedMcuVersion required_mcu_version; | ||
| 231 | ImageTransferProcessorFormat origin_format; | ||
| 232 | ImageTransferProcessorFormat trimming_format; | ||
| 233 | u16 trimming_start_x; | ||
| 234 | u16 trimming_start_y; | ||
| 235 | u8 is_external_light_filter_enabled; | ||
| 236 | INSERT_PADDING_BYTES(3); | ||
| 237 | }; | ||
| 238 | static_assert(sizeof(PackedImageTransferProcessorExConfig) == 0x20, | ||
| 239 | "PackedImageTransferProcessorExConfig is an invalid size"); | ||
| 240 | |||
| 241 | // This is nn::irsensor::PackedIrLedProcessorConfig | ||
| 242 | struct PackedIrLedProcessorConfig { | ||
| 243 | PackedMcuVersion required_mcu_version; | ||
| 244 | u8 light_target; | ||
| 245 | INSERT_PADDING_BYTES(3); | ||
| 246 | }; | ||
| 247 | static_assert(sizeof(PackedIrLedProcessorConfig) == 0x8, | ||
| 248 | "PackedIrLedProcessorConfig is an invalid size"); | ||
| 249 | |||
| 20 | void ActivateIrsensor(Kernel::HLERequestContext& ctx); | 250 | void ActivateIrsensor(Kernel::HLERequestContext& ctx); |
| 21 | void DeactivateIrsensor(Kernel::HLERequestContext& ctx); | 251 | void DeactivateIrsensor(Kernel::HLERequestContext& ctx); |
| 22 | void GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx); | 252 | void GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx); |
| @@ -35,8 +265,6 @@ private: | |||
| 35 | void RunIrLedProcessor(Kernel::HLERequestContext& ctx); | 265 | void RunIrLedProcessor(Kernel::HLERequestContext& ctx); |
| 36 | void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); | 266 | void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); |
| 37 | void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); | 267 | void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); |
| 38 | |||
| 39 | const u32 device_handle{0xABCD}; | ||
| 40 | }; | 268 | }; |
| 41 | 269 | ||
| 42 | class IRS_SYS final : public ServiceFramework<IRS_SYS> { | 270 | class IRS_SYS final : public ServiceFramework<IRS_SYS> { |
diff --git a/src/core/hle/service/jit/jit_context.cpp b/src/core/hle/service/jit/jit_context.cpp index 19bd85b6c..4ed3f02e2 100644 --- a/src/core/hle/service/jit/jit_context.cpp +++ b/src/core/hle/service/jit/jit_context.cpp | |||
| @@ -11,10 +11,13 @@ | |||
| 11 | #include "common/alignment.h" | 11 | #include "common/alignment.h" |
| 12 | #include "common/common_funcs.h" | 12 | #include "common/common_funcs.h" |
| 13 | #include "common/div_ceil.h" | 13 | #include "common/div_ceil.h" |
| 14 | #include "common/elf.h" | ||
| 14 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 15 | #include "core/hle/service/jit/jit_context.h" | 16 | #include "core/hle/service/jit/jit_context.h" |
| 16 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 17 | 18 | ||
| 19 | using namespace Common::ELF; | ||
| 20 | |||
| 18 | namespace Service::JIT { | 21 | namespace Service::JIT { |
| 19 | 22 | ||
| 20 | constexpr std::array<u8, 8> SVC0_ARM64 = { | 23 | constexpr std::array<u8, 8> SVC0_ARM64 = { |
| @@ -26,25 +29,6 @@ constexpr std::array HELPER_FUNCTIONS{ | |||
| 26 | "_stop", "_resolve", "_panic", "memcpy", "memmove", "memset", | 29 | "_stop", "_resolve", "_panic", "memcpy", "memmove", "memset", |
| 27 | }; | 30 | }; |
| 28 | 31 | ||
| 29 | struct Elf64_Dyn { | ||
| 30 | u64 d_tag; | ||
| 31 | u64 d_un; | ||
| 32 | }; | ||
| 33 | |||
| 34 | struct Elf64_Rela { | ||
| 35 | u64 r_offset; | ||
| 36 | u64 r_info; | ||
| 37 | s64 r_addend; | ||
| 38 | }; | ||
| 39 | |||
| 40 | static constexpr u32 Elf64_RelaType(const Elf64_Rela* rela) { | ||
| 41 | return static_cast<u32>(rela->r_info); | ||
| 42 | } | ||
| 43 | |||
| 44 | constexpr int DT_RELA = 7; /* Address of Rela relocs */ | ||
| 45 | constexpr int DT_RELASZ = 8; /* Total size of Rela relocs */ | ||
| 46 | constexpr int R_AARCH64_RELATIVE = 1027; /* Adjust by program base. */ | ||
| 47 | |||
| 48 | constexpr size_t STACK_ALIGN = 16; | 32 | constexpr size_t STACK_ALIGN = 16; |
| 49 | 33 | ||
| 50 | class JITContextImpl; | 34 | class JITContextImpl; |
| @@ -206,17 +190,17 @@ public: | |||
| 206 | if (!dyn.d_tag) { | 190 | if (!dyn.d_tag) { |
| 207 | break; | 191 | break; |
| 208 | } | 192 | } |
| 209 | if (dyn.d_tag == DT_RELA) { | 193 | if (dyn.d_tag == ElfDtRela) { |
| 210 | rela_dyn = dyn.d_un; | 194 | rela_dyn = dyn.d_un.d_ptr; |
| 211 | } | 195 | } |
| 212 | if (dyn.d_tag == DT_RELASZ) { | 196 | if (dyn.d_tag == ElfDtRelasz) { |
| 213 | num_rela = dyn.d_un / sizeof(Elf64_Rela); | 197 | num_rela = dyn.d_un.d_val / sizeof(Elf64_Rela); |
| 214 | } | 198 | } |
| 215 | } | 199 | } |
| 216 | 200 | ||
| 217 | for (size_t i = 0; i < num_rela; i++) { | 201 | for (size_t i = 0; i < num_rela; i++) { |
| 218 | const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))}; | 202 | const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))}; |
| 219 | if (Elf64_RelaType(&rela) != R_AARCH64_RELATIVE) { | 203 | if (Elf64RelType(rela.r_info) != ElfAArch64Relative) { |
| 220 | continue; | 204 | continue; |
| 221 | } | 205 | } |
| 222 | const VAddr contents{callbacks->MemoryRead64(rela.r_offset)}; | 206 | const VAddr contents{callbacks->MemoryRead64(rela.r_offset)}; |
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index fa72fcba9..72e4902cb 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -347,7 +347,7 @@ public: | |||
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | if (!succeeded) { | 349 | if (!succeeded) { |
| 350 | UNREACHABLE_MSG("Out of address space!"); | 350 | ASSERT_MSG(false, "Out of address space!"); |
| 351 | return Kernel::ResultOutOfMemory; | 351 | return Kernel::ResultOutOfMemory; |
| 352 | } | 352 | } |
| 353 | 353 | ||
diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp index 4964539f9..08300a1a6 100644 --- a/src/core/hle/service/mii/mii_manager.cpp +++ b/src/core/hle/service/mii/mii_manager.cpp | |||
| @@ -290,7 +290,7 @@ MiiStoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Commo | |||
| 290 | u8 glasses_type{}; | 290 | u8 glasses_type{}; |
| 291 | while (glasses_type_start < glasses_type_info.values[glasses_type]) { | 291 | while (glasses_type_start < glasses_type_info.values[glasses_type]) { |
| 292 | if (++glasses_type >= glasses_type_info.values_count) { | 292 | if (++glasses_type >= glasses_type_info.values_count) { |
| 293 | UNREACHABLE(); | 293 | ASSERT(false); |
| 294 | break; | 294 | break; |
| 295 | } | 295 | } |
| 296 | } | 296 | } |
diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/syncpoint_manager.cpp index f77f0df27..a6fa943e8 100644 --- a/src/core/hle/service/nvdrv/syncpoint_manager.cpp +++ b/src/core/hle/service/nvdrv/syncpoint_manager.cpp | |||
| @@ -23,7 +23,7 @@ u32 SyncpointManager::AllocateSyncpoint() { | |||
| 23 | return syncpoint_id; | 23 | return syncpoint_id; |
| 24 | } | 24 | } |
| 25 | } | 25 | } |
| 26 | UNREACHABLE_MSG("No more available syncpoints!"); | 26 | ASSERT_MSG(false, "No more available syncpoints!"); |
| 27 | return {}; | 27 | return {}; |
| 28 | } | 28 | } |
| 29 | 29 | ||
diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp index d7db77aff..4b3d5efd6 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp | |||
| @@ -89,14 +89,6 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, | |||
| 89 | 89 | ||
| 90 | LOG_DEBUG(Service_NVFlinger, "acquiring slot={}", slot); | 90 | LOG_DEBUG(Service_NVFlinger, "acquiring slot={}", slot); |
| 91 | 91 | ||
| 92 | // If the front buffer is still being tracked, update its slot state | ||
| 93 | if (core->StillTracking(*front)) { | ||
| 94 | slots[slot].acquire_called = true; | ||
| 95 | slots[slot].needs_cleanup_on_release = false; | ||
| 96 | slots[slot].buffer_state = BufferState::Acquired; | ||
| 97 | slots[slot].fence = Fence::NoFence(); | ||
| 98 | } | ||
| 99 | |||
| 100 | // If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr to | 92 | // If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr to |
| 101 | // avoid unnecessarily remapping this buffer on the consumer side. | 93 | // avoid unnecessarily remapping this buffer on the consumer side. |
| 102 | if (out_buffer->acquire_called) { | 94 | if (out_buffer->acquire_called) { |
| @@ -139,26 +131,11 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc | |||
| 139 | ++current; | 131 | ++current; |
| 140 | } | 132 | } |
| 141 | 133 | ||
| 142 | if (slots[slot].buffer_state == BufferState::Acquired) { | 134 | slots[slot].buffer_state = BufferState::Free; |
| 143 | slots[slot].fence = release_fence; | ||
| 144 | slots[slot].buffer_state = BufferState::Free; | ||
| 145 | |||
| 146 | listener = core->connected_producer_listener; | ||
| 147 | |||
| 148 | LOG_DEBUG(Service_NVFlinger, "releasing slot {}", slot); | ||
| 149 | } else if (slots[slot].needs_cleanup_on_release) { | ||
| 150 | LOG_DEBUG(Service_NVFlinger, "releasing a stale buffer slot {} (state = {})", slot, | ||
| 151 | slots[slot].buffer_state); | ||
| 152 | 135 | ||
| 153 | slots[slot].needs_cleanup_on_release = false; | 136 | listener = core->connected_producer_listener; |
| 154 | 137 | ||
| 155 | return Status::StaleBufferSlot; | 138 | LOG_DEBUG(Service_NVFlinger, "releasing slot {}", slot); |
| 156 | } else { | ||
| 157 | LOG_ERROR(Service_NVFlinger, "attempted to release buffer slot {} but its state was {}", | ||
| 158 | slot, slots[slot].buffer_state); | ||
| 159 | |||
| 160 | return Status::BadValue; | ||
| 161 | } | ||
| 162 | 139 | ||
| 163 | core->SignalDequeueCondition(); | 140 | core->SignalDequeueCondition(); |
| 164 | } | 141 | } |
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp index d4e8b44d0..ea4a14ea4 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp | |||
| @@ -84,10 +84,6 @@ void BufferQueueCore::FreeBufferLocked(s32 slot) { | |||
| 84 | 84 | ||
| 85 | slots[slot].graphic_buffer.reset(); | 85 | slots[slot].graphic_buffer.reset(); |
| 86 | 86 | ||
| 87 | if (slots[slot].buffer_state == BufferState::Acquired) { | ||
| 88 | slots[slot].needs_cleanup_on_release = true; | ||
| 89 | } | ||
| 90 | |||
| 91 | slots[slot].buffer_state = BufferState::Free; | 87 | slots[slot].buffer_state = BufferState::Free; |
| 92 | slots[slot].frame_number = UINT32_MAX; | 88 | slots[slot].frame_number = UINT32_MAX; |
| 93 | slots[slot].acquire_called = false; | 89 | slots[slot].acquire_called = false; |
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index fe95d1b73..337431488 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp | |||
| @@ -659,7 +659,7 @@ Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) { | |||
| 659 | value = core->consumer_usage_bit; | 659 | value = core->consumer_usage_bit; |
| 660 | break; | 660 | break; |
| 661 | default: | 661 | default: |
| 662 | UNREACHABLE(); | 662 | ASSERT(false); |
| 663 | return Status::BadValue; | 663 | return Status::BadValue; |
| 664 | } | 664 | } |
| 665 | 665 | ||
diff --git a/src/core/hle/service/nvflinger/buffer_slot.h b/src/core/hle/service/nvflinger/buffer_slot.h index 6b3e87446..0cd0e9964 100644 --- a/src/core/hle/service/nvflinger/buffer_slot.h +++ b/src/core/hle/service/nvflinger/buffer_slot.h | |||
| @@ -31,7 +31,6 @@ struct BufferSlot final { | |||
| 31 | u64 frame_number{}; | 31 | u64 frame_number{}; |
| 32 | Fence fence; | 32 | Fence fence; |
| 33 | bool acquire_called{}; | 33 | bool acquire_called{}; |
| 34 | bool needs_cleanup_on_release{}; | ||
| 35 | bool attached_by_consumer{}; | 34 | bool attached_by_consumer{}; |
| 36 | bool is_preallocated{}; | 35 | bool is_preallocated{}; |
| 37 | }; | 36 | }; |
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.cpp b/src/core/hle/service/time/standard_user_system_clock_core.cpp index f0cc9a155..508091dc2 100644 --- a/src/core/hle/service/time/standard_user_system_clock_core.cpp +++ b/src/core/hle/service/time/standard_user_system_clock_core.cpp | |||
| @@ -48,12 +48,12 @@ ResultCode StandardUserSystemClockCore::GetClockContext(Core::System& system, | |||
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | ResultCode StandardUserSystemClockCore::Flush(const SystemClockContext&) { | 50 | ResultCode StandardUserSystemClockCore::Flush(const SystemClockContext&) { |
| 51 | UNREACHABLE(); | 51 | UNIMPLEMENTED(); |
| 52 | return ERROR_NOT_IMPLEMENTED; | 52 | return ERROR_NOT_IMPLEMENTED; |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | ResultCode StandardUserSystemClockCore::SetClockContext(const SystemClockContext&) { | 55 | ResultCode StandardUserSystemClockCore::SetClockContext(const SystemClockContext&) { |
| 56 | UNREACHABLE(); | 56 | UNIMPLEMENTED(); |
| 57 | return ERROR_NOT_IMPLEMENTED; | 57 | return ERROR_NOT_IMPLEMENTED; |
| 58 | } | 58 | } |
| 59 | 59 | ||
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp index acc038dbf..28667710e 100644 --- a/src/core/hle/service/time/time_manager.cpp +++ b/src/core/hle/service/time/time_manager.cpp | |||
| @@ -111,7 +111,7 @@ struct TimeManager::Impl final { | |||
| 111 | FileSys::VirtualFile& vfs_file) { | 111 | FileSys::VirtualFile& vfs_file) { |
| 112 | if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule( | 112 | if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule( |
| 113 | location_name, vfs_file) != ResultSuccess) { | 113 | location_name, vfs_file) != ResultSuccess) { |
| 114 | UNREACHABLE(); | 114 | ASSERT(false); |
| 115 | return; | 115 | return; |
| 116 | } | 116 | } |
| 117 | 117 | ||
| @@ -155,7 +155,7 @@ struct TimeManager::Impl final { | |||
| 155 | } else { | 155 | } else { |
| 156 | if (standard_local_system_clock_core.SetCurrentTime(system_, posix_time) != | 156 | if (standard_local_system_clock_core.SetCurrentTime(system_, posix_time) != |
| 157 | ResultSuccess) { | 157 | ResultSuccess) { |
| 158 | UNREACHABLE(); | 158 | ASSERT(false); |
| 159 | return; | 159 | return; |
| 160 | } | 160 | } |
| 161 | } | 161 | } |
| @@ -170,7 +170,7 @@ struct TimeManager::Impl final { | |||
| 170 | 170 | ||
| 171 | if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != | 171 | if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != |
| 172 | ResultSuccess) { | 172 | ResultSuccess) { |
| 173 | UNREACHABLE(); | 173 | ASSERT(false); |
| 174 | return; | 174 | return; |
| 175 | } | 175 | } |
| 176 | 176 | ||
| @@ -183,7 +183,7 @@ struct TimeManager::Impl final { | |||
| 183 | Clock::SteadyClockTimePoint steady_clock_time_point) { | 183 | Clock::SteadyClockTimePoint steady_clock_time_point) { |
| 184 | if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled( | 184 | if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled( |
| 185 | system_, is_automatic_correction_enabled) != ResultSuccess) { | 185 | system_, is_automatic_correction_enabled) != ResultSuccess) { |
| 186 | UNREACHABLE(); | 186 | ASSERT(false); |
| 187 | return; | 187 | return; |
| 188 | } | 188 | } |
| 189 | 189 | ||
| @@ -203,7 +203,7 @@ struct TimeManager::Impl final { | |||
| 203 | if (GetStandardLocalSystemClockCore() | 203 | if (GetStandardLocalSystemClockCore() |
| 204 | .SetCurrentTime(system_, timespan.ToSeconds()) | 204 | .SetCurrentTime(system_, timespan.ToSeconds()) |
| 205 | .IsError()) { | 205 | .IsError()) { |
| 206 | UNREACHABLE(); | 206 | ASSERT(false); |
| 207 | return; | 207 | return; |
| 208 | } | 208 | } |
| 209 | } | 209 | } |
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 449a5ac96..fee05ec7a 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp | |||
| @@ -110,10 +110,9 @@ static constexpr s64 GetLeapDaysFromYear(s64 year) { | |||
| 110 | } | 110 | } |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | static constexpr int GetMonthLength(bool is_leap_year, int month) { | 113 | static constexpr s8 GetMonthLength(bool is_leap_year, int month) { |
| 114 | constexpr std::array<int, 12> month_lengths{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | 114 | constexpr std::array<s8, 12> month_lengths{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
| 115 | constexpr std::array<int, 12> month_lengths_leap{31, 29, 31, 30, 31, 30, | 115 | constexpr std::array<s8, 12> month_lengths_leap{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
| 116 | 31, 31, 30, 31, 30, 31}; | ||
| 117 | return is_leap_year ? month_lengths_leap[month] : month_lengths[month]; | 116 | return is_leap_year ? month_lengths_leap[month] : month_lengths[month]; |
| 118 | } | 117 | } |
| 119 | 118 | ||
| @@ -280,7 +279,7 @@ static constexpr int TransitionTime(int year, Rule rule, int offset) { | |||
| 280 | break; | 279 | break; |
| 281 | } | 280 | } |
| 282 | default: | 281 | default: |
| 283 | UNREACHABLE(); | 282 | ASSERT(false); |
| 284 | } | 283 | } |
| 285 | return value + rule.transition_time + offset; | 284 | return value + rule.transition_time + offset; |
| 286 | } | 285 | } |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index cf5933699..dfb10c34f 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include "common/common_funcs.h" | 7 | #include "common/common_funcs.h" |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "common/elf.h" | ||
| 9 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 10 | #include "core/hle/kernel/code_set.h" | 11 | #include "core/hle/kernel/code_set.h" |
| 11 | #include "core/hle/kernel/k_page_table.h" | 12 | #include "core/hle/kernel/k_page_table.h" |
| @@ -13,159 +14,7 @@ | |||
| 13 | #include "core/loader/elf.h" | 14 | #include "core/loader/elf.h" |
| 14 | #include "core/memory.h" | 15 | #include "core/memory.h" |
| 15 | 16 | ||
| 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 17 | using namespace Common::ELF; |
| 17 | // ELF Header Constants | ||
| 18 | |||
| 19 | // File type | ||
| 20 | enum ElfType { | ||
| 21 | ET_NONE = 0, | ||
| 22 | ET_REL = 1, | ||
| 23 | ET_EXEC = 2, | ||
| 24 | ET_DYN = 3, | ||
| 25 | ET_CORE = 4, | ||
| 26 | ET_LOPROC = 0xFF00, | ||
| 27 | ET_HIPROC = 0xFFFF, | ||
| 28 | }; | ||
| 29 | |||
| 30 | // Machine/Architecture | ||
| 31 | enum ElfMachine { | ||
| 32 | EM_NONE = 0, | ||
| 33 | EM_M32 = 1, | ||
| 34 | EM_SPARC = 2, | ||
| 35 | EM_386 = 3, | ||
| 36 | EM_68K = 4, | ||
| 37 | EM_88K = 5, | ||
| 38 | EM_860 = 7, | ||
| 39 | EM_MIPS = 8 | ||
| 40 | }; | ||
| 41 | |||
| 42 | // File version | ||
| 43 | #define EV_NONE 0 | ||
| 44 | #define EV_CURRENT 1 | ||
| 45 | |||
| 46 | // Identification index | ||
| 47 | #define EI_MAG0 0 | ||
| 48 | #define EI_MAG1 1 | ||
| 49 | #define EI_MAG2 2 | ||
| 50 | #define EI_MAG3 3 | ||
| 51 | #define EI_CLASS 4 | ||
| 52 | #define EI_DATA 5 | ||
| 53 | #define EI_VERSION 6 | ||
| 54 | #define EI_PAD 7 | ||
| 55 | #define EI_NIDENT 16 | ||
| 56 | |||
| 57 | // Sections constants | ||
| 58 | |||
| 59 | // Section types | ||
| 60 | #define SHT_NULL 0 | ||
| 61 | #define SHT_PROGBITS 1 | ||
| 62 | #define SHT_SYMTAB 2 | ||
| 63 | #define SHT_STRTAB 3 | ||
| 64 | #define SHT_RELA 4 | ||
| 65 | #define SHT_HASH 5 | ||
| 66 | #define SHT_DYNAMIC 6 | ||
| 67 | #define SHT_NOTE 7 | ||
| 68 | #define SHT_NOBITS 8 | ||
| 69 | #define SHT_REL 9 | ||
| 70 | #define SHT_SHLIB 10 | ||
| 71 | #define SHT_DYNSYM 11 | ||
| 72 | #define SHT_LOPROC 0x70000000 | ||
| 73 | #define SHT_HIPROC 0x7FFFFFFF | ||
| 74 | #define SHT_LOUSER 0x80000000 | ||
| 75 | #define SHT_HIUSER 0xFFFFFFFF | ||
| 76 | |||
| 77 | // Section flags | ||
| 78 | enum ElfSectionFlags { | ||
| 79 | SHF_WRITE = 0x1, | ||
| 80 | SHF_ALLOC = 0x2, | ||
| 81 | SHF_EXECINSTR = 0x4, | ||
| 82 | SHF_MASKPROC = 0xF0000000, | ||
| 83 | }; | ||
| 84 | |||
| 85 | // Segment types | ||
| 86 | #define PT_NULL 0 | ||
| 87 | #define PT_LOAD 1 | ||
| 88 | #define PT_DYNAMIC 2 | ||
| 89 | #define PT_INTERP 3 | ||
| 90 | #define PT_NOTE 4 | ||
| 91 | #define PT_SHLIB 5 | ||
| 92 | #define PT_PHDR 6 | ||
| 93 | #define PT_LOPROC 0x70000000 | ||
| 94 | #define PT_HIPROC 0x7FFFFFFF | ||
| 95 | |||
| 96 | // Segment flags | ||
| 97 | #define PF_X 0x1 | ||
| 98 | #define PF_W 0x2 | ||
| 99 | #define PF_R 0x4 | ||
| 100 | #define PF_MASKPROC 0xF0000000 | ||
| 101 | |||
| 102 | typedef unsigned int Elf32_Addr; | ||
| 103 | typedef unsigned short Elf32_Half; | ||
| 104 | typedef unsigned int Elf32_Off; | ||
| 105 | typedef signed int Elf32_Sword; | ||
| 106 | typedef unsigned int Elf32_Word; | ||
| 107 | |||
| 108 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 109 | // ELF file header | ||
| 110 | |||
| 111 | struct Elf32_Ehdr { | ||
| 112 | unsigned char e_ident[EI_NIDENT]; | ||
| 113 | Elf32_Half e_type; | ||
| 114 | Elf32_Half e_machine; | ||
| 115 | Elf32_Word e_version; | ||
| 116 | Elf32_Addr e_entry; | ||
| 117 | Elf32_Off e_phoff; | ||
| 118 | Elf32_Off e_shoff; | ||
| 119 | Elf32_Word e_flags; | ||
| 120 | Elf32_Half e_ehsize; | ||
| 121 | Elf32_Half e_phentsize; | ||
| 122 | Elf32_Half e_phnum; | ||
| 123 | Elf32_Half e_shentsize; | ||
| 124 | Elf32_Half e_shnum; | ||
| 125 | Elf32_Half e_shstrndx; | ||
| 126 | }; | ||
| 127 | |||
| 128 | // Section header | ||
| 129 | struct Elf32_Shdr { | ||
| 130 | Elf32_Word sh_name; | ||
| 131 | Elf32_Word sh_type; | ||
| 132 | Elf32_Word sh_flags; | ||
| 133 | Elf32_Addr sh_addr; | ||
| 134 | Elf32_Off sh_offset; | ||
| 135 | Elf32_Word sh_size; | ||
| 136 | Elf32_Word sh_link; | ||
| 137 | Elf32_Word sh_info; | ||
| 138 | Elf32_Word sh_addralign; | ||
| 139 | Elf32_Word sh_entsize; | ||
| 140 | }; | ||
| 141 | |||
| 142 | // Segment header | ||
| 143 | struct Elf32_Phdr { | ||
| 144 | Elf32_Word p_type; | ||
| 145 | Elf32_Off p_offset; | ||
| 146 | Elf32_Addr p_vaddr; | ||
| 147 | Elf32_Addr p_paddr; | ||
| 148 | Elf32_Word p_filesz; | ||
| 149 | Elf32_Word p_memsz; | ||
| 150 | Elf32_Word p_flags; | ||
| 151 | Elf32_Word p_align; | ||
| 152 | }; | ||
| 153 | |||
| 154 | // Symbol table entry | ||
| 155 | struct Elf32_Sym { | ||
| 156 | Elf32_Word st_name; | ||
| 157 | Elf32_Addr st_value; | ||
| 158 | Elf32_Word st_size; | ||
| 159 | unsigned char st_info; | ||
| 160 | unsigned char st_other; | ||
| 161 | Elf32_Half st_shndx; | ||
| 162 | }; | ||
| 163 | |||
| 164 | // Relocation entries | ||
| 165 | struct Elf32_Rel { | ||
| 166 | Elf32_Addr r_offset; | ||
| 167 | Elf32_Word r_info; | ||
| 168 | }; | ||
| 169 | 18 | ||
| 170 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 19 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 171 | // ElfReader class | 20 | // ElfReader class |
| @@ -193,11 +42,11 @@ public: | |||
| 193 | } | 42 | } |
| 194 | 43 | ||
| 195 | // Quick accessors | 44 | // Quick accessors |
| 196 | ElfType GetType() const { | 45 | u16 GetType() const { |
| 197 | return (ElfType)(header->e_type); | 46 | return header->e_type; |
| 198 | } | 47 | } |
| 199 | ElfMachine GetMachine() const { | 48 | u16 GetMachine() const { |
| 200 | return (ElfMachine)(header->e_machine); | 49 | return header->e_machine; |
| 201 | } | 50 | } |
| 202 | VAddr GetEntryPoint() const { | 51 | VAddr GetEntryPoint() const { |
| 203 | return entryPoint; | 52 | return entryPoint; |
| @@ -220,13 +69,13 @@ public: | |||
| 220 | const u8* GetSectionDataPtr(int section) const { | 69 | const u8* GetSectionDataPtr(int section) const { |
| 221 | if (section < 0 || section >= header->e_shnum) | 70 | if (section < 0 || section >= header->e_shnum) |
| 222 | return nullptr; | 71 | return nullptr; |
| 223 | if (sections[section].sh_type != SHT_NOBITS) | 72 | if (sections[section].sh_type != ElfShtNobits) |
| 224 | return GetPtr(sections[section].sh_offset); | 73 | return GetPtr(sections[section].sh_offset); |
| 225 | else | 74 | else |
| 226 | return nullptr; | 75 | return nullptr; |
| 227 | } | 76 | } |
| 228 | bool IsCodeSection(int section) const { | 77 | bool IsCodeSection(int section) const { |
| 229 | return sections[section].sh_type == SHT_PROGBITS; | 78 | return sections[section].sh_type == ElfShtProgBits; |
| 230 | } | 79 | } |
| 231 | const u8* GetSegmentPtr(int segment) { | 80 | const u8* GetSegmentPtr(int segment) { |
| 232 | return GetPtr(segments[segment].p_offset); | 81 | return GetPtr(segments[segment].p_offset); |
| @@ -256,7 +105,7 @@ ElfReader::ElfReader(void* ptr) { | |||
| 256 | } | 105 | } |
| 257 | 106 | ||
| 258 | const char* ElfReader::GetSectionName(int section) const { | 107 | const char* ElfReader::GetSectionName(int section) const { |
| 259 | if (sections[section].sh_type == SHT_NULL) | 108 | if (sections[section].sh_type == ElfShtNull) |
| 260 | return nullptr; | 109 | return nullptr; |
| 261 | 110 | ||
| 262 | int name_offset = sections[section].sh_name; | 111 | int name_offset = sections[section].sh_name; |
| @@ -272,7 +121,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) { | |||
| 272 | LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx); | 121 | LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx); |
| 273 | 122 | ||
| 274 | // Should we relocate? | 123 | // Should we relocate? |
| 275 | relocate = (header->e_type != ET_EXEC); | 124 | relocate = (header->e_type != ElfTypeExec); |
| 276 | 125 | ||
| 277 | if (relocate) { | 126 | if (relocate) { |
| 278 | LOG_DEBUG(Loader, "Relocatable module"); | 127 | LOG_DEBUG(Loader, "Relocatable module"); |
| @@ -288,7 +137,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) { | |||
| 288 | u64 total_image_size = 0; | 137 | u64 total_image_size = 0; |
| 289 | for (unsigned int i = 0; i < header->e_phnum; ++i) { | 138 | for (unsigned int i = 0; i < header->e_phnum; ++i) { |
| 290 | const Elf32_Phdr* p = &segments[i]; | 139 | const Elf32_Phdr* p = &segments[i]; |
| 291 | if (p->p_type == PT_LOAD) { | 140 | if (p->p_type == ElfPtLoad) { |
| 292 | total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF; | 141 | total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF; |
| 293 | } | 142 | } |
| 294 | } | 143 | } |
| @@ -303,14 +152,14 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) { | |||
| 303 | LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type, | 152 | LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type, |
| 304 | p->p_vaddr, p->p_filesz, p->p_memsz); | 153 | p->p_vaddr, p->p_filesz, p->p_memsz); |
| 305 | 154 | ||
| 306 | if (p->p_type == PT_LOAD) { | 155 | if (p->p_type == ElfPtLoad) { |
| 307 | Kernel::CodeSet::Segment* codeset_segment; | 156 | Kernel::CodeSet::Segment* codeset_segment; |
| 308 | u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X); | 157 | u32 permission_flags = p->p_flags & (ElfPfRead | ElfPfWrite | ElfPfExec); |
| 309 | if (permission_flags == (PF_R | PF_X)) { | 158 | if (permission_flags == (ElfPfRead | ElfPfExec)) { |
| 310 | codeset_segment = &codeset.CodeSegment(); | 159 | codeset_segment = &codeset.CodeSegment(); |
| 311 | } else if (permission_flags == (PF_R)) { | 160 | } else if (permission_flags == (ElfPfRead)) { |
| 312 | codeset_segment = &codeset.RODataSegment(); | 161 | codeset_segment = &codeset.RODataSegment(); |
| 313 | } else if (permission_flags == (PF_R | PF_W)) { | 162 | } else if (permission_flags == (ElfPfRead | ElfPfWrite)) { |
| 314 | codeset_segment = &codeset.DataSegment(); | 163 | codeset_segment = &codeset.DataSegment(); |
| 315 | } else { | 164 | } else { |
| 316 | LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i, | 165 | LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i, |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 8a938aa83..8dd956fc6 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -128,11 +128,10 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: | |||
| 128 | 128 | ||
| 129 | // Apply patches if necessary | 129 | // Apply patches if necessary |
| 130 | if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) { | 130 | if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) { |
| 131 | std::vector<u8> pi_header; | 131 | std::vector<u8> pi_header(sizeof(NSOHeader) + program_image.size()); |
| 132 | pi_header.insert(pi_header.begin(), reinterpret_cast<u8*>(&nso_header), | 132 | std::memcpy(pi_header.data(), &nso_header, sizeof(NSOHeader)); |
| 133 | reinterpret_cast<u8*>(&nso_header) + sizeof(NSOHeader)); | 133 | std::memcpy(pi_header.data() + sizeof(NSOHeader), program_image.data(), |
| 134 | pi_header.insert(pi_header.begin() + sizeof(NSOHeader), program_image.data(), | 134 | program_image.size()); |
| 135 | program_image.data() + program_image.size()); | ||
| 136 | 135 | ||
| 137 | pi_header = pm->PatchNSO(pi_header, nso_file.GetName()); | 136 | pi_header = pm->PatchNSO(pi_header, nso_file.GetName()); |
| 138 | 137 | ||
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 28d30eee2..7534de01e 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -594,6 +594,19 @@ bool Memory::IsValidVirtualAddress(const VAddr vaddr) const { | |||
| 594 | return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory; | 594 | return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory; |
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | bool Memory::IsValidVirtualAddressRange(VAddr base, u64 size) const { | ||
| 598 | VAddr end = base + size; | ||
| 599 | VAddr page = Common::AlignDown(base, PAGE_SIZE); | ||
| 600 | |||
| 601 | for (; page < end; page += PAGE_SIZE) { | ||
| 602 | if (!IsValidVirtualAddress(page)) { | ||
| 603 | return false; | ||
| 604 | } | ||
| 605 | } | ||
| 606 | |||
| 607 | return true; | ||
| 608 | } | ||
| 609 | |||
| 597 | u8* Memory::GetPointer(VAddr vaddr) { | 610 | u8* Memory::GetPointer(VAddr vaddr) { |
| 598 | return impl->GetPointer(vaddr); | 611 | return impl->GetPointer(vaddr); |
| 599 | } | 612 | } |
diff --git a/src/core/memory.h b/src/core/memory.h index b5721b740..58cc27b29 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -96,6 +96,17 @@ public: | |||
| 96 | [[nodiscard]] bool IsValidVirtualAddress(VAddr vaddr) const; | 96 | [[nodiscard]] bool IsValidVirtualAddress(VAddr vaddr) const; |
| 97 | 97 | ||
| 98 | /** | 98 | /** |
| 99 | * Checks whether or not the supplied range of addresses are all valid | ||
| 100 | * virtual addresses for the current process. | ||
| 101 | * | ||
| 102 | * @param base The address to begin checking. | ||
| 103 | * @param size The amount of bytes to check. | ||
| 104 | * | ||
| 105 | * @returns True if all bytes in the given range are valid, false otherwise. | ||
| 106 | */ | ||
| 107 | [[nodiscard]] bool IsValidVirtualAddressRange(VAddr base, u64 size) const; | ||
| 108 | |||
| 109 | /** | ||
| 99 | * Gets a pointer to the given address. | 110 | * Gets a pointer to the given address. |
| 100 | * | 111 | * |
| 101 | * @param vaddr Virtual address to retrieve a pointer to. | 112 | * @param vaddr Virtual address to retrieve a pointer to. |
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp index 7a0b73eca..5cc99fbe4 100644 --- a/src/core/tools/freezer.cpp +++ b/src/core/tools/freezer.cpp | |||
| @@ -25,7 +25,6 @@ u64 MemoryReadWidth(Core::Memory::Memory& memory, u32 width, VAddr addr) { | |||
| 25 | return memory.Read64(addr); | 25 | return memory.Read64(addr); |
| 26 | default: | 26 | default: |
| 27 | UNREACHABLE(); | 27 | UNREACHABLE(); |
| 28 | return 0; | ||
| 29 | } | 28 | } |
| 30 | } | 29 | } |
| 31 | 30 | ||
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index d4fa69a77..48e799cf5 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -44,7 +44,6 @@ else() | |||
| 44 | -Werror | 44 | -Werror |
| 45 | -Werror=conversion | 45 | -Werror=conversion |
| 46 | -Werror=ignored-qualifiers | 46 | -Werror=ignored-qualifiers |
| 47 | -Werror=shadow | ||
| 48 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> | 47 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> |
| 49 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> | 48 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> |
| 50 | -Werror=unused-variable | 49 | -Werror=unused-variable |
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index a5c63e74a..446c027d3 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp | |||
| @@ -13,11 +13,11 @@ | |||
| 13 | namespace InputCommon { | 13 | namespace InputCommon { |
| 14 | 14 | ||
| 15 | namespace { | 15 | namespace { |
| 16 | std::string GetGUID(SDL_Joystick* joystick) { | 16 | Common::UUID GetGUID(SDL_Joystick* joystick) { |
| 17 | const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); | 17 | const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); |
| 18 | char guid_str[33]; | 18 | std::array<u8, 16> data{}; |
| 19 | SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); | 19 | std::memcpy(data.data(), guid.data, sizeof(data)); |
| 20 | return guid_str; | 20 | return Common::UUID{data}; |
| 21 | } | 21 | } |
| 22 | } // Anonymous namespace | 22 | } // Anonymous namespace |
| 23 | 23 | ||
| @@ -31,9 +31,9 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) { | |||
| 31 | 31 | ||
| 32 | class SDLJoystick { | 32 | class SDLJoystick { |
| 33 | public: | 33 | public: |
| 34 | SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, | 34 | SDLJoystick(Common::UUID guid_, int port_, SDL_Joystick* joystick, |
| 35 | SDL_GameController* game_controller) | 35 | SDL_GameController* game_controller) |
| 36 | : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, | 36 | : guid{guid_}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, |
| 37 | sdl_controller{game_controller, &SDL_GameControllerClose} { | 37 | sdl_controller{game_controller, &SDL_GameControllerClose} { |
| 38 | EnableMotion(); | 38 | EnableMotion(); |
| 39 | } | 39 | } |
| @@ -120,7 +120,7 @@ public: | |||
| 120 | */ | 120 | */ |
| 121 | const PadIdentifier GetPadIdentifier() const { | 121 | const PadIdentifier GetPadIdentifier() const { |
| 122 | return { | 122 | return { |
| 123 | .guid = Common::UUID{guid}, | 123 | .guid = guid, |
| 124 | .port = static_cast<std::size_t>(port), | 124 | .port = static_cast<std::size_t>(port), |
| 125 | .pad = 0, | 125 | .pad = 0, |
| 126 | }; | 126 | }; |
| @@ -129,7 +129,7 @@ public: | |||
| 129 | /** | 129 | /** |
| 130 | * The guid of the joystick | 130 | * The guid of the joystick |
| 131 | */ | 131 | */ |
| 132 | const std::string& GetGUID() const { | 132 | const Common::UUID& GetGUID() const { |
| 133 | return guid; | 133 | return guid; |
| 134 | } | 134 | } |
| 135 | 135 | ||
| @@ -228,7 +228,7 @@ public: | |||
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | private: | 230 | private: |
| 231 | std::string guid; | 231 | Common::UUID guid; |
| 232 | int port; | 232 | int port; |
| 233 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; | 233 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; |
| 234 | std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; | 234 | std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; |
| @@ -240,7 +240,7 @@ private: | |||
| 240 | BasicMotion motion; | 240 | BasicMotion motion; |
| 241 | }; | 241 | }; |
| 242 | 242 | ||
| 243 | std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) { | 243 | std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const Common::UUID& guid, int port) { |
| 244 | std::scoped_lock lock{joystick_map_mutex}; | 244 | std::scoped_lock lock{joystick_map_mutex}; |
| 245 | const auto it = joystick_map.find(guid); | 245 | const auto it = joystick_map.find(guid); |
| 246 | 246 | ||
| @@ -259,9 +259,13 @@ std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string& | |||
| 259 | return joystick_map[guid].emplace_back(std::move(joystick)); | 259 | return joystick_map[guid].emplace_back(std::move(joystick)); |
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) { | ||
| 263 | return GetSDLJoystickByGUID(Common::UUID{guid}, port); | ||
| 264 | } | ||
| 265 | |||
| 262 | std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { | 266 | std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { |
| 263 | auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); | 267 | auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); |
| 264 | const std::string guid = GetGUID(sdl_joystick); | 268 | const auto guid = GetGUID(sdl_joystick); |
| 265 | 269 | ||
| 266 | std::scoped_lock lock{joystick_map_mutex}; | 270 | std::scoped_lock lock{joystick_map_mutex}; |
| 267 | const auto map_it = joystick_map.find(guid); | 271 | const auto map_it = joystick_map.find(guid); |
| @@ -295,7 +299,7 @@ void SDLDriver::InitJoystick(int joystick_index) { | |||
| 295 | return; | 299 | return; |
| 296 | } | 300 | } |
| 297 | 301 | ||
| 298 | const std::string guid = GetGUID(sdl_joystick); | 302 | const auto guid = GetGUID(sdl_joystick); |
| 299 | 303 | ||
| 300 | std::scoped_lock lock{joystick_map_mutex}; | 304 | std::scoped_lock lock{joystick_map_mutex}; |
| 301 | if (joystick_map.find(guid) == joystick_map.end()) { | 305 | if (joystick_map.find(guid) == joystick_map.end()) { |
| @@ -324,7 +328,7 @@ void SDLDriver::InitJoystick(int joystick_index) { | |||
| 324 | } | 328 | } |
| 325 | 329 | ||
| 326 | void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) { | 330 | void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) { |
| 327 | const std::string guid = GetGUID(sdl_joystick); | 331 | const auto guid = GetGUID(sdl_joystick); |
| 328 | 332 | ||
| 329 | std::scoped_lock lock{joystick_map_mutex}; | 333 | std::scoped_lock lock{joystick_map_mutex}; |
| 330 | // This call to guid is safe since the joystick is guaranteed to be in the map | 334 | // This call to guid is safe since the joystick is guaranteed to be in the map |
| @@ -434,6 +438,7 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en | |||
| 434 | using namespace std::chrono_literals; | 438 | using namespace std::chrono_literals; |
| 435 | while (initialized) { | 439 | while (initialized) { |
| 436 | SDL_PumpEvents(); | 440 | SDL_PumpEvents(); |
| 441 | SendVibrations(); | ||
| 437 | std::this_thread::sleep_for(1ms); | 442 | std::this_thread::sleep_for(1ms); |
| 438 | } | 443 | } |
| 439 | }); | 444 | }); |
| @@ -469,7 +474,7 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const { | |||
| 469 | devices.emplace_back(Common::ParamPackage{ | 474 | devices.emplace_back(Common::ParamPackage{ |
| 470 | {"engine", GetEngineName()}, | 475 | {"engine", GetEngineName()}, |
| 471 | {"display", std::move(name)}, | 476 | {"display", std::move(name)}, |
| 472 | {"guid", joystick->GetGUID()}, | 477 | {"guid", joystick->GetGUID().RawString()}, |
| 473 | {"port", std::to_string(joystick->GetPort())}, | 478 | {"port", std::to_string(joystick->GetPort())}, |
| 474 | }); | 479 | }); |
| 475 | if (joystick->IsJoyconLeft()) { | 480 | if (joystick->IsJoyconLeft()) { |
| @@ -492,8 +497,8 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const { | |||
| 492 | devices.emplace_back(Common::ParamPackage{ | 497 | devices.emplace_back(Common::ParamPackage{ |
| 493 | {"engine", GetEngineName()}, | 498 | {"engine", GetEngineName()}, |
| 494 | {"display", std::move(name)}, | 499 | {"display", std::move(name)}, |
| 495 | {"guid", joystick->GetGUID()}, | 500 | {"guid", joystick->GetGUID().RawString()}, |
| 496 | {"guid2", joystick2->GetGUID()}, | 501 | {"guid2", joystick2->GetGUID().RawString()}, |
| 497 | {"port", std::to_string(joystick->GetPort())}, | 502 | {"port", std::to_string(joystick->GetPort())}, |
| 498 | }); | 503 | }); |
| 499 | } | 504 | } |
| @@ -531,57 +536,75 @@ Common::Input::VibrationError SDLDriver::SetRumble( | |||
| 531 | .type = Common::Input::VibrationAmplificationType::Exponential, | 536 | .type = Common::Input::VibrationAmplificationType::Exponential, |
| 532 | }; | 537 | }; |
| 533 | 538 | ||
| 534 | if (!joystick->RumblePlay(new_vibration)) { | 539 | if (vibration.type == Common::Input::VibrationAmplificationType::Test) { |
| 535 | return Common::Input::VibrationError::Unknown; | 540 | if (!joystick->RumblePlay(new_vibration)) { |
| 541 | return Common::Input::VibrationError::Unknown; | ||
| 542 | } | ||
| 543 | return Common::Input::VibrationError::None; | ||
| 536 | } | 544 | } |
| 537 | 545 | ||
| 546 | vibration_queue.Push(VibrationRequest{ | ||
| 547 | .identifier = identifier, | ||
| 548 | .vibration = new_vibration, | ||
| 549 | }); | ||
| 550 | |||
| 538 | return Common::Input::VibrationError::None; | 551 | return Common::Input::VibrationError::None; |
| 539 | } | 552 | } |
| 540 | 553 | ||
| 541 | Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, | 554 | void SDLDriver::SendVibrations() { |
| 555 | while (!vibration_queue.Empty()) { | ||
| 556 | VibrationRequest request; | ||
| 557 | vibration_queue.Pop(request); | ||
| 558 | const auto joystick = GetSDLJoystickByGUID(request.identifier.guid.RawString(), | ||
| 559 | static_cast<int>(request.identifier.port)); | ||
| 560 | joystick->RumblePlay(request.vibration); | ||
| 561 | } | ||
| 562 | } | ||
| 563 | |||
| 564 | Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, const Common::UUID& guid, | ||
| 542 | s32 axis, float value) const { | 565 | s32 axis, float value) const { |
| 543 | Common::ParamPackage params{}; | 566 | Common::ParamPackage params{}; |
| 544 | params.Set("engine", GetEngineName()); | 567 | params.Set("engine", GetEngineName()); |
| 545 | params.Set("port", port); | 568 | params.Set("port", port); |
| 546 | params.Set("guid", std::move(guid)); | 569 | params.Set("guid", guid.RawString()); |
| 547 | params.Set("axis", axis); | 570 | params.Set("axis", axis); |
| 548 | params.Set("threshold", "0.5"); | 571 | params.Set("threshold", "0.5"); |
| 549 | params.Set("invert", value < 0 ? "-" : "+"); | 572 | params.Set("invert", value < 0 ? "-" : "+"); |
| 550 | return params; | 573 | return params; |
| 551 | } | 574 | } |
| 552 | 575 | ||
| 553 | Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, std::string guid, | 576 | Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, const Common::UUID& guid, |
| 554 | s32 button) const { | 577 | s32 button) const { |
| 555 | Common::ParamPackage params{}; | 578 | Common::ParamPackage params{}; |
| 556 | params.Set("engine", GetEngineName()); | 579 | params.Set("engine", GetEngineName()); |
| 557 | params.Set("port", port); | 580 | params.Set("port", port); |
| 558 | params.Set("guid", std::move(guid)); | 581 | params.Set("guid", guid.RawString()); |
| 559 | params.Set("button", button); | 582 | params.Set("button", button); |
| 560 | return params; | 583 | return params; |
| 561 | } | 584 | } |
| 562 | 585 | ||
| 563 | Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, std::string guid, s32 hat, | 586 | Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, const Common::UUID& guid, |
| 564 | u8 value) const { | 587 | s32 hat, u8 value) const { |
| 565 | Common::ParamPackage params{}; | 588 | Common::ParamPackage params{}; |
| 566 | params.Set("engine", GetEngineName()); | 589 | params.Set("engine", GetEngineName()); |
| 567 | params.Set("port", port); | 590 | params.Set("port", port); |
| 568 | params.Set("guid", std::move(guid)); | 591 | params.Set("guid", guid.RawString()); |
| 569 | params.Set("hat", hat); | 592 | params.Set("hat", hat); |
| 570 | params.Set("direction", GetHatButtonName(value)); | 593 | params.Set("direction", GetHatButtonName(value)); |
| 571 | return params; | 594 | return params; |
| 572 | } | 595 | } |
| 573 | 596 | ||
| 574 | Common::ParamPackage SDLDriver::BuildMotionParam(int port, std::string guid) const { | 597 | Common::ParamPackage SDLDriver::BuildMotionParam(int port, const Common::UUID& guid) const { |
| 575 | Common::ParamPackage params{}; | 598 | Common::ParamPackage params{}; |
| 576 | params.Set("engine", GetEngineName()); | 599 | params.Set("engine", GetEngineName()); |
| 577 | params.Set("motion", 0); | 600 | params.Set("motion", 0); |
| 578 | params.Set("port", port); | 601 | params.Set("port", port); |
| 579 | params.Set("guid", std::move(guid)); | 602 | params.Set("guid", guid.RawString()); |
| 580 | return params; | 603 | return params; |
| 581 | } | 604 | } |
| 582 | 605 | ||
| 583 | Common::ParamPackage SDLDriver::BuildParamPackageForBinding( | 606 | Common::ParamPackage SDLDriver::BuildParamPackageForBinding( |
| 584 | int port, const std::string& guid, const SDL_GameControllerButtonBind& binding) const { | 607 | int port, const Common::UUID& guid, const SDL_GameControllerButtonBind& binding) const { |
| 585 | switch (binding.bindType) { | 608 | switch (binding.bindType) { |
| 586 | case SDL_CONTROLLER_BINDTYPE_NONE: | 609 | case SDL_CONTROLLER_BINDTYPE_NONE: |
| 587 | break; | 610 | break; |
diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index dcd0d1e64..0846fbb50 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <SDL.h> | 12 | #include <SDL.h> |
| 13 | 13 | ||
| 14 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 15 | #include "common/threadsafe_queue.h" | ||
| 15 | #include "input_common/input_engine.h" | 16 | #include "input_common/input_engine.h" |
| 16 | 17 | ||
| 17 | union SDL_Event; | 18 | union SDL_Event; |
| @@ -46,6 +47,7 @@ public: | |||
| 46 | * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so | 47 | * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so |
| 47 | * tie it to a SDLJoystick with the same guid and that port | 48 | * tie it to a SDLJoystick with the same guid and that port |
| 48 | */ | 49 | */ |
| 50 | std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const Common::UUID& guid, int port); | ||
| 49 | std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port); | 51 | std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port); |
| 50 | 52 | ||
| 51 | std::vector<Common::ParamPackage> GetInputDevices() const override; | 53 | std::vector<Common::ParamPackage> GetInputDevices() const override; |
| @@ -64,24 +66,32 @@ public: | |||
| 64 | const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; | 66 | const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; |
| 65 | 67 | ||
| 66 | private: | 68 | private: |
| 69 | struct VibrationRequest { | ||
| 70 | PadIdentifier identifier; | ||
| 71 | Common::Input::VibrationStatus vibration; | ||
| 72 | }; | ||
| 73 | |||
| 67 | void InitJoystick(int joystick_index); | 74 | void InitJoystick(int joystick_index); |
| 68 | void CloseJoystick(SDL_Joystick* sdl_joystick); | 75 | void CloseJoystick(SDL_Joystick* sdl_joystick); |
| 69 | 76 | ||
| 70 | /// Needs to be called before SDL_QuitSubSystem. | 77 | /// Needs to be called before SDL_QuitSubSystem. |
| 71 | void CloseJoysticks(); | 78 | void CloseJoysticks(); |
| 72 | 79 | ||
| 73 | Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, | 80 | /// Takes all vibrations from the queue and sends the command to the controller |
| 74 | float value = 0.1f) const; | 81 | void SendVibrations(); |
| 75 | Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, | 82 | |
| 83 | Common::ParamPackage BuildAnalogParamPackageForButton(int port, const Common::UUID& guid, | ||
| 84 | s32 axis, float value = 0.1f) const; | ||
| 85 | Common::ParamPackage BuildButtonParamPackageForButton(int port, const Common::UUID& guid, | ||
| 76 | s32 button) const; | 86 | s32 button) const; |
| 77 | 87 | ||
| 78 | Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat, | 88 | Common::ParamPackage BuildHatParamPackageForButton(int port, const Common::UUID& guid, s32 hat, |
| 79 | u8 value) const; | 89 | u8 value) const; |
| 80 | 90 | ||
| 81 | Common::ParamPackage BuildMotionParam(int port, std::string guid) const; | 91 | Common::ParamPackage BuildMotionParam(int port, const Common::UUID& guid) const; |
| 82 | 92 | ||
| 83 | Common::ParamPackage BuildParamPackageForBinding( | 93 | Common::ParamPackage BuildParamPackageForBinding( |
| 84 | int port, const std::string& guid, const SDL_GameControllerButtonBind& binding) const; | 94 | int port, const Common::UUID& guid, const SDL_GameControllerButtonBind& binding) const; |
| 85 | 95 | ||
| 86 | Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x, | 96 | Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x, |
| 87 | int axis_y, float offset_x, | 97 | int axis_y, float offset_x, |
| @@ -107,8 +117,11 @@ private: | |||
| 107 | /// Returns true if the button is on the left joycon | 117 | /// Returns true if the button is on the left joycon |
| 108 | bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const; | 118 | bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const; |
| 109 | 119 | ||
| 120 | /// Queue of vibration request to controllers | ||
| 121 | Common::SPSCQueue<VibrationRequest> vibration_queue; | ||
| 122 | |||
| 110 | /// Map of GUID of a list of corresponding virtual Joysticks | 123 | /// Map of GUID of a list of corresponding virtual Joysticks |
| 111 | std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map; | 124 | std::unordered_map<Common::UUID, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map; |
| 112 | std::mutex joystick_map_mutex; | 125 | std::mutex joystick_map_mutex; |
| 113 | 126 | ||
| 114 | bool start_thread = false; | 127 | bool start_thread = false; |
diff --git a/src/input_common/drivers/touch_screen.cpp b/src/input_common/drivers/touch_screen.cpp index 8acbe4584..1753e0893 100644 --- a/src/input_common/drivers/touch_screen.cpp +++ b/src/input_common/drivers/touch_screen.cpp | |||
| @@ -14,38 +14,93 @@ constexpr PadIdentifier identifier = { | |||
| 14 | 14 | ||
| 15 | TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) { | 15 | TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) { |
| 16 | PreSetController(identifier); | 16 | PreSetController(identifier); |
| 17 | ReleaseAllTouch(); | ||
| 17 | } | 18 | } |
| 18 | 19 | ||
| 19 | void TouchScreen::TouchMoved(float x, float y, std::size_t finger) { | 20 | void TouchScreen::TouchMoved(float x, float y, std::size_t finger_id) { |
| 20 | if (finger >= 16) { | 21 | const auto index = GetIndexFromFingerId(finger_id); |
| 22 | if (!index) { | ||
| 23 | // Touch doesn't exist handle it as a new one | ||
| 24 | TouchPressed(x, y, finger_id); | ||
| 21 | return; | 25 | return; |
| 22 | } | 26 | } |
| 23 | TouchPressed(x, y, finger); | 27 | const auto i = index.value(); |
| 28 | fingers[i].is_active = true; | ||
| 29 | SetButton(identifier, static_cast<int>(i), true); | ||
| 30 | SetAxis(identifier, static_cast<int>(i * 2), x); | ||
| 31 | SetAxis(identifier, static_cast<int>(i * 2 + 1), y); | ||
| 24 | } | 32 | } |
| 25 | 33 | ||
| 26 | void TouchScreen::TouchPressed(float x, float y, std::size_t finger) { | 34 | void TouchScreen::TouchPressed(float x, float y, std::size_t finger_id) { |
| 27 | if (finger >= 16) { | 35 | if (GetIndexFromFingerId(finger_id)) { |
| 36 | // Touch already exist. Just update the data | ||
| 37 | TouchMoved(x, y, finger_id); | ||
| 28 | return; | 38 | return; |
| 29 | } | 39 | } |
| 30 | SetButton(identifier, static_cast<int>(finger), true); | 40 | const auto index = GetNextFreeIndex(); |
| 31 | SetAxis(identifier, static_cast<int>(finger * 2), x); | 41 | if (!index) { |
| 32 | SetAxis(identifier, static_cast<int>(finger * 2 + 1), y); | 42 | // No free entries. Ignore input |
| 43 | return; | ||
| 44 | } | ||
| 45 | const auto i = index.value(); | ||
| 46 | fingers[i].is_enabled = true; | ||
| 47 | fingers[i].finger_id = finger_id; | ||
| 48 | TouchMoved(x, y, finger_id); | ||
| 33 | } | 49 | } |
| 34 | 50 | ||
| 35 | void TouchScreen::TouchReleased(std::size_t finger) { | 51 | void TouchScreen::TouchReleased(std::size_t finger_id) { |
| 36 | if (finger >= 16) { | 52 | const auto index = GetIndexFromFingerId(finger_id); |
| 53 | if (!index) { | ||
| 37 | return; | 54 | return; |
| 38 | } | 55 | } |
| 39 | SetButton(identifier, static_cast<int>(finger), false); | 56 | const auto i = index.value(); |
| 40 | SetAxis(identifier, static_cast<int>(finger * 2), 0.0f); | 57 | fingers[i].is_enabled = false; |
| 41 | SetAxis(identifier, static_cast<int>(finger * 2 + 1), 0.0f); | 58 | SetButton(identifier, static_cast<int>(i), false); |
| 59 | SetAxis(identifier, static_cast<int>(i * 2), 0.0f); | ||
| 60 | SetAxis(identifier, static_cast<int>(i * 2 + 1), 0.0f); | ||
| 61 | } | ||
| 62 | |||
| 63 | std::optional<std::size_t> TouchScreen::GetIndexFromFingerId(std::size_t finger_id) const { | ||
| 64 | for (std::size_t index = 0; index < MAX_FINGER_COUNT; ++index) { | ||
| 65 | const auto& finger = fingers[index]; | ||
| 66 | if (!finger.is_enabled) { | ||
| 67 | continue; | ||
| 68 | } | ||
| 69 | if (finger.finger_id == finger_id) { | ||
| 70 | return index; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | return std::nullopt; | ||
| 74 | } | ||
| 75 | |||
| 76 | std::optional<std::size_t> TouchScreen::GetNextFreeIndex() const { | ||
| 77 | for (std::size_t index = 0; index < MAX_FINGER_COUNT; ++index) { | ||
| 78 | if (!fingers[index].is_enabled) { | ||
| 79 | return index; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | return std::nullopt; | ||
| 83 | } | ||
| 84 | |||
| 85 | void TouchScreen::ClearActiveFlag() { | ||
| 86 | for (auto& finger : fingers) { | ||
| 87 | finger.is_active = false; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | void TouchScreen::ReleaseInactiveTouch() { | ||
| 92 | for (const auto& finger : fingers) { | ||
| 93 | if (!finger.is_active) { | ||
| 94 | TouchReleased(finger.finger_id); | ||
| 95 | } | ||
| 96 | } | ||
| 42 | } | 97 | } |
| 43 | 98 | ||
| 44 | void TouchScreen::ReleaseAllTouch() { | 99 | void TouchScreen::ReleaseAllTouch() { |
| 45 | for (int index = 0; index < 16; ++index) { | 100 | for (const auto& finger : fingers) { |
| 46 | SetButton(identifier, index, false); | 101 | if (finger.is_enabled) { |
| 47 | SetAxis(identifier, index * 2, 0.0f); | 102 | TouchReleased(finger.finger_id); |
| 48 | SetAxis(identifier, index * 2 + 1, 0.0f); | 103 | } |
| 49 | } | 104 | } |
| 50 | } | 105 | } |
| 51 | 106 | ||
diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h index 193478ead..f46036ffd 100644 --- a/src/input_common/drivers/touch_screen.h +++ b/src/input_common/drivers/touch_screen.h | |||
| @@ -3,41 +3,65 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <optional> | ||
| 7 | |||
| 6 | #include "input_common/input_engine.h" | 8 | #include "input_common/input_engine.h" |
| 7 | 9 | ||
| 8 | namespace InputCommon { | 10 | namespace InputCommon { |
| 9 | 11 | ||
| 10 | /** | 12 | /** |
| 11 | * A button device factory representing a keyboard. It receives keyboard events and forward them | 13 | * A touch device factory representing a touch screen. It receives touch events and forward them |
| 12 | * to all button devices it created. | 14 | * to all touch devices it created. |
| 13 | */ | 15 | */ |
| 14 | class TouchScreen final : public InputEngine { | 16 | class TouchScreen final : public InputEngine { |
| 15 | public: | 17 | public: |
| 16 | explicit TouchScreen(std::string input_engine_); | 18 | explicit TouchScreen(std::string input_engine_); |
| 17 | 19 | ||
| 18 | /** | 20 | /** |
| 19 | * Signals that mouse has moved. | 21 | * Signals that touch has moved and marks this touch point as active |
| 20 | * @param x the x-coordinate of the cursor | 22 | * @param x new horizontal position |
| 21 | * @param y the y-coordinate of the cursor | 23 | * @param y new vertical position |
| 22 | * @param center_x the x-coordinate of the middle of the screen | 24 | * @param finger_id of the touch point to be updated |
| 23 | * @param center_y the y-coordinate of the middle of the screen | ||
| 24 | */ | 25 | */ |
| 25 | void TouchMoved(float x, float y, std::size_t finger); | 26 | void TouchMoved(float x, float y, std::size_t finger_id); |
| 26 | 27 | ||
| 27 | /** | 28 | /** |
| 28 | * Sets the status of all buttons bound with the key to pressed | 29 | * Signals and creates a new touch point with this finger id |
| 29 | * @param key_code the code of the key to press | 30 | * @param x starting horizontal position |
| 31 | * @param y starting vertical position | ||
| 32 | * @param finger_id to be assigned to the new touch point | ||
| 30 | */ | 33 | */ |
| 31 | void TouchPressed(float x, float y, std::size_t finger); | 34 | void TouchPressed(float x, float y, std::size_t finger_id); |
| 32 | 35 | ||
| 33 | /** | 36 | /** |
| 34 | * Sets the status of all buttons bound with the key to released | 37 | * Signals and resets the touch point related to the this finger id |
| 35 | * @param key_code the code of the key to release | 38 | * @param finger_id to be released |
| 36 | */ | 39 | */ |
| 37 | void TouchReleased(std::size_t finger); | 40 | void TouchReleased(std::size_t finger_id); |
| 41 | |||
| 42 | /// Resets the active flag for each touch point | ||
| 43 | void ClearActiveFlag(); | ||
| 44 | |||
| 45 | /// Releases all touch that haven't been marked as active | ||
| 46 | void ReleaseInactiveTouch(); | ||
| 38 | 47 | ||
| 39 | /// Resets all inputs to their initial value | 48 | /// Resets all inputs to their initial value |
| 40 | void ReleaseAllTouch(); | 49 | void ReleaseAllTouch(); |
| 50 | |||
| 51 | private: | ||
| 52 | static constexpr std::size_t MAX_FINGER_COUNT = 16; | ||
| 53 | |||
| 54 | struct TouchStatus { | ||
| 55 | std::size_t finger_id{}; | ||
| 56 | bool is_enabled{}; | ||
| 57 | bool is_active{}; | ||
| 58 | }; | ||
| 59 | |||
| 60 | std::optional<std::size_t> GetIndexFromFingerId(std::size_t finger_id) const; | ||
| 61 | |||
| 62 | std::optional<std::size_t> GetNextFreeIndex() const; | ||
| 63 | |||
| 64 | std::array<TouchStatus, MAX_FINGER_COUNT> fingers{}; | ||
| 41 | }; | 65 | }; |
| 42 | 66 | ||
| 43 | } // namespace InputCommon | 67 | } // namespace InputCommon |
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 4c76ce1ea..ae1dbe619 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -253,9 +253,6 @@ else() | |||
| 253 | -Werror | 253 | -Werror |
| 254 | -Werror=conversion | 254 | -Werror=conversion |
| 255 | -Werror=ignored-qualifiers | 255 | -Werror=ignored-qualifiers |
| 256 | -Werror=implicit-fallthrough | ||
| 257 | -Werror=shadow | ||
| 258 | -Werror=sign-compare | ||
| 259 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> | 256 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> |
| 260 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> | 257 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> |
| 261 | -Werror=unused-variable | 258 | -Werror=unused-variable |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.h b/src/shader_recompiler/frontend/ir/opcodes.h index d17dc0376..752879a18 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.h +++ b/src/shader_recompiler/frontend/ir/opcodes.h | |||
| @@ -103,6 +103,6 @@ struct fmt::formatter<Shader::IR::Opcode> { | |||
| 103 | } | 103 | } |
| 104 | template <typename FormatContext> | 104 | template <typename FormatContext> |
| 105 | auto format(const Shader::IR::Opcode& op, FormatContext& ctx) { | 105 | auto format(const Shader::IR::Opcode& op, FormatContext& ctx) { |
| 106 | return format_to(ctx.out(), "{}", Shader::IR::NameOf(op)); | 106 | return fmt::format_to(ctx.out(), "{}", Shader::IR::NameOf(op)); |
| 107 | } | 107 | } |
| 108 | }; | 108 | }; |
diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.h b/src/shader_recompiler/frontend/maxwell/control_flow.h index 2487b9b0b..1ce45b3a5 100644 --- a/src/shader_recompiler/frontend/maxwell/control_flow.h +++ b/src/shader_recompiler/frontend/maxwell/control_flow.h | |||
| @@ -58,7 +58,7 @@ public: | |||
| 58 | [[nodiscard]] Stack Remove(Token token) const; | 58 | [[nodiscard]] Stack Remove(Token token) const; |
| 59 | 59 | ||
| 60 | private: | 60 | private: |
| 61 | boost::container::small_vector<StackEntry, 3> entries; | 61 | std::vector<StackEntry> entries; |
| 62 | }; | 62 | }; |
| 63 | 63 | ||
| 64 | struct IndirectBranch { | 64 | struct IndirectBranch { |
diff --git a/src/shader_recompiler/frontend/maxwell/opcodes.h b/src/shader_recompiler/frontend/maxwell/opcodes.h index 83093fca0..72dd143c2 100644 --- a/src/shader_recompiler/frontend/maxwell/opcodes.h +++ b/src/shader_recompiler/frontend/maxwell/opcodes.h | |||
| @@ -24,6 +24,6 @@ struct fmt::formatter<Shader::Maxwell::Opcode> { | |||
| 24 | } | 24 | } |
| 25 | template <typename FormatContext> | 25 | template <typename FormatContext> |
| 26 | auto format(const Shader::Maxwell::Opcode& opcode, FormatContext& ctx) { | 26 | auto format(const Shader::Maxwell::Opcode& opcode, FormatContext& ctx) { |
| 27 | return format_to(ctx.out(), "{}", NameOf(opcode)); | 27 | return fmt::format_to(ctx.out(), "{}", NameOf(opcode)); |
| 28 | } | 28 | } |
| 29 | }; | 29 | }; |
diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp index 3dc7c9a11..578bc8c1b 100644 --- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp +++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp | |||
| @@ -975,13 +975,7 @@ private: | |||
| 975 | Environment& env; | 975 | Environment& env; |
| 976 | IR::AbstractSyntaxList& syntax_list; | 976 | IR::AbstractSyntaxList& syntax_list; |
| 977 | bool uses_demote_to_helper{}; | 977 | bool uses_demote_to_helper{}; |
| 978 | |||
| 979 | // TODO: C++20 Remove this when all compilers support constexpr std::vector | ||
| 980 | #if __cpp_lib_constexpr_vector >= 201907 | ||
| 981 | static constexpr Flow::Block dummy_flow_block; | ||
| 982 | #else | ||
| 983 | const Flow::Block dummy_flow_block; | 978 | const Flow::Block dummy_flow_block; |
| 984 | #endif | ||
| 985 | }; | 979 | }; |
| 986 | } // Anonymous namespace | 980 | } // Anonymous namespace |
| 987 | 981 | ||
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 6a6325e38..14de7bc89 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -258,10 +258,6 @@ if (MSVC) | |||
| 258 | target_compile_options(video_core PRIVATE | 258 | target_compile_options(video_core PRIVATE |
| 259 | /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data | 259 | /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data |
| 260 | /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data | 260 | /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data |
| 261 | /we4456 # Declaration of 'identifier' hides previous local declaration | ||
| 262 | /we4457 # Declaration of 'identifier' hides function parameter | ||
| 263 | /we4458 # Declaration of 'identifier' hides class member | ||
| 264 | /we4459 # Declaration of 'identifier' hides global declaration | ||
| 265 | ) | 261 | ) |
| 266 | else() | 262 | else() |
| 267 | target_compile_options(video_core PRIVATE | 263 | target_compile_options(video_core PRIVATE |
| @@ -269,7 +265,6 @@ else() | |||
| 269 | -Wno-error=sign-conversion | 265 | -Wno-error=sign-conversion |
| 270 | -Werror=pessimizing-move | 266 | -Werror=pessimizing-move |
| 271 | -Werror=redundant-move | 267 | -Werror=redundant-move |
| 272 | -Werror=shadow | ||
| 273 | -Werror=type-limits | 268 | -Werror=type-limits |
| 274 | 269 | ||
| 275 | $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> | 270 | $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> |
| @@ -277,3 +272,7 @@ else() | |||
| 277 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> | 272 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> |
| 278 | ) | 273 | ) |
| 279 | endif() | 274 | endif() |
| 275 | |||
| 276 | if (ARCHITECTURE_x86_64) | ||
| 277 | target_link_libraries(video_core PRIVATE dynarmic) | ||
| 278 | endif() | ||
diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 83b2e0fc4..a5eb97b7f 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp | |||
| @@ -224,7 +224,7 @@ void Codec::Decode() { | |||
| 224 | vp9_hidden_frame = vp9_decoder->WasFrameHidden(); | 224 | vp9_hidden_frame = vp9_decoder->WasFrameHidden(); |
| 225 | return vp9_decoder->GetFrameBytes(); | 225 | return vp9_decoder->GetFrameBytes(); |
| 226 | default: | 226 | default: |
| 227 | UNREACHABLE(); | 227 | ASSERT(false); |
| 228 | return std::vector<u8>{}; | 228 | return std::vector<u8>{}; |
| 229 | } | 229 | } |
| 230 | }(); | 230 | }(); |
diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp index a95618913..c01431441 100644 --- a/src/video_core/command_classes/codecs/vp9.cpp +++ b/src/video_core/command_classes/codecs/vp9.cpp | |||
| @@ -153,7 +153,7 @@ constexpr Vp9EntropyProbs default_probs{ | |||
| 153 | .high_precision{128, 128}, | 153 | .high_precision{128, 128}, |
| 154 | }; | 154 | }; |
| 155 | 155 | ||
| 156 | constexpr std::array<s32, 256> norm_lut{ | 156 | constexpr std::array<u8, 256> norm_lut{ |
| 157 | 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | 157 | 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
| 158 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | 158 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
| 159 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 159 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| @@ -164,7 +164,7 @@ constexpr std::array<s32, 256> norm_lut{ | |||
| 164 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 164 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 165 | }; | 165 | }; |
| 166 | 166 | ||
| 167 | constexpr std::array<s32, 254> map_lut{ | 167 | constexpr std::array<u8, 254> map_lut{ |
| 168 | 20, 21, 22, 23, 24, 25, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, | 168 | 20, 21, 22, 23, 24, 25, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, |
| 169 | 1, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 2, 50, 51, 52, 53, 54, | 169 | 1, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 2, 50, 51, 52, 53, 54, |
| 170 | 55, 56, 57, 58, 59, 60, 61, 3, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, | 170 | 55, 56, 57, 58, 59, 60, 61, 3, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, |
| @@ -232,7 +232,7 @@ constexpr std::array<s32, 254> map_lut{ | |||
| 232 | std::max(0, RecenterNonNeg(0xff - 1 - new_prob, 0xff - 1 - old_prob) - 1)); | 232 | std::max(0, RecenterNonNeg(0xff - 1 - new_prob, 0xff - 1 - old_prob) - 1)); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | return map_lut[index]; | 235 | return static_cast<s32>(map_lut[index]); |
| 236 | } | 236 | } |
| 237 | } // Anonymous namespace | 237 | } // Anonymous namespace |
| 238 | 238 | ||
| @@ -819,7 +819,7 @@ void VpxRangeEncoder::Write(bool bit, s32 probability) { | |||
| 819 | local_range = range - split; | 819 | local_range = range - split; |
| 820 | } | 820 | } |
| 821 | 821 | ||
| 822 | s32 shift = norm_lut[local_range]; | 822 | s32 shift = static_cast<s32>(norm_lut[local_range]); |
| 823 | local_range <<= shift; | 823 | local_range <<= shift; |
| 824 | count += shift; | 824 | count += shift; |
| 825 | 825 | ||
diff --git a/src/video_core/command_classes/vic.cpp b/src/video_core/command_classes/vic.cpp index bef321b6e..7c17df353 100644 --- a/src/video_core/command_classes/vic.cpp +++ b/src/video_core/command_classes/vic.cpp | |||
| @@ -228,7 +228,7 @@ void Vic::WriteYUVFrame(const AVFrame* frame, const VicConfig& config) { | |||
| 228 | break; | 228 | break; |
| 229 | } | 229 | } |
| 230 | default: | 230 | default: |
| 231 | UNREACHABLE(); | 231 | ASSERT(false); |
| 232 | break; | 232 | break; |
| 233 | } | 233 | } |
| 234 | gpu.MemoryManager().WriteBlock(output_surface_chroma_address, chroma_buffer.data(), | 234 | gpu.MemoryManager().WriteBlock(output_surface_chroma_address, chroma_buffer.data(), |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index d4652b167..3a4646289 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -173,6 +173,8 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume | |||
| 173 | case MAXWELL3D_REG_INDEX(shadow_ram_control): | 173 | case MAXWELL3D_REG_INDEX(shadow_ram_control): |
| 174 | shadow_state.shadow_ram_control = static_cast<Regs::ShadowRamControl>(nonshadow_argument); | 174 | shadow_state.shadow_ram_control = static_cast<Regs::ShadowRamControl>(nonshadow_argument); |
| 175 | return; | 175 | return; |
| 176 | case MAXWELL3D_REG_INDEX(macros.upload_address): | ||
| 177 | return macro_engine->ClearCode(regs.macros.upload_address); | ||
| 176 | case MAXWELL3D_REG_INDEX(macros.data): | 178 | case MAXWELL3D_REG_INDEX(macros.data): |
| 177 | return macro_engine->AddCode(regs.macros.upload_address, argument); | 179 | return macro_engine->AddCode(regs.macros.upload_address, argument); |
| 178 | case MAXWELL3D_REG_INDEX(macros.bind): | 180 | case MAXWELL3D_REG_INDEX(macros.bind): |
| @@ -593,8 +595,8 @@ void Maxwell3D::DrawArrays() { | |||
| 593 | 595 | ||
| 594 | std::optional<u64> Maxwell3D::GetQueryResult() { | 596 | std::optional<u64> Maxwell3D::GetQueryResult() { |
| 595 | switch (regs.query.query_get.select) { | 597 | switch (regs.query.query_get.select) { |
| 596 | case Regs::QuerySelect::Zero: | 598 | case Regs::QuerySelect::Payload: |
| 597 | return 0; | 599 | return regs.query.query_sequence; |
| 598 | case Regs::QuerySelect::SamplesPassed: | 600 | case Regs::QuerySelect::SamplesPassed: |
| 599 | // Deferred. | 601 | // Deferred. |
| 600 | rasterizer->Query(regs.query.QueryAddress(), QueryType::SamplesPassed, | 602 | rasterizer->Query(regs.query.QueryAddress(), QueryType::SamplesPassed, |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index c0c2c7d96..5f9eb208c 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -93,7 +93,7 @@ public: | |||
| 93 | }; | 93 | }; |
| 94 | 94 | ||
| 95 | enum class QuerySelect : u32 { | 95 | enum class QuerySelect : u32 { |
| 96 | Zero = 0, | 96 | Payload = 0, |
| 97 | TimeElapsed = 2, | 97 | TimeElapsed = 2, |
| 98 | TransformFeedbackPrimitivesGenerated = 11, | 98 | TransformFeedbackPrimitivesGenerated = 11, |
| 99 | PrimitivesGenerated = 18, | 99 | PrimitivesGenerated = 18, |
| @@ -202,7 +202,7 @@ public: | |||
| 202 | case Size::Size_11_11_10: | 202 | case Size::Size_11_11_10: |
| 203 | return 3; | 203 | return 3; |
| 204 | default: | 204 | default: |
| 205 | UNREACHABLE(); | 205 | ASSERT(false); |
| 206 | return 1; | 206 | return 1; |
| 207 | } | 207 | } |
| 208 | } | 208 | } |
| @@ -238,7 +238,7 @@ public: | |||
| 238 | case Size::Size_11_11_10: | 238 | case Size::Size_11_11_10: |
| 239 | return 4; | 239 | return 4; |
| 240 | default: | 240 | default: |
| 241 | UNREACHABLE(); | 241 | ASSERT(false); |
| 242 | return 1; | 242 | return 1; |
| 243 | } | 243 | } |
| 244 | } | 244 | } |
| @@ -274,7 +274,7 @@ public: | |||
| 274 | case Size::Size_11_11_10: | 274 | case Size::Size_11_11_10: |
| 275 | return "11_11_10"; | 275 | return "11_11_10"; |
| 276 | default: | 276 | default: |
| 277 | UNREACHABLE(); | 277 | ASSERT(false); |
| 278 | return {}; | 278 | return {}; |
| 279 | } | 279 | } |
| 280 | } | 280 | } |
| @@ -296,7 +296,7 @@ public: | |||
| 296 | case Type::Float: | 296 | case Type::Float: |
| 297 | return "FLOAT"; | 297 | return "FLOAT"; |
| 298 | } | 298 | } |
| 299 | UNREACHABLE(); | 299 | ASSERT(false); |
| 300 | return {}; | 300 | return {}; |
| 301 | } | 301 | } |
| 302 | 302 | ||
| @@ -336,7 +336,7 @@ public: | |||
| 336 | case 3: | 336 | case 3: |
| 337 | return {x3, y3}; | 337 | return {x3, y3}; |
| 338 | default: | 338 | default: |
| 339 | UNREACHABLE(); | 339 | ASSERT(false); |
| 340 | return {0, 0}; | 340 | return {0, 0}; |
| 341 | } | 341 | } |
| 342 | } | 342 | } |
| @@ -1193,7 +1193,7 @@ public: | |||
| 1193 | case IndexFormat::UnsignedInt: | 1193 | case IndexFormat::UnsignedInt: |
| 1194 | return 4; | 1194 | return 4; |
| 1195 | } | 1195 | } |
| 1196 | UNREACHABLE(); | 1196 | ASSERT(false); |
| 1197 | return 1; | 1197 | return 1; |
| 1198 | } | 1198 | } |
| 1199 | 1199 | ||
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index 76e8bc656..0efe58282 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp | |||
| @@ -62,7 +62,7 @@ void MaxwellDMA::Launch() { | |||
| 62 | 62 | ||
| 63 | if (!is_src_pitch && !is_dst_pitch) { | 63 | if (!is_src_pitch && !is_dst_pitch) { |
| 64 | // If both the source and the destination are in block layout, assert. | 64 | // If both the source and the destination are in block layout, assert. |
| 65 | UNREACHABLE_MSG("Tiled->Tiled DMA transfers are not yet implemented"); | 65 | UNIMPLEMENTED_MSG("Tiled->Tiled DMA transfers are not yet implemented"); |
| 66 | return; | 66 | return; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| @@ -134,7 +134,8 @@ void MaxwellDMA::CopyBlockLinearToPitch() { | |||
| 134 | 134 | ||
| 135 | // Deswizzle the input and copy it over. | 135 | // Deswizzle the input and copy it over. |
| 136 | UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0); | 136 | UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0); |
| 137 | const u32 bytes_per_pixel = regs.pitch_out / regs.line_length_in; | 137 | const u32 bytes_per_pixel = |
| 138 | regs.launch_dma.remap_enable ? regs.pitch_out / regs.line_length_in : 1; | ||
| 138 | const Parameters& src_params = regs.src_params; | 139 | const Parameters& src_params = regs.src_params; |
| 139 | const u32 width = src_params.width; | 140 | const u32 width = src_params.width; |
| 140 | const u32 height = src_params.height; | 141 | const u32 height = src_params.height; |
| @@ -166,7 +167,8 @@ void MaxwellDMA::CopyPitchToBlockLinear() { | |||
| 166 | UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0); | 167 | UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0); |
| 167 | 168 | ||
| 168 | const auto& dst_params = regs.dst_params; | 169 | const auto& dst_params = regs.dst_params; |
| 169 | const u32 bytes_per_pixel = regs.pitch_in / regs.line_length_in; | 170 | const u32 bytes_per_pixel = |
| 171 | regs.launch_dma.remap_enable ? regs.pitch_in / regs.line_length_in : 1; | ||
| 170 | const u32 width = dst_params.width; | 172 | const u32 width = dst_params.width; |
| 171 | const u32 height = dst_params.height; | 173 | const u32 height = dst_params.height; |
| 172 | const u32 depth = dst_params.depth; | 174 | const u32 depth = dst_params.depth; |
| @@ -210,7 +212,8 @@ void MaxwellDMA::CopyPitchToBlockLinear() { | |||
| 210 | } | 212 | } |
| 211 | 213 | ||
| 212 | void MaxwellDMA::FastCopyBlockLinearToPitch() { | 214 | void MaxwellDMA::FastCopyBlockLinearToPitch() { |
| 213 | const u32 bytes_per_pixel = regs.pitch_out / regs.line_length_in; | 215 | const u32 bytes_per_pixel = |
| 216 | regs.launch_dma.remap_enable ? regs.pitch_out / regs.line_length_in : 1; | ||
| 214 | const size_t src_size = GOB_SIZE; | 217 | const size_t src_size = GOB_SIZE; |
| 215 | const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count; | 218 | const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count; |
| 216 | u32 pos_x = regs.src_params.origin.x; | 219 | u32 pos_x = regs.src_params.origin.x; |
| @@ -257,7 +260,7 @@ void MaxwellDMA::ReleaseSemaphore() { | |||
| 257 | memory_manager.Write<u64>(address + 8, system.GPU().GetTicks()); | 260 | memory_manager.Write<u64>(address + 8, system.GPU().GetTicks()); |
| 258 | break; | 261 | break; |
| 259 | default: | 262 | default: |
| 260 | UNREACHABLE_MSG("Unknown semaphore type: {}", static_cast<u32>(type.Value())); | 263 | ASSERT_MSG(false, "Unknown semaphore type: {}", static_cast<u32>(type.Value())); |
| 261 | } | 264 | } |
| 262 | } | 265 | } |
| 263 | 266 | ||
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index b79a73132..b0ce9f000 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp | |||
| @@ -31,7 +31,8 @@ static void RunThread(std::stop_token stop_token, Core::System& system, | |||
| 31 | VideoCore::RasterizerInterface* const rasterizer = renderer.ReadRasterizer(); | 31 | VideoCore::RasterizerInterface* const rasterizer = renderer.ReadRasterizer(); |
| 32 | 32 | ||
| 33 | while (!stop_token.stop_requested()) { | 33 | while (!stop_token.stop_requested()) { |
| 34 | CommandDataContainer next = state.queue.PopWait(stop_token); | 34 | CommandDataContainer next; |
| 35 | state.queue.Pop(next, stop_token); | ||
| 35 | if (stop_token.stop_requested()) { | 36 | if (stop_token.stop_requested()) { |
| 36 | break; | 37 | break; |
| 37 | } | 38 | } |
| @@ -49,7 +50,7 @@ static void RunThread(std::stop_token stop_token, Core::System& system, | |||
| 49 | } else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) { | 50 | } else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) { |
| 50 | rasterizer->OnCPUWrite(invalidate->addr, invalidate->size); | 51 | rasterizer->OnCPUWrite(invalidate->addr, invalidate->size); |
| 51 | } else { | 52 | } else { |
| 52 | UNREACHABLE(); | 53 | ASSERT(false); |
| 53 | } | 54 | } |
| 54 | state.signaled_fence.store(next.fence); | 55 | state.signaled_fence.store(next.fence); |
| 55 | if (next.block) { | 56 | if (next.block) { |
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h index 71cd35756..ad9fd5eff 100644 --- a/src/video_core/gpu_thread.h +++ b/src/video_core/gpu_thread.h | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | #include <thread> | 10 | #include <thread> |
| 11 | #include <variant> | 11 | #include <variant> |
| 12 | 12 | ||
| 13 | #include "common/threadsafe_queue.h" | 13 | #include "common/bounded_threadsafe_queue.h" |
| 14 | #include "video_core/framebuffer_config.h" | 14 | #include "video_core/framebuffer_config.h" |
| 15 | 15 | ||
| 16 | namespace Tegra { | 16 | namespace Tegra { |
| @@ -96,9 +96,9 @@ struct CommandDataContainer { | |||
| 96 | 96 | ||
| 97 | /// Struct used to synchronize the GPU thread | 97 | /// Struct used to synchronize the GPU thread |
| 98 | struct SynchState final { | 98 | struct SynchState final { |
| 99 | using CommandQueue = Common::SPSCQueue<CommandDataContainer, true>; | 99 | using CommandQueue = Common::MPSCQueue<CommandDataContainer>; |
| 100 | std::mutex write_lock; | 100 | std::mutex write_lock; |
| 101 | CommandQueue queue; | 101 | CommandQueue queue{512}; // size must be 2^n |
| 102 | u64 last_fence{}; | 102 | u64 last_fence{}; |
| 103 | std::atomic<u64> signaled_fence{}; | 103 | std::atomic<u64> signaled_fence{}; |
| 104 | std::condition_variable_any cv; | 104 | std::condition_variable_any cv; |
diff --git a/src/video_core/macro/macro.cpp b/src/video_core/macro/macro.cpp index a033d03be..43f8b5904 100644 --- a/src/video_core/macro/macro.cpp +++ b/src/video_core/macro/macro.cpp | |||
| @@ -2,11 +2,15 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <cstring> | 4 | #include <cstring> |
| 5 | #include <fstream> | ||
| 5 | #include <optional> | 6 | #include <optional> |
| 7 | #include <span> | ||
| 6 | 8 | ||
| 7 | #include <boost/container_hash/hash.hpp> | 9 | #include <boost/container_hash/hash.hpp> |
| 8 | 10 | ||
| 9 | #include "common/assert.h" | 11 | #include "common/assert.h" |
| 12 | #include "common/fs/fs.h" | ||
| 13 | #include "common/fs/path_util.h" | ||
| 10 | #include "common/settings.h" | 14 | #include "common/settings.h" |
| 11 | #include "video_core/macro/macro.h" | 15 | #include "video_core/macro/macro.h" |
| 12 | #include "video_core/macro/macro_hle.h" | 16 | #include "video_core/macro/macro_hle.h" |
| @@ -15,6 +19,23 @@ | |||
| 15 | 19 | ||
| 16 | namespace Tegra { | 20 | namespace Tegra { |
| 17 | 21 | ||
| 22 | static void Dump(u64 hash, std::span<const u32> code) { | ||
| 23 | const auto base_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)}; | ||
| 24 | const auto macro_dir{base_dir / "macros"}; | ||
| 25 | if (!Common::FS::CreateDir(base_dir) || !Common::FS::CreateDir(macro_dir)) { | ||
| 26 | LOG_ERROR(Common_Filesystem, "Failed to create macro dump directories"); | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | const auto name{macro_dir / fmt::format("{:016x}.macro", hash)}; | ||
| 30 | std::fstream macro_file(name, std::ios::out | std::ios::binary); | ||
| 31 | if (!macro_file) { | ||
| 32 | LOG_ERROR(Common_Filesystem, "Unable to open or create file at {}", | ||
| 33 | Common::FS::PathToUTF8String(name)); | ||
| 34 | return; | ||
| 35 | } | ||
| 36 | macro_file.write(reinterpret_cast<const char*>(code.data()), code.size_bytes()); | ||
| 37 | } | ||
| 38 | |||
| 18 | MacroEngine::MacroEngine(Engines::Maxwell3D& maxwell3d) | 39 | MacroEngine::MacroEngine(Engines::Maxwell3D& maxwell3d) |
| 19 | : hle_macros{std::make_unique<Tegra::HLEMacro>(maxwell3d)} {} | 40 | : hle_macros{std::make_unique<Tegra::HLEMacro>(maxwell3d)} {} |
| 20 | 41 | ||
| @@ -24,6 +45,11 @@ void MacroEngine::AddCode(u32 method, u32 data) { | |||
| 24 | uploaded_macro_code[method].push_back(data); | 45 | uploaded_macro_code[method].push_back(data); |
| 25 | } | 46 | } |
| 26 | 47 | ||
| 48 | void MacroEngine::ClearCode(u32 method) { | ||
| 49 | macro_cache.erase(method); | ||
| 50 | uploaded_macro_code.erase(method); | ||
| 51 | } | ||
| 52 | |||
| 27 | void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) { | 53 | void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) { |
| 28 | auto compiled_macro = macro_cache.find(method); | 54 | auto compiled_macro = macro_cache.find(method); |
| 29 | if (compiled_macro != macro_cache.end()) { | 55 | if (compiled_macro != macro_cache.end()) { |
| @@ -45,7 +71,7 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) { | |||
| 45 | } | 71 | } |
| 46 | } | 72 | } |
| 47 | if (!mid_method.has_value()) { | 73 | if (!mid_method.has_value()) { |
| 48 | UNREACHABLE_MSG("Macro 0x{0:x} was not uploaded", method); | 74 | ASSERT_MSG(false, "Macro 0x{0:x} was not uploaded", method); |
| 49 | return; | 75 | return; |
| 50 | } | 76 | } |
| 51 | } | 77 | } |
| @@ -54,6 +80,9 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) { | |||
| 54 | if (!mid_method.has_value()) { | 80 | if (!mid_method.has_value()) { |
| 55 | cache_info.lle_program = Compile(macro_code->second); | 81 | cache_info.lle_program = Compile(macro_code->second); |
| 56 | cache_info.hash = boost::hash_value(macro_code->second); | 82 | cache_info.hash = boost::hash_value(macro_code->second); |
| 83 | if (Settings::values.dump_macros) { | ||
| 84 | Dump(cache_info.hash, macro_code->second); | ||
| 85 | } | ||
| 57 | } else { | 86 | } else { |
| 58 | const auto& macro_cached = uploaded_macro_code[mid_method.value()]; | 87 | const auto& macro_cached = uploaded_macro_code[mid_method.value()]; |
| 59 | const auto rebased_method = method - mid_method.value(); | 88 | const auto rebased_method = method - mid_method.value(); |
| @@ -63,6 +92,9 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) { | |||
| 63 | code.size() * sizeof(u32)); | 92 | code.size() * sizeof(u32)); |
| 64 | cache_info.hash = boost::hash_value(code); | 93 | cache_info.hash = boost::hash_value(code); |
| 65 | cache_info.lle_program = Compile(code); | 94 | cache_info.lle_program = Compile(code); |
| 95 | if (Settings::values.dump_macros) { | ||
| 96 | Dump(cache_info.hash, code); | ||
| 97 | } | ||
| 66 | } | 98 | } |
| 67 | 99 | ||
| 68 | if (auto hle_program = hle_macros->GetHLEProgram(cache_info.hash)) { | 100 | if (auto hle_program = hle_macros->GetHLEProgram(cache_info.hash)) { |
diff --git a/src/video_core/macro/macro.h b/src/video_core/macro/macro.h index 7e12c16dc..07d97ba39 100644 --- a/src/video_core/macro/macro.h +++ b/src/video_core/macro/macro.h | |||
| @@ -117,6 +117,9 @@ public: | |||
| 117 | // Store the uploaded macro code to compile them when they're called. | 117 | // Store the uploaded macro code to compile them when they're called. |
| 118 | void AddCode(u32 method, u32 data); | 118 | void AddCode(u32 method, u32 data); |
| 119 | 119 | ||
| 120 | // Clear the code associated with a method. | ||
| 121 | void ClearCode(u32 method); | ||
| 122 | |||
| 120 | // Compiles the macro if its not in the cache, and executes the compiled macro | 123 | // Compiles the macro if its not in the cache, and executes the compiled macro |
| 121 | void Execute(u32 method, const std::vector<u32>& parameters); | 124 | void Execute(u32 method, const std::vector<u32>& parameters); |
| 122 | 125 | ||
diff --git a/src/video_core/macro/macro_interpreter.cpp b/src/video_core/macro/macro_interpreter.cpp index 87d2e8721..f670b1bca 100644 --- a/src/video_core/macro/macro_interpreter.cpp +++ b/src/video_core/macro/macro_interpreter.cpp | |||
| @@ -308,7 +308,6 @@ bool MacroInterpreterImpl::EvaluateBranchCondition(Macro::BranchCondition cond, | |||
| 308 | return value != 0; | 308 | return value != 0; |
| 309 | } | 309 | } |
| 310 | UNREACHABLE(); | 310 | UNREACHABLE(); |
| 311 | return true; | ||
| 312 | } | 311 | } |
| 313 | 312 | ||
| 314 | Macro::Opcode MacroInterpreterImpl::GetOpcode() const { | 313 | Macro::Opcode MacroInterpreterImpl::GetOpcode() const { |
diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp index dc2b490d4..aca25d902 100644 --- a/src/video_core/macro/macro_jit_x64.cpp +++ b/src/video_core/macro/macro_jit_x64.cpp | |||
| @@ -23,7 +23,8 @@ MICROPROFILE_DEFINE(MacroJitExecute, "GPU", "Execute macro JIT", MP_RGB(255, 255 | |||
| 23 | namespace Tegra { | 23 | namespace Tegra { |
| 24 | namespace { | 24 | namespace { |
| 25 | constexpr Xbyak::Reg64 STATE = Xbyak::util::rbx; | 25 | constexpr Xbyak::Reg64 STATE = Xbyak::util::rbx; |
| 26 | constexpr Xbyak::Reg32 RESULT = Xbyak::util::ebp; | 26 | constexpr Xbyak::Reg32 RESULT = Xbyak::util::r10d; |
| 27 | constexpr Xbyak::Reg64 MAX_PARAMETER = Xbyak::util::r11; | ||
| 27 | constexpr Xbyak::Reg64 PARAMETERS = Xbyak::util::r12; | 28 | constexpr Xbyak::Reg64 PARAMETERS = Xbyak::util::r12; |
| 28 | constexpr Xbyak::Reg32 METHOD_ADDRESS = Xbyak::util::r14d; | 29 | constexpr Xbyak::Reg32 METHOD_ADDRESS = Xbyak::util::r14d; |
| 29 | constexpr Xbyak::Reg64 BRANCH_HOLDER = Xbyak::util::r15; | 30 | constexpr Xbyak::Reg64 BRANCH_HOLDER = Xbyak::util::r15; |
| @@ -31,6 +32,7 @@ constexpr Xbyak::Reg64 BRANCH_HOLDER = Xbyak::util::r15; | |||
| 31 | constexpr std::bitset<32> PERSISTENT_REGISTERS = Common::X64::BuildRegSet({ | 32 | constexpr std::bitset<32> PERSISTENT_REGISTERS = Common::X64::BuildRegSet({ |
| 32 | STATE, | 33 | STATE, |
| 33 | RESULT, | 34 | RESULT, |
| 35 | MAX_PARAMETER, | ||
| 34 | PARAMETERS, | 36 | PARAMETERS, |
| 35 | METHOD_ADDRESS, | 37 | METHOD_ADDRESS, |
| 36 | BRANCH_HOLDER, | 38 | BRANCH_HOLDER, |
| @@ -80,7 +82,7 @@ private: | |||
| 80 | u32 carry_flag{}; | 82 | u32 carry_flag{}; |
| 81 | }; | 83 | }; |
| 82 | static_assert(offsetof(JITState, maxwell3d) == 0, "Maxwell3D is not at 0x0"); | 84 | static_assert(offsetof(JITState, maxwell3d) == 0, "Maxwell3D is not at 0x0"); |
| 83 | using ProgramType = void (*)(JITState*, const u32*); | 85 | using ProgramType = void (*)(JITState*, const u32*, const u32*); |
| 84 | 86 | ||
| 85 | struct OptimizerState { | 87 | struct OptimizerState { |
| 86 | bool can_skip_carry{}; | 88 | bool can_skip_carry{}; |
| @@ -112,7 +114,7 @@ void MacroJITx64Impl::Execute(const std::vector<u32>& parameters, u32 method) { | |||
| 112 | JITState state{}; | 114 | JITState state{}; |
| 113 | state.maxwell3d = &maxwell3d; | 115 | state.maxwell3d = &maxwell3d; |
| 114 | state.registers = {}; | 116 | state.registers = {}; |
| 115 | program(&state, parameters.data()); | 117 | program(&state, parameters.data(), parameters.data() + parameters.size()); |
| 116 | } | 118 | } |
| 117 | 119 | ||
| 118 | void MacroJITx64Impl::Compile_ALU(Macro::Opcode opcode) { | 120 | void MacroJITx64Impl::Compile_ALU(Macro::Opcode opcode) { |
| @@ -409,7 +411,7 @@ void MacroJITx64Impl::Compile_Branch(Macro::Opcode opcode) { | |||
| 409 | 411 | ||
| 410 | Xbyak::Label end; | 412 | Xbyak::Label end; |
| 411 | auto value = Compile_GetRegister(opcode.src_a, eax); | 413 | auto value = Compile_GetRegister(opcode.src_a, eax); |
| 412 | test(value, value); | 414 | cmp(value, 0); // test(value, value); |
| 413 | if (optimizer.has_delayed_pc) { | 415 | if (optimizer.has_delayed_pc) { |
| 414 | switch (opcode.branch_condition) { | 416 | switch (opcode.branch_condition) { |
| 415 | case Macro::BranchCondition::Zero: | 417 | case Macro::BranchCondition::Zero: |
| @@ -488,6 +490,7 @@ void MacroJITx64Impl::Compile() { | |||
| 488 | // JIT state | 490 | // JIT state |
| 489 | mov(STATE, Common::X64::ABI_PARAM1); | 491 | mov(STATE, Common::X64::ABI_PARAM1); |
| 490 | mov(PARAMETERS, Common::X64::ABI_PARAM2); | 492 | mov(PARAMETERS, Common::X64::ABI_PARAM2); |
| 493 | mov(MAX_PARAMETER, Common::X64::ABI_PARAM3); | ||
| 491 | xor_(RESULT, RESULT); | 494 | xor_(RESULT, RESULT); |
| 492 | xor_(METHOD_ADDRESS, METHOD_ADDRESS); | 495 | xor_(METHOD_ADDRESS, METHOD_ADDRESS); |
| 493 | xor_(BRANCH_HOLDER, BRANCH_HOLDER); | 496 | xor_(BRANCH_HOLDER, BRANCH_HOLDER); |
| @@ -598,7 +601,22 @@ bool MacroJITx64Impl::Compile_NextInstruction() { | |||
| 598 | return true; | 601 | return true; |
| 599 | } | 602 | } |
| 600 | 603 | ||
| 604 | static void WarnInvalidParameter(uintptr_t parameter, uintptr_t max_parameter) { | ||
| 605 | LOG_CRITICAL(HW_GPU, | ||
| 606 | "Macro JIT: invalid parameter access 0x{:x} (0x{:x} is the last parameter)", | ||
| 607 | parameter, max_parameter - sizeof(u32)); | ||
| 608 | } | ||
| 609 | |||
| 601 | Xbyak::Reg32 MacroJITx64Impl::Compile_FetchParameter() { | 610 | Xbyak::Reg32 MacroJITx64Impl::Compile_FetchParameter() { |
| 611 | Xbyak::Label parameter_ok{}; | ||
| 612 | cmp(PARAMETERS, MAX_PARAMETER); | ||
| 613 | jb(parameter_ok, T_NEAR); | ||
| 614 | Common::X64::ABI_PushRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0); | ||
| 615 | mov(Common::X64::ABI_PARAM1, PARAMETERS); | ||
| 616 | mov(Common::X64::ABI_PARAM2, MAX_PARAMETER); | ||
| 617 | Common::X64::CallFarFunction(*this, &WarnInvalidParameter); | ||
| 618 | Common::X64::ABI_PopRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0); | ||
| 619 | L(parameter_ok); | ||
| 602 | mov(eax, dword[PARAMETERS]); | 620 | mov(eax, dword[PARAMETERS]); |
| 603 | add(PARAMETERS, sizeof(u32)); | 621 | add(PARAMETERS, sizeof(u32)); |
| 604 | return eax; | 622 | return eax; |
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index c8d99fdb5..d373be0ba 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp | |||
| @@ -67,7 +67,7 @@ void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) { | |||
| 67 | ASSERT(it->first == gpu_addr); | 67 | ASSERT(it->first == gpu_addr); |
| 68 | map_ranges.erase(it); | 68 | map_ranges.erase(it); |
| 69 | } else { | 69 | } else { |
| 70 | UNREACHABLE_MSG("Unmapping non-existent GPU address=0x{:x}", gpu_addr); | 70 | ASSERT_MSG(false, "Unmapping non-existent GPU address=0x{:x}", gpu_addr); |
| 71 | } | 71 | } |
| 72 | const auto submapped_ranges = GetSubmappedRange(gpu_addr, size); | 72 | const auto submapped_ranges = GetSubmappedRange(gpu_addr, size); |
| 73 | 73 | ||
| @@ -206,7 +206,7 @@ T MemoryManager::Read(GPUVAddr addr) const { | |||
| 206 | return value; | 206 | return value; |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | UNREACHABLE(); | 209 | ASSERT(false); |
| 210 | 210 | ||
| 211 | return {}; | 211 | return {}; |
| 212 | } | 212 | } |
| @@ -219,7 +219,7 @@ void MemoryManager::Write(GPUVAddr addr, T data) { | |||
| 219 | return; | 219 | return; |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | UNREACHABLE(); | 222 | ASSERT(false); |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | template u8 MemoryManager::Read<u8>(GPUVAddr addr) const; | 225 | template u8 MemoryManager::Read<u8>(GPUVAddr addr) const; |
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp index 35f42f2f8..67eae369d 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp | |||
| @@ -48,7 +48,7 @@ GLenum Stage(size_t stage_index) { | |||
| 48 | case 4: | 48 | case 4: |
| 49 | return GL_FRAGMENT_SHADER; | 49 | return GL_FRAGMENT_SHADER; |
| 50 | } | 50 | } |
| 51 | UNREACHABLE_MSG("{}", stage_index); | 51 | ASSERT_MSG(false, "{}", stage_index); |
| 52 | return GL_NONE; | 52 | return GL_NONE; |
| 53 | } | 53 | } |
| 54 | 54 | ||
| @@ -65,7 +65,7 @@ GLenum AssemblyStage(size_t stage_index) { | |||
| 65 | case 4: | 65 | case 4: |
| 66 | return GL_FRAGMENT_PROGRAM_NV; | 66 | return GL_FRAGMENT_PROGRAM_NV; |
| 67 | } | 67 | } |
| 68 | UNREACHABLE_MSG("{}", stage_index); | 68 | ASSERT_MSG(false, "{}", stage_index); |
| 69 | return GL_NONE; | 69 | return GL_NONE; |
| 70 | } | 70 | } |
| 71 | 71 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 8ef79753f..159b71161 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -563,12 +563,11 @@ void RasterizerOpenGL::SyncViewport() { | |||
| 563 | flags[Dirty::FrontFace] = false; | 563 | flags[Dirty::FrontFace] = false; |
| 564 | 564 | ||
| 565 | GLenum mode = MaxwellToGL::FrontFace(regs.front_face); | 565 | GLenum mode = MaxwellToGL::FrontFace(regs.front_face); |
| 566 | bool flip_faces = false; | 566 | bool flip_faces = true; |
| 567 | if (regs.screen_y_control.triangle_rast_flip != 0 && | 567 | if (regs.screen_y_control.triangle_rast_flip != 0) { |
| 568 | regs.viewport_transform[0].scale_y < 0.0f) { | ||
| 569 | flip_faces = !flip_faces; | 568 | flip_faces = !flip_faces; |
| 570 | } | 569 | } |
| 571 | if (regs.viewport_transform[0].scale_z < 0.0f) { | 570 | if (regs.viewport_transform[0].scale_y < 0.0f) { |
| 572 | flip_faces = !flip_faces; | 571 | flip_faces = !flip_faces; |
| 573 | } | 572 | } |
| 574 | if (flip_faces) { | 573 | if (flip_faces) { |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index cd48fef26..07d4b7cf0 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -85,7 +85,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, | |||
| 85 | case Maxwell::TessellationPrimitive::Quads: | 85 | case Maxwell::TessellationPrimitive::Quads: |
| 86 | return Shader::TessPrimitive::Quads; | 86 | return Shader::TessPrimitive::Quads; |
| 87 | } | 87 | } |
| 88 | UNREACHABLE(); | 88 | ASSERT(false); |
| 89 | return Shader::TessPrimitive::Triangles; | 89 | return Shader::TessPrimitive::Triangles; |
| 90 | }(); | 90 | }(); |
| 91 | info.tess_spacing = [&] { | 91 | info.tess_spacing = [&] { |
| @@ -97,7 +97,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, | |||
| 97 | case Maxwell::TessellationSpacing::FractionalEven: | 97 | case Maxwell::TessellationSpacing::FractionalEven: |
| 98 | return Shader::TessSpacing::FractionalEven; | 98 | return Shader::TessSpacing::FractionalEven; |
| 99 | } | 99 | } |
| 100 | UNREACHABLE(); | 100 | ASSERT(false); |
| 101 | return Shader::TessSpacing::Equal; | 101 | return Shader::TessSpacing::Equal; |
| 102 | }(); | 102 | }(); |
| 103 | break; | 103 | break; |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 29ff736fb..8c0fffc67 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -83,7 +83,7 @@ GLenum ImageTarget(const VideoCommon::ImageInfo& info) { | |||
| 83 | case ImageType::Buffer: | 83 | case ImageType::Buffer: |
| 84 | return GL_TEXTURE_BUFFER; | 84 | return GL_TEXTURE_BUFFER; |
| 85 | } | 85 | } |
| 86 | UNREACHABLE_MSG("Invalid image type={}", info.type); | 86 | ASSERT_MSG(false, "Invalid image type={}", info.type); |
| 87 | return GL_NONE; | 87 | return GL_NONE; |
| 88 | } | 88 | } |
| 89 | 89 | ||
| @@ -107,7 +107,7 @@ GLenum ImageTarget(Shader::TextureType type, int num_samples = 1) { | |||
| 107 | case Shader::TextureType::Buffer: | 107 | case Shader::TextureType::Buffer: |
| 108 | return GL_TEXTURE_BUFFER; | 108 | return GL_TEXTURE_BUFFER; |
| 109 | } | 109 | } |
| 110 | UNREACHABLE_MSG("Invalid image view type={}", type); | 110 | ASSERT_MSG(false, "Invalid image view type={}", type); |
| 111 | return GL_NONE; | 111 | return GL_NONE; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| @@ -119,7 +119,7 @@ GLenum TextureMode(PixelFormat format, bool is_first) { | |||
| 119 | case PixelFormat::S8_UINT_D24_UNORM: | 119 | case PixelFormat::S8_UINT_D24_UNORM: |
| 120 | return is_first ? GL_STENCIL_INDEX : GL_DEPTH_COMPONENT; | 120 | return is_first ? GL_STENCIL_INDEX : GL_DEPTH_COMPONENT; |
| 121 | default: | 121 | default: |
| 122 | UNREACHABLE(); | 122 | ASSERT(false); |
| 123 | return GL_DEPTH_COMPONENT; | 123 | return GL_DEPTH_COMPONENT; |
| 124 | } | 124 | } |
| 125 | } | 125 | } |
| @@ -140,7 +140,7 @@ GLint Swizzle(SwizzleSource source) { | |||
| 140 | case SwizzleSource::OneFloat: | 140 | case SwizzleSource::OneFloat: |
| 141 | return GL_ONE; | 141 | return GL_ONE; |
| 142 | } | 142 | } |
| 143 | UNREACHABLE_MSG("Invalid swizzle source={}", source); | 143 | ASSERT_MSG(false, "Invalid swizzle source={}", source); |
| 144 | return GL_NONE; | 144 | return GL_NONE; |
| 145 | } | 145 | } |
| 146 | 146 | ||
| @@ -197,7 +197,7 @@ GLint ConvertA5B5G5R1_UNORM(SwizzleSource source) { | |||
| 197 | case SwizzleSource::OneFloat: | 197 | case SwizzleSource::OneFloat: |
| 198 | return GL_ONE; | 198 | return GL_ONE; |
| 199 | } | 199 | } |
| 200 | UNREACHABLE_MSG("Invalid swizzle source={}", source); | 200 | ASSERT_MSG(false, "Invalid swizzle source={}", source); |
| 201 | return GL_NONE; | 201 | return GL_NONE; |
| 202 | } | 202 | } |
| 203 | 203 | ||
| @@ -381,10 +381,10 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form | |||
| 381 | glTextureStorage3D(handle, gl_num_levels, gl_internal_format, width, height, depth); | 381 | glTextureStorage3D(handle, gl_num_levels, gl_internal_format, width, height, depth); |
| 382 | break; | 382 | break; |
| 383 | case GL_TEXTURE_BUFFER: | 383 | case GL_TEXTURE_BUFFER: |
| 384 | UNREACHABLE(); | 384 | ASSERT(false); |
| 385 | break; | 385 | break; |
| 386 | default: | 386 | default: |
| 387 | UNREACHABLE_MSG("Invalid target=0x{:x}", target); | 387 | ASSERT_MSG(false, "Invalid target=0x{:x}", target); |
| 388 | break; | 388 | break; |
| 389 | } | 389 | } |
| 390 | return texture; | 390 | return texture; |
| @@ -420,7 +420,7 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form | |||
| 420 | case Shader::ImageFormat::R32G32B32A32_UINT: | 420 | case Shader::ImageFormat::R32G32B32A32_UINT: |
| 421 | return GL_RGBA32UI; | 421 | return GL_RGBA32UI; |
| 422 | } | 422 | } |
| 423 | UNREACHABLE_MSG("Invalid image format={}", format); | 423 | ASSERT_MSG(false, "Invalid image format={}", format); |
| 424 | return GL_R32UI; | 424 | return GL_R32UI; |
| 425 | } | 425 | } |
| 426 | 426 | ||
| @@ -579,7 +579,7 @@ void TextureCacheRuntime::EmulateCopyImage(Image& dst, Image& src, | |||
| 579 | } else if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) { | 579 | } else if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) { |
| 580 | format_conversion_pass.ConvertImage(dst, src, copies); | 580 | format_conversion_pass.ConvertImage(dst, src, copies); |
| 581 | } else { | 581 | } else { |
| 582 | UNREACHABLE(); | 582 | ASSERT(false); |
| 583 | } | 583 | } |
| 584 | } | 584 | } |
| 585 | 585 | ||
| @@ -620,7 +620,7 @@ void TextureCacheRuntime::AccelerateImageUpload(Image& image, const ImageBufferM | |||
| 620 | case ImageType::Linear: | 620 | case ImageType::Linear: |
| 621 | return util_shaders.PitchUpload(image, map, swizzles); | 621 | return util_shaders.PitchUpload(image, map, swizzles); |
| 622 | default: | 622 | default: |
| 623 | UNREACHABLE(); | 623 | ASSERT(false); |
| 624 | break; | 624 | break; |
| 625 | } | 625 | } |
| 626 | } | 626 | } |
| @@ -639,7 +639,7 @@ FormatProperties TextureCacheRuntime::FormatInfo(ImageType type, GLenum internal | |||
| 639 | case ImageType::e3D: | 639 | case ImageType::e3D: |
| 640 | return format_properties[2].at(internal_format); | 640 | return format_properties[2].at(internal_format); |
| 641 | default: | 641 | default: |
| 642 | UNREACHABLE(); | 642 | ASSERT(false); |
| 643 | return FormatProperties{}; | 643 | return FormatProperties{}; |
| 644 | } | 644 | } |
| 645 | } | 645 | } |
| @@ -888,7 +888,7 @@ void Image::CopyBufferToImage(const VideoCommon::BufferImageCopy& copy, size_t b | |||
| 888 | } | 888 | } |
| 889 | break; | 889 | break; |
| 890 | default: | 890 | default: |
| 891 | UNREACHABLE(); | 891 | ASSERT(false); |
| 892 | } | 892 | } |
| 893 | } | 893 | } |
| 894 | 894 | ||
| @@ -924,7 +924,7 @@ void Image::CopyImageToBuffer(const VideoCommon::BufferImageCopy& copy, size_t b | |||
| 924 | depth = copy.image_extent.depth; | 924 | depth = copy.image_extent.depth; |
| 925 | break; | 925 | break; |
| 926 | default: | 926 | default: |
| 927 | UNREACHABLE(); | 927 | ASSERT(false); |
| 928 | } | 928 | } |
| 929 | // Compressed formats don't have a pixel format or type | 929 | // Compressed formats don't have a pixel format or type |
| 930 | const bool is_compressed = gl_format == GL_NONE; | 930 | const bool is_compressed = gl_format == GL_NONE; |
| @@ -950,7 +950,7 @@ void Image::Scale(bool up_scale) { | |||
| 950 | case SurfaceType::DepthStencil: | 950 | case SurfaceType::DepthStencil: |
| 951 | return GL_DEPTH_STENCIL_ATTACHMENT; | 951 | return GL_DEPTH_STENCIL_ATTACHMENT; |
| 952 | default: | 952 | default: |
| 953 | UNREACHABLE(); | 953 | ASSERT(false); |
| 954 | return GL_COLOR_ATTACHMENT0; | 954 | return GL_COLOR_ATTACHMENT0; |
| 955 | } | 955 | } |
| 956 | }(); | 956 | }(); |
| @@ -965,7 +965,7 @@ void Image::Scale(bool up_scale) { | |||
| 965 | case SurfaceType::DepthStencil: | 965 | case SurfaceType::DepthStencil: |
| 966 | return GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; | 966 | return GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; |
| 967 | default: | 967 | default: |
| 968 | UNREACHABLE(); | 968 | ASSERT(false); |
| 969 | return GL_COLOR_BUFFER_BIT; | 969 | return GL_COLOR_BUFFER_BIT; |
| 970 | } | 970 | } |
| 971 | }(); | 971 | }(); |
| @@ -980,7 +980,7 @@ void Image::Scale(bool up_scale) { | |||
| 980 | case SurfaceType::DepthStencil: | 980 | case SurfaceType::DepthStencil: |
| 981 | return 3; | 981 | return 3; |
| 982 | default: | 982 | default: |
| 983 | UNREACHABLE(); | 983 | ASSERT(false); |
| 984 | return 0; | 984 | return 0; |
| 985 | } | 985 | } |
| 986 | }(); | 986 | }(); |
| @@ -1045,7 +1045,7 @@ bool Image::ScaleUp(bool ignore) { | |||
| 1045 | return false; | 1045 | return false; |
| 1046 | } | 1046 | } |
| 1047 | if (info.type == ImageType::Linear) { | 1047 | if (info.type == ImageType::Linear) { |
| 1048 | UNREACHABLE(); | 1048 | ASSERT(false); |
| 1049 | return false; | 1049 | return false; |
| 1050 | } | 1050 | } |
| 1051 | flags |= ImageFlagBits::Rescaled; | 1051 | flags |= ImageFlagBits::Rescaled; |
| @@ -1139,7 +1139,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI | |||
| 1139 | UNIMPLEMENTED(); | 1139 | UNIMPLEMENTED(); |
| 1140 | break; | 1140 | break; |
| 1141 | case ImageViewType::Buffer: | 1141 | case ImageViewType::Buffer: |
| 1142 | UNREACHABLE(); | 1142 | ASSERT(false); |
| 1143 | break; | 1143 | break; |
| 1144 | } | 1144 | } |
| 1145 | switch (info.type) { | 1145 | switch (info.type) { |
| @@ -1319,7 +1319,7 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM | |||
| 1319 | buffer_bits |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; | 1319 | buffer_bits |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; |
| 1320 | break; | 1320 | break; |
| 1321 | default: | 1321 | default: |
| 1322 | UNREACHABLE(); | 1322 | ASSERT(false); |
| 1323 | buffer_bits |= GL_DEPTH_BUFFER_BIT; | 1323 | buffer_bits |= GL_DEPTH_BUFFER_BIT; |
| 1324 | break; | 1324 | break; |
| 1325 | } | 1325 | } |
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index c2a6da5a7..644b60d73 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h | |||
| @@ -206,7 +206,7 @@ inline GLenum IndexFormat(Maxwell::IndexFormat index_format) { | |||
| 206 | case Maxwell::IndexFormat::UnsignedInt: | 206 | case Maxwell::IndexFormat::UnsignedInt: |
| 207 | return GL_UNSIGNED_INT; | 207 | return GL_UNSIGNED_INT; |
| 208 | } | 208 | } |
| 209 | UNREACHABLE_MSG("Invalid index_format={}", index_format); | 209 | ASSERT_MSG(false, "Invalid index_format={}", index_format); |
| 210 | return {}; | 210 | return {}; |
| 211 | } | 211 | } |
| 212 | 212 | ||
| @@ -243,7 +243,7 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) { | |||
| 243 | case Maxwell::PrimitiveTopology::Patches: | 243 | case Maxwell::PrimitiveTopology::Patches: |
| 244 | return GL_PATCHES; | 244 | return GL_PATCHES; |
| 245 | } | 245 | } |
| 246 | UNREACHABLE_MSG("Invalid topology={}", topology); | 246 | ASSERT_MSG(false, "Invalid topology={}", topology); |
| 247 | return GL_POINTS; | 247 | return GL_POINTS; |
| 248 | } | 248 | } |
| 249 | 249 | ||
| @@ -271,8 +271,8 @@ inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode, | |||
| 271 | } | 271 | } |
| 272 | break; | 272 | break; |
| 273 | } | 273 | } |
| 274 | UNREACHABLE_MSG("Invalid texture filter mode={} and mipmap filter mode={}", filter_mode, | 274 | ASSERT_MSG(false, "Invalid texture filter mode={} and mipmap filter mode={}", filter_mode, |
| 275 | mipmap_filter_mode); | 275 | mipmap_filter_mode); |
| 276 | return GL_NEAREST; | 276 | return GL_NEAREST; |
| 277 | } | 277 | } |
| 278 | 278 | ||
| @@ -550,7 +550,7 @@ inline GLenum PolygonMode(Maxwell::PolygonMode polygon_mode) { | |||
| 550 | case Maxwell::PolygonMode::Fill: | 550 | case Maxwell::PolygonMode::Fill: |
| 551 | return GL_FILL; | 551 | return GL_FILL; |
| 552 | } | 552 | } |
| 553 | UNREACHABLE_MSG("Invalid polygon mode={}", polygon_mode); | 553 | ASSERT_MSG(false, "Invalid polygon mode={}", polygon_mode); |
| 554 | return GL_FILL; | 554 | return GL_FILL; |
| 555 | } | 555 | } |
| 556 | 556 | ||
| @@ -563,7 +563,7 @@ inline GLenum ReductionFilter(Tegra::Texture::SamplerReduction filter) { | |||
| 563 | case Tegra::Texture::SamplerReduction::Max: | 563 | case Tegra::Texture::SamplerReduction::Max: |
| 564 | return GL_MAX; | 564 | return GL_MAX; |
| 565 | } | 565 | } |
| 566 | UNREACHABLE_MSG("Invalid reduction filter={}", static_cast<int>(filter)); | 566 | ASSERT_MSG(false, "Invalid reduction filter={}", static_cast<int>(filter)); |
| 567 | return GL_WEIGHTED_AVERAGE_ARB; | 567 | return GL_WEIGHTED_AVERAGE_ARB; |
| 568 | } | 568 | } |
| 569 | 569 | ||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 3a3c213bb..9a9243544 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -79,7 +79,7 @@ const char* GetSource(GLenum source) { | |||
| 79 | case GL_DEBUG_SOURCE_OTHER: | 79 | case GL_DEBUG_SOURCE_OTHER: |
| 80 | return "OTHER"; | 80 | return "OTHER"; |
| 81 | default: | 81 | default: |
| 82 | UNREACHABLE(); | 82 | ASSERT(false); |
| 83 | return "Unknown source"; | 83 | return "Unknown source"; |
| 84 | } | 84 | } |
| 85 | } | 85 | } |
| @@ -101,7 +101,7 @@ const char* GetType(GLenum type) { | |||
| 101 | case GL_DEBUG_TYPE_MARKER: | 101 | case GL_DEBUG_TYPE_MARKER: |
| 102 | return "MARKER"; | 102 | return "MARKER"; |
| 103 | default: | 103 | default: |
| 104 | UNREACHABLE(); | 104 | ASSERT(false); |
| 105 | return "Unknown type"; | 105 | return "Unknown type"; |
| 106 | } | 106 | } |
| 107 | } | 107 | } |
diff --git a/src/video_core/renderer_opengl/util_shaders.cpp b/src/video_core/renderer_opengl/util_shaders.cpp index 837825737..404def62e 100644 --- a/src/video_core/renderer_opengl/util_shaders.cpp +++ b/src/video_core/renderer_opengl/util_shaders.cpp | |||
| @@ -282,7 +282,7 @@ GLenum StoreFormat(u32 bytes_per_block) { | |||
| 282 | case 16: | 282 | case 16: |
| 283 | return GL_RGBA32UI; | 283 | return GL_RGBA32UI; |
| 284 | } | 284 | } |
| 285 | UNREACHABLE(); | 285 | ASSERT(false); |
| 286 | return GL_R8UI; | 286 | return GL_R8UI; |
| 287 | } | 287 | } |
| 288 | 288 | ||
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index ea360f339..193cbe15e 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp | |||
| @@ -25,7 +25,7 @@ VkFilter Filter(Tegra::Texture::TextureFilter filter) { | |||
| 25 | case Tegra::Texture::TextureFilter::Linear: | 25 | case Tegra::Texture::TextureFilter::Linear: |
| 26 | return VK_FILTER_LINEAR; | 26 | return VK_FILTER_LINEAR; |
| 27 | } | 27 | } |
| 28 | UNREACHABLE_MSG("Invalid sampler filter={}", filter); | 28 | ASSERT_MSG(false, "Invalid sampler filter={}", filter); |
| 29 | return {}; | 29 | return {}; |
| 30 | } | 30 | } |
| 31 | 31 | ||
| @@ -42,7 +42,7 @@ VkSamplerMipmapMode MipmapMode(Tegra::Texture::TextureMipmapFilter mipmap_filter | |||
| 42 | case Tegra::Texture::TextureMipmapFilter::Linear: | 42 | case Tegra::Texture::TextureMipmapFilter::Linear: |
| 43 | return VK_SAMPLER_MIPMAP_MODE_LINEAR; | 43 | return VK_SAMPLER_MIPMAP_MODE_LINEAR; |
| 44 | } | 44 | } |
| 45 | UNREACHABLE_MSG("Invalid sampler mipmap mode={}", mipmap_filter); | 45 | ASSERT_MSG(false, "Invalid sampler mipmap mode={}", mipmap_filter); |
| 46 | return {}; | 46 | return {}; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| @@ -70,7 +70,7 @@ VkSamplerAddressMode WrapMode(const Device& device, Tegra::Texture::WrapMode wra | |||
| 70 | case Tegra::Texture::TextureFilter::Linear: | 70 | case Tegra::Texture::TextureFilter::Linear: |
| 71 | return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; | 71 | return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; |
| 72 | } | 72 | } |
| 73 | UNREACHABLE(); | 73 | ASSERT(false); |
| 74 | return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; | 74 | return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; |
| 75 | case Tegra::Texture::WrapMode::MirrorOnceClampToEdge: | 75 | case Tegra::Texture::WrapMode::MirrorOnceClampToEdge: |
| 76 | return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; | 76 | return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; |
| @@ -744,7 +744,7 @@ VkViewportCoordinateSwizzleNV ViewportSwizzle(Maxwell::ViewportSwizzle swizzle) | |||
| 744 | case Maxwell::ViewportSwizzle::NegativeW: | 744 | case Maxwell::ViewportSwizzle::NegativeW: |
| 745 | return VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV; | 745 | return VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV; |
| 746 | } | 746 | } |
| 747 | UNREACHABLE_MSG("Invalid swizzle={}", swizzle); | 747 | ASSERT_MSG(false, "Invalid swizzle={}", swizzle); |
| 748 | return {}; | 748 | return {}; |
| 749 | } | 749 | } |
| 750 | 750 | ||
| @@ -757,7 +757,7 @@ VkSamplerReductionMode SamplerReduction(Tegra::Texture::SamplerReduction reducti | |||
| 757 | case Tegra::Texture::SamplerReduction::Max: | 757 | case Tegra::Texture::SamplerReduction::Max: |
| 758 | return VK_SAMPLER_REDUCTION_MODE_MAX_EXT; | 758 | return VK_SAMPLER_REDUCTION_MODE_MAX_EXT; |
| 759 | } | 759 | } |
| 760 | UNREACHABLE_MSG("Invalid sampler mode={}", static_cast<int>(reduction)); | 760 | ASSERT_MSG(false, "Invalid sampler mode={}", static_cast<int>(reduction)); |
| 761 | return VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT; | 761 | return VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT; |
| 762 | } | 762 | } |
| 763 | 763 | ||
| @@ -780,7 +780,7 @@ VkSampleCountFlagBits MsaaMode(Tegra::Texture::MsaaMode msaa_mode) { | |||
| 780 | case Tegra::Texture::MsaaMode::Msaa4x4: | 780 | case Tegra::Texture::MsaaMode::Msaa4x4: |
| 781 | return VK_SAMPLE_COUNT_16_BIT; | 781 | return VK_SAMPLE_COUNT_16_BIT; |
| 782 | default: | 782 | default: |
| 783 | UNREACHABLE_MSG("Invalid msaa_mode={}", static_cast<int>(msaa_mode)); | 783 | ASSERT_MSG(false, "Invalid msaa_mode={}", static_cast<int>(msaa_mode)); |
| 784 | return VK_SAMPLE_COUNT_1_BIT; | 784 | return VK_SAMPLE_COUNT_1_BIT; |
| 785 | } | 785 | } |
| 786 | } | 786 | } |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 0aeb37538..450905197 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -46,7 +46,7 @@ size_t BytesPerIndex(VkIndexType index_type) { | |||
| 46 | case VK_INDEX_TYPE_UINT32: | 46 | case VK_INDEX_TYPE_UINT32: |
| 47 | return 4; | 47 | return 4; |
| 48 | default: | 48 | default: |
| 49 | UNREACHABLE_MSG("Invalid index type={}", index_type); | 49 | ASSERT_MSG(false, "Invalid index type={}", index_type); |
| 50 | return 1; | 50 | return 1; |
| 51 | } | 51 | } |
| 52 | } | 52 | } |
| @@ -366,7 +366,7 @@ void BufferCacheRuntime::ReserveQuadArrayLUT(u32 num_indices, bool wait_for_idle | |||
| 366 | std::memcpy(staging_data, MakeQuadIndices<u32>(quad, first).data(), quad_size); | 366 | std::memcpy(staging_data, MakeQuadIndices<u32>(quad, first).data(), quad_size); |
| 367 | break; | 367 | break; |
| 368 | default: | 368 | default: |
| 369 | UNREACHABLE(); | 369 | ASSERT(false); |
| 370 | break; | 370 | break; |
| 371 | } | 371 | } |
| 372 | staging_data += quad_size; | 372 | staging_data += quad_size; |
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 29481a102..4cba777e6 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp | |||
| @@ -265,7 +265,7 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble( | |||
| 265 | case Tegra::Engines::Maxwell3D::Regs::IndexFormat::UnsignedInt: | 265 | case Tegra::Engines::Maxwell3D::Regs::IndexFormat::UnsignedInt: |
| 266 | return 2; | 266 | return 2; |
| 267 | } | 267 | } |
| 268 | UNREACHABLE(); | 268 | ASSERT(false); |
| 269 | return 2; | 269 | return 2; |
| 270 | }(); | 270 | }(); |
| 271 | const u32 input_size = num_vertices << index_shift; | 271 | const u32 input_size = num_vertices << index_shift; |
| @@ -328,31 +328,32 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map, | |||
| 328 | const VkImageAspectFlags aspect_mask = image.AspectMask(); | 328 | const VkImageAspectFlags aspect_mask = image.AspectMask(); |
| 329 | const VkImage vk_image = image.Handle(); | 329 | const VkImage vk_image = image.Handle(); |
| 330 | const bool is_initialized = image.ExchangeInitialization(); | 330 | const bool is_initialized = image.ExchangeInitialization(); |
| 331 | scheduler.Record( | 331 | scheduler.Record([vk_pipeline, vk_image, aspect_mask, |
| 332 | [vk_pipeline, vk_image, aspect_mask, is_initialized](vk::CommandBuffer cmdbuf) { | 332 | is_initialized](vk::CommandBuffer cmdbuf) { |
| 333 | const VkImageMemoryBarrier image_barrier{ | 333 | const VkImageMemoryBarrier image_barrier{ |
| 334 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | 334 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| 335 | .pNext = nullptr, | 335 | .pNext = nullptr, |
| 336 | .srcAccessMask = is_initialized ? VK_ACCESS_SHADER_WRITE_BIT : VkAccessFlags{}, | 336 | .srcAccessMask = static_cast<VkAccessFlags>(is_initialized ? VK_ACCESS_SHADER_WRITE_BIT |
| 337 | .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, | 337 | : VK_ACCESS_NONE), |
| 338 | .oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED, | 338 | .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, |
| 339 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | 339 | .oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED, |
| 340 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 340 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, |
| 341 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 341 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 342 | .image = vk_image, | 342 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 343 | .subresourceRange{ | 343 | .image = vk_image, |
| 344 | .aspectMask = aspect_mask, | 344 | .subresourceRange{ |
| 345 | .baseMipLevel = 0, | 345 | .aspectMask = aspect_mask, |
| 346 | .levelCount = VK_REMAINING_MIP_LEVELS, | 346 | .baseMipLevel = 0, |
| 347 | .baseArrayLayer = 0, | 347 | .levelCount = VK_REMAINING_MIP_LEVELS, |
| 348 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | 348 | .baseArrayLayer = 0, |
| 349 | }, | 349 | .layerCount = VK_REMAINING_ARRAY_LAYERS, |
| 350 | }; | 350 | }, |
| 351 | cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT | 351 | }; |
| 352 | : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, | 352 | cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT |
| 353 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier); | 353 | : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, |
| 354 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline); | 354 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier); |
| 355 | }); | 355 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline); |
| 356 | }); | ||
| 356 | for (const VideoCommon::SwizzleParameters& swizzle : swizzles) { | 357 | for (const VideoCommon::SwizzleParameters& swizzle : swizzles) { |
| 357 | const size_t input_offset = swizzle.buffer_offset + map.offset; | 358 | const size_t input_offset = swizzle.buffer_offset + map.offset; |
| 358 | const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 8U); | 359 | const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 8U); |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 5196bdcf2..978e827f5 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -174,7 +174,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program | |||
| 174 | case Maxwell::TessellationPrimitive::Quads: | 174 | case Maxwell::TessellationPrimitive::Quads: |
| 175 | return Shader::TessPrimitive::Quads; | 175 | return Shader::TessPrimitive::Quads; |
| 176 | } | 176 | } |
| 177 | UNREACHABLE(); | 177 | ASSERT(false); |
| 178 | return Shader::TessPrimitive::Triangles; | 178 | return Shader::TessPrimitive::Triangles; |
| 179 | }(); | 179 | }(); |
| 180 | info.tess_spacing = [&] { | 180 | info.tess_spacing = [&] { |
| @@ -187,7 +187,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program | |||
| 187 | case Maxwell::TessellationSpacing::FractionalEven: | 187 | case Maxwell::TessellationSpacing::FractionalEven: |
| 188 | return Shader::TessSpacing::FractionalEven; | 188 | return Shader::TessSpacing::FractionalEven; |
| 189 | } | 189 | } |
| 190 | UNREACHABLE(); | 190 | ASSERT(false); |
| 191 | return Shader::TessSpacing::Equal; | 191 | return Shader::TessSpacing::Equal; |
| 192 | }(); | 192 | }(); |
| 193 | break; | 193 | break; |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index fd27581ce..ce6c853c1 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -784,8 +784,8 @@ void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs) | |||
| 784 | }); | 784 | }); |
| 785 | } else { | 785 | } else { |
| 786 | // Front face defines both faces | 786 | // Front face defines both faces |
| 787 | scheduler.Record([ref = regs.stencil_back_func_ref, write_mask = regs.stencil_back_mask, | 787 | scheduler.Record([ref = regs.stencil_front_func_ref, write_mask = regs.stencil_front_mask, |
| 788 | test_mask = regs.stencil_back_func_mask](vk::CommandBuffer cmdbuf) { | 788 | test_mask = regs.stencil_front_func_mask](vk::CommandBuffer cmdbuf) { |
| 789 | cmdbuf.SetStencilReference(VK_STENCIL_FACE_FRONT_AND_BACK, ref); | 789 | cmdbuf.SetStencilReference(VK_STENCIL_FACE_FRONT_AND_BACK, ref); |
| 790 | cmdbuf.SetStencilWriteMask(VK_STENCIL_FACE_FRONT_AND_BACK, write_mask); | 790 | cmdbuf.SetStencilWriteMask(VK_STENCIL_FACE_FRONT_AND_BACK, write_mask); |
| 791 | cmdbuf.SetStencilCompareMask(VK_STENCIL_FACE_FRONT_AND_BACK, test_mask); | 791 | cmdbuf.SetStencilCompareMask(VK_STENCIL_FACE_FRONT_AND_BACK, test_mask); |
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 31ce2f815..9a6afaca6 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp | |||
| @@ -263,7 +263,7 @@ StagingBufferPool::StagingBuffersCache& StagingBufferPool::GetCache(MemoryUsage | |||
| 263 | case MemoryUsage::Download: | 263 | case MemoryUsage::Download: |
| 264 | return download_cache; | 264 | return download_cache; |
| 265 | default: | 265 | default: |
| 266 | UNREACHABLE_MSG("Invalid memory usage={}", usage); | 266 | ASSERT_MSG(false, "Invalid memory usage={}", usage); |
| 267 | return upload_cache; | 267 | return upload_cache; |
| 268 | } | 268 | } |
| 269 | } | 269 | } |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 353594293..43ecb9647 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -70,7 +70,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 70 | case ImageType::Buffer: | 70 | case ImageType::Buffer: |
| 71 | break; | 71 | break; |
| 72 | } | 72 | } |
| 73 | UNREACHABLE_MSG("Invalid image type={}", type); | 73 | ASSERT_MSG(false, "Invalid image type={}", type); |
| 74 | return {}; | 74 | return {}; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| @@ -87,7 +87,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 87 | case 16: | 87 | case 16: |
| 88 | return VK_SAMPLE_COUNT_16_BIT; | 88 | return VK_SAMPLE_COUNT_16_BIT; |
| 89 | default: | 89 | default: |
| 90 | UNREACHABLE_MSG("Invalid number of samples={}", num_samples); | 90 | ASSERT_MSG(false, "Invalid number of samples={}", num_samples); |
| 91 | return VK_SAMPLE_COUNT_1_BIT; | 91 | return VK_SAMPLE_COUNT_1_BIT; |
| 92 | } | 92 | } |
| 93 | } | 93 | } |
| @@ -107,7 +107,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 107 | usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; | 107 | usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; |
| 108 | break; | 108 | break; |
| 109 | default: | 109 | default: |
| 110 | UNREACHABLE_MSG("Invalid surface type"); | 110 | ASSERT_MSG(false, "Invalid surface type"); |
| 111 | } | 111 | } |
| 112 | } | 112 | } |
| 113 | if (info.storage) { | 113 | if (info.storage) { |
| @@ -179,7 +179,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 179 | case VideoCore::Surface::SurfaceType::DepthStencil: | 179 | case VideoCore::Surface::SurfaceType::DepthStencil: |
| 180 | return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; | 180 | return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; |
| 181 | default: | 181 | default: |
| 182 | UNREACHABLE_MSG("Invalid surface type"); | 182 | ASSERT_MSG(false, "Invalid surface type"); |
| 183 | return VkImageAspectFlags{}; | 183 | return VkImageAspectFlags{}; |
| 184 | } | 184 | } |
| 185 | } | 185 | } |
| @@ -221,7 +221,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 221 | case SwizzleSource::OneInt: | 221 | case SwizzleSource::OneInt: |
| 222 | return VK_COMPONENT_SWIZZLE_ONE; | 222 | return VK_COMPONENT_SWIZZLE_ONE; |
| 223 | } | 223 | } |
| 224 | UNREACHABLE_MSG("Invalid swizzle={}", swizzle); | 224 | ASSERT_MSG(false, "Invalid swizzle={}", swizzle); |
| 225 | return VK_COMPONENT_SWIZZLE_ZERO; | 225 | return VK_COMPONENT_SWIZZLE_ZERO; |
| 226 | } | 226 | } |
| 227 | 227 | ||
| @@ -242,10 +242,10 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 242 | case Shader::TextureType::ColorArrayCube: | 242 | case Shader::TextureType::ColorArrayCube: |
| 243 | return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; | 243 | return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; |
| 244 | case Shader::TextureType::Buffer: | 244 | case Shader::TextureType::Buffer: |
| 245 | UNREACHABLE_MSG("Texture buffers can't be image views"); | 245 | ASSERT_MSG(false, "Texture buffers can't be image views"); |
| 246 | return VK_IMAGE_VIEW_TYPE_1D; | 246 | return VK_IMAGE_VIEW_TYPE_1D; |
| 247 | } | 247 | } |
| 248 | UNREACHABLE_MSG("Invalid image view type={}", type); | 248 | ASSERT_MSG(false, "Invalid image view type={}", type); |
| 249 | return VK_IMAGE_VIEW_TYPE_2D; | 249 | return VK_IMAGE_VIEW_TYPE_2D; |
| 250 | } | 250 | } |
| 251 | 251 | ||
| @@ -269,10 +269,10 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 269 | UNIMPLEMENTED_MSG("Rect image view"); | 269 | UNIMPLEMENTED_MSG("Rect image view"); |
| 270 | return VK_IMAGE_VIEW_TYPE_2D; | 270 | return VK_IMAGE_VIEW_TYPE_2D; |
| 271 | case VideoCommon::ImageViewType::Buffer: | 271 | case VideoCommon::ImageViewType::Buffer: |
| 272 | UNREACHABLE_MSG("Texture buffers can't be image views"); | 272 | ASSERT_MSG(false, "Texture buffers can't be image views"); |
| 273 | return VK_IMAGE_VIEW_TYPE_1D; | 273 | return VK_IMAGE_VIEW_TYPE_1D; |
| 274 | } | 274 | } |
| 275 | UNREACHABLE_MSG("Invalid image view type={}", type); | 275 | ASSERT_MSG(false, "Invalid image view type={}", type); |
| 276 | return VK_IMAGE_VIEW_TYPE_2D; | 276 | return VK_IMAGE_VIEW_TYPE_2D; |
| 277 | } | 277 | } |
| 278 | 278 | ||
| @@ -644,7 +644,7 @@ struct RangedBarrierRange { | |||
| 644 | case Shader::ImageFormat::R32G32B32A32_UINT: | 644 | case Shader::ImageFormat::R32G32B32A32_UINT: |
| 645 | return VK_FORMAT_R32G32B32A32_UINT; | 645 | return VK_FORMAT_R32G32B32A32_UINT; |
| 646 | } | 646 | } |
| 647 | UNREACHABLE_MSG("Invalid image format={}", format); | 647 | ASSERT_MSG(false, "Invalid image format={}", format); |
| 648 | return VK_FORMAT_R32_UINT; | 648 | return VK_FORMAT_R32_UINT; |
| 649 | } | 649 | } |
| 650 | 650 | ||
| @@ -1596,7 +1596,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI | |||
| 1596 | UNIMPLEMENTED(); | 1596 | UNIMPLEMENTED(); |
| 1597 | break; | 1597 | break; |
| 1598 | case VideoCommon::ImageViewType::Buffer: | 1598 | case VideoCommon::ImageViewType::Buffer: |
| 1599 | UNREACHABLE(); | 1599 | ASSERT(false); |
| 1600 | break; | 1600 | break; |
| 1601 | } | 1601 | } |
| 1602 | } | 1602 | } |
| @@ -1822,7 +1822,7 @@ void TextureCacheRuntime::AccelerateImageUpload( | |||
| 1822 | if (IsPixelFormatASTC(image.info.format)) { | 1822 | if (IsPixelFormatASTC(image.info.format)) { |
| 1823 | return astc_decoder_pass.Assemble(image, map, swizzles); | 1823 | return astc_decoder_pass.Assemble(image, map, swizzles); |
| 1824 | } | 1824 | } |
| 1825 | UNREACHABLE(); | 1825 | ASSERT(false); |
| 1826 | } | 1826 | } |
| 1827 | 1827 | ||
| 1828 | } // namespace Vulkan | 1828 | } // namespace Vulkan |
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp index d469964f6..c4e923bbf 100644 --- a/src/video_core/shader_environment.cpp +++ b/src/video_core/shader_environment.cpp | |||
| @@ -280,7 +280,7 @@ GraphicsEnvironment::GraphicsEnvironment(Tegra::Engines::Maxwell3D& maxwell3d_, | |||
| 280 | stage_index = 4; | 280 | stage_index = 4; |
| 281 | break; | 281 | break; |
| 282 | default: | 282 | default: |
| 283 | UNREACHABLE_MSG("Invalid program={}", program); | 283 | ASSERT_MSG(false, "Invalid program={}", program); |
| 284 | break; | 284 | break; |
| 285 | } | 285 | } |
| 286 | const u64 local_size{sph.LocalMemorySize()}; | 286 | const u64 local_size{sph.LocalMemorySize()}; |
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index 5f428d35d..69c1b1e6d 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp | |||
| @@ -29,7 +29,7 @@ SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_t | |||
| 29 | return SurfaceTarget::Texture2DArray; | 29 | return SurfaceTarget::Texture2DArray; |
| 30 | default: | 30 | default: |
| 31 | LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", texture_type); | 31 | LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", texture_type); |
| 32 | UNREACHABLE(); | 32 | ASSERT(false); |
| 33 | return SurfaceTarget::Texture2D; | 33 | return SurfaceTarget::Texture2D; |
| 34 | } | 34 | } |
| 35 | } | 35 | } |
| @@ -48,7 +48,7 @@ bool SurfaceTargetIsLayered(SurfaceTarget target) { | |||
| 48 | return true; | 48 | return true; |
| 49 | default: | 49 | default: |
| 50 | LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", target); | 50 | LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", target); |
| 51 | UNREACHABLE(); | 51 | ASSERT(false); |
| 52 | return false; | 52 | return false; |
| 53 | } | 53 | } |
| 54 | } | 54 | } |
| @@ -67,7 +67,7 @@ bool SurfaceTargetIsArray(SurfaceTarget target) { | |||
| 67 | return true; | 67 | return true; |
| 68 | default: | 68 | default: |
| 69 | LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", target); | 69 | LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", target); |
| 70 | UNREACHABLE(); | 70 | ASSERT(false); |
| 71 | return false; | 71 | return false; |
| 72 | } | 72 | } |
| 73 | } | 73 | } |
diff --git a/src/video_core/surface.h b/src/video_core/surface.h index 86fea61ae..75e055592 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h | |||
| @@ -147,7 +147,7 @@ enum class SurfaceTarget { | |||
| 147 | TextureCubeArray, | 147 | TextureCubeArray, |
| 148 | }; | 148 | }; |
| 149 | 149 | ||
| 150 | constexpr std::array<u32, MaxPixelFormat> BLOCK_WIDTH_TABLE = {{ | 150 | constexpr std::array<u8, MaxPixelFormat> BLOCK_WIDTH_TABLE = {{ |
| 151 | 1, // A8B8G8R8_UNORM | 151 | 1, // A8B8G8R8_UNORM |
| 152 | 1, // A8B8G8R8_SNORM | 152 | 1, // A8B8G8R8_SNORM |
| 153 | 1, // A8B8G8R8_SINT | 153 | 1, // A8B8G8R8_SINT |
| @@ -249,7 +249,7 @@ constexpr u32 DefaultBlockWidth(PixelFormat format) { | |||
| 249 | return BLOCK_WIDTH_TABLE[static_cast<std::size_t>(format)]; | 249 | return BLOCK_WIDTH_TABLE[static_cast<std::size_t>(format)]; |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | constexpr std::array<u32, MaxPixelFormat> BLOCK_HEIGHT_TABLE = {{ | 252 | constexpr std::array<u8, MaxPixelFormat> BLOCK_HEIGHT_TABLE = {{ |
| 253 | 1, // A8B8G8R8_UNORM | 253 | 1, // A8B8G8R8_UNORM |
| 254 | 1, // A8B8G8R8_SNORM | 254 | 1, // A8B8G8R8_SNORM |
| 255 | 1, // A8B8G8R8_SINT | 255 | 1, // A8B8G8R8_SINT |
| @@ -351,7 +351,7 @@ constexpr u32 DefaultBlockHeight(PixelFormat format) { | |||
| 351 | return BLOCK_HEIGHT_TABLE[static_cast<std::size_t>(format)]; | 351 | return BLOCK_HEIGHT_TABLE[static_cast<std::size_t>(format)]; |
| 352 | } | 352 | } |
| 353 | 353 | ||
| 354 | constexpr std::array<u32, MaxPixelFormat> BITS_PER_BLOCK_TABLE = {{ | 354 | constexpr std::array<u8, MaxPixelFormat> BITS_PER_BLOCK_TABLE = {{ |
| 355 | 32, // A8B8G8R8_UNORM | 355 | 32, // A8B8G8R8_UNORM |
| 356 | 32, // A8B8G8R8_SNORM | 356 | 32, // A8B8G8R8_SNORM |
| 357 | 32, // A8B8G8R8_SINT | 357 | 32, // A8B8G8R8_SINT |
diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp index 802939f6c..6c073ee57 100644 --- a/src/video_core/texture_cache/image_info.cpp +++ b/src/video_core/texture_cache/image_info.cpp | |||
| @@ -94,7 +94,7 @@ ImageInfo::ImageInfo(const TICEntry& config) noexcept { | |||
| 94 | resources.layers = 1; | 94 | resources.layers = 1; |
| 95 | break; | 95 | break; |
| 96 | default: | 96 | default: |
| 97 | UNREACHABLE_MSG("Invalid texture_type={}", static_cast<int>(config.texture_type.Value())); | 97 | ASSERT_MSG(false, "Invalid texture_type={}", static_cast<int>(config.texture_type.Value())); |
| 98 | break; | 98 | break; |
| 99 | } | 99 | } |
| 100 | if (type != ImageType::Linear) { | 100 | if (type != ImageType::Linear) { |
diff --git a/src/video_core/texture_cache/image_view_info.cpp b/src/video_core/texture_cache/image_view_info.cpp index 0cee5e45f..f47885147 100644 --- a/src/video_core/texture_cache/image_view_info.cpp +++ b/src/video_core/texture_cache/image_view_info.cpp | |||
| @@ -71,7 +71,7 @@ ImageViewInfo::ImageViewInfo(const TICEntry& config, s32 base_layer) noexcept | |||
| 71 | range.extent.layers = config.Depth() * 6; | 71 | range.extent.layers = config.Depth() * 6; |
| 72 | break; | 72 | break; |
| 73 | default: | 73 | default: |
| 74 | UNREACHABLE_MSG("Invalid texture_type={}", static_cast<int>(config.texture_type.Value())); | 74 | ASSERT_MSG(false, "Invalid texture_type={}", static_cast<int>(config.texture_type.Value())); |
| 75 | break; | 75 | break; |
| 76 | } | 76 | } |
| 77 | } | 77 | } |
diff --git a/src/video_core/texture_cache/samples_helper.h b/src/video_core/texture_cache/samples_helper.h index 91fec60bd..d552bccf0 100644 --- a/src/video_core/texture_cache/samples_helper.h +++ b/src/video_core/texture_cache/samples_helper.h | |||
| @@ -23,7 +23,7 @@ namespace VideoCommon { | |||
| 23 | case 16: | 23 | case 16: |
| 24 | return {2, 2}; | 24 | return {2, 2}; |
| 25 | } | 25 | } |
| 26 | UNREACHABLE_MSG("Invalid number of samples={}", num_samples); | 26 | ASSERT_MSG(false, "Invalid number of samples={}", num_samples); |
| 27 | return {1, 1}; | 27 | return {1, 1}; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| @@ -47,7 +47,7 @@ namespace VideoCommon { | |||
| 47 | case MsaaMode::Msaa4x4: | 47 | case MsaaMode::Msaa4x4: |
| 48 | return 16; | 48 | return 16; |
| 49 | } | 49 | } |
| 50 | UNREACHABLE_MSG("Invalid MSAA mode={}", static_cast<int>(msaa_mode)); | 50 | ASSERT_MSG(false, "Invalid MSAA mode={}", static_cast<int>(msaa_mode)); |
| 51 | return 1; | 51 | return 1; |
| 52 | } | 52 | } |
| 53 | 53 | ||
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 6622d7818..cf3ca06a6 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -1485,14 +1485,14 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) { | |||
| 1485 | std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>>& selected_page_table) { | 1485 | std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>>& selected_page_table) { |
| 1486 | const auto page_it = selected_page_table.find(page); | 1486 | const auto page_it = selected_page_table.find(page); |
| 1487 | if (page_it == selected_page_table.end()) { | 1487 | if (page_it == selected_page_table.end()) { |
| 1488 | UNREACHABLE_MSG("Unregistering unregistered page=0x{:x}", page << PAGE_BITS); | 1488 | ASSERT_MSG(false, "Unregistering unregistered page=0x{:x}", page << PAGE_BITS); |
| 1489 | return; | 1489 | return; |
| 1490 | } | 1490 | } |
| 1491 | std::vector<ImageId>& image_ids = page_it->second; | 1491 | std::vector<ImageId>& image_ids = page_it->second; |
| 1492 | const auto vector_it = std::ranges::find(image_ids, image_id); | 1492 | const auto vector_it = std::ranges::find(image_ids, image_id); |
| 1493 | if (vector_it == image_ids.end()) { | 1493 | if (vector_it == image_ids.end()) { |
| 1494 | UNREACHABLE_MSG("Unregistering unregistered image in page=0x{:x}", | 1494 | ASSERT_MSG(false, "Unregistering unregistered image in page=0x{:x}", |
| 1495 | page << PAGE_BITS); | 1495 | page << PAGE_BITS); |
| 1496 | return; | 1496 | return; |
| 1497 | } | 1497 | } |
| 1498 | image_ids.erase(vector_it); | 1498 | image_ids.erase(vector_it); |
| @@ -1504,14 +1504,14 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) { | |||
| 1504 | ForEachCPUPage(image.cpu_addr, image.guest_size_bytes, [this, map_id](u64 page) { | 1504 | ForEachCPUPage(image.cpu_addr, image.guest_size_bytes, [this, map_id](u64 page) { |
| 1505 | const auto page_it = page_table.find(page); | 1505 | const auto page_it = page_table.find(page); |
| 1506 | if (page_it == page_table.end()) { | 1506 | if (page_it == page_table.end()) { |
| 1507 | UNREACHABLE_MSG("Unregistering unregistered page=0x{:x}", page << PAGE_BITS); | 1507 | ASSERT_MSG(false, "Unregistering unregistered page=0x{:x}", page << PAGE_BITS); |
| 1508 | return; | 1508 | return; |
| 1509 | } | 1509 | } |
| 1510 | std::vector<ImageMapId>& image_map_ids = page_it->second; | 1510 | std::vector<ImageMapId>& image_map_ids = page_it->second; |
| 1511 | const auto vector_it = std::ranges::find(image_map_ids, map_id); | 1511 | const auto vector_it = std::ranges::find(image_map_ids, map_id); |
| 1512 | if (vector_it == image_map_ids.end()) { | 1512 | if (vector_it == image_map_ids.end()) { |
| 1513 | UNREACHABLE_MSG("Unregistering unregistered image in page=0x{:x}", | 1513 | ASSERT_MSG(false, "Unregistering unregistered image in page=0x{:x}", |
| 1514 | page << PAGE_BITS); | 1514 | page << PAGE_BITS); |
| 1515 | return; | 1515 | return; |
| 1516 | } | 1516 | } |
| 1517 | image_map_ids.erase(vector_it); | 1517 | image_map_ids.erase(vector_it); |
| @@ -1532,7 +1532,7 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) { | |||
| 1532 | ForEachCPUPage(cpu_addr, size, [this, image_id](u64 page) { | 1532 | ForEachCPUPage(cpu_addr, size, [this, image_id](u64 page) { |
| 1533 | const auto page_it = page_table.find(page); | 1533 | const auto page_it = page_table.find(page); |
| 1534 | if (page_it == page_table.end()) { | 1534 | if (page_it == page_table.end()) { |
| 1535 | UNREACHABLE_MSG("Unregistering unregistered page=0x{:x}", page << PAGE_BITS); | 1535 | ASSERT_MSG(false, "Unregistering unregistered page=0x{:x}", page << PAGE_BITS); |
| 1536 | return; | 1536 | return; |
| 1537 | } | 1537 | } |
| 1538 | std::vector<ImageMapId>& image_map_ids = page_it->second; | 1538 | std::vector<ImageMapId>& image_map_ids = page_it->second; |
| @@ -1616,15 +1616,15 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) { | |||
| 1616 | const GPUVAddr gpu_addr = image.gpu_addr; | 1616 | const GPUVAddr gpu_addr = image.gpu_addr; |
| 1617 | const auto alloc_it = image_allocs_table.find(gpu_addr); | 1617 | const auto alloc_it = image_allocs_table.find(gpu_addr); |
| 1618 | if (alloc_it == image_allocs_table.end()) { | 1618 | if (alloc_it == image_allocs_table.end()) { |
| 1619 | UNREACHABLE_MSG("Trying to delete an image alloc that does not exist in address 0x{:x}", | 1619 | ASSERT_MSG(false, "Trying to delete an image alloc that does not exist in address 0x{:x}", |
| 1620 | gpu_addr); | 1620 | gpu_addr); |
| 1621 | return; | 1621 | return; |
| 1622 | } | 1622 | } |
| 1623 | const ImageAllocId alloc_id = alloc_it->second; | 1623 | const ImageAllocId alloc_id = alloc_it->second; |
| 1624 | std::vector<ImageId>& alloc_images = slot_image_allocs[alloc_id].images; | 1624 | std::vector<ImageId>& alloc_images = slot_image_allocs[alloc_id].images; |
| 1625 | const auto alloc_image_it = std::ranges::find(alloc_images, image_id); | 1625 | const auto alloc_image_it = std::ranges::find(alloc_images, image_id); |
| 1626 | if (alloc_image_it == alloc_images.end()) { | 1626 | if (alloc_image_it == alloc_images.end()) { |
| 1627 | UNREACHABLE_MSG("Trying to delete an image that does not exist"); | 1627 | ASSERT_MSG(false, "Trying to delete an image that does not exist"); |
| 1628 | return; | 1628 | return; |
| 1629 | } | 1629 | } |
| 1630 | ASSERT_MSG(False(image.flags & ImageFlagBits::Tracked), "Image was not untracked"); | 1630 | ASSERT_MSG(False(image.flags & ImageFlagBits::Tracked), "Image was not untracked"); |
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index c81343850..9b6b8527b 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp | |||
| @@ -87,7 +87,7 @@ void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixe | |||
| 87 | BPP_CASE(16) | 87 | BPP_CASE(16) |
| 88 | #undef BPP_CASE | 88 | #undef BPP_CASE |
| 89 | default: | 89 | default: |
| 90 | UNREACHABLE_MSG("Invalid bytes_per_pixel={}", bytes_per_pixel); | 90 | ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); |
| 91 | } | 91 | } |
| 92 | } | 92 | } |
| 93 | 93 | ||
| @@ -209,7 +209,7 @@ void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 | |||
| 209 | BPP_CASE(16) | 209 | BPP_CASE(16) |
| 210 | #undef BPP_CASE | 210 | #undef BPP_CASE |
| 211 | default: | 211 | default: |
| 212 | UNREACHABLE_MSG("Invalid bytes_per_pixel={}", bytes_per_pixel); | 212 | ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); |
| 213 | } | 213 | } |
| 214 | } | 214 | } |
| 215 | 215 | ||
| @@ -230,7 +230,7 @@ void UnswizzleSubrect(u32 line_length_in, u32 line_count, u32 pitch, u32 width, | |||
| 230 | BPP_CASE(16) | 230 | BPP_CASE(16) |
| 231 | #undef BPP_CASE | 231 | #undef BPP_CASE |
| 232 | default: | 232 | default: |
| 233 | UNREACHABLE_MSG("Invalid bytes_per_pixel={}", bytes_per_pixel); | 233 | ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); |
| 234 | } | 234 | } |
| 235 | } | 235 | } |
| 236 | 236 | ||
| @@ -253,7 +253,7 @@ void SwizzleSliceToVoxel(u32 line_length_in, u32 line_count, u32 pitch, u32 widt | |||
| 253 | BPP_CASE(16) | 253 | BPP_CASE(16) |
| 254 | #undef BPP_CASE | 254 | #undef BPP_CASE |
| 255 | default: | 255 | default: |
| 256 | UNREACHABLE_MSG("Invalid bytes_per_pixel={}", bytes_per_pixel); | 256 | ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); |
| 257 | } | 257 | } |
| 258 | } | 258 | } |
| 259 | 259 | ||
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 7b2ca8046..11ce865a7 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -566,7 +566,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 566 | } | 566 | } |
| 567 | 567 | ||
| 568 | VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR workgroup_layout; | 568 | VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR workgroup_layout; |
| 569 | if (khr_workgroup_memory_explicit_layout) { | 569 | if (khr_workgroup_memory_explicit_layout && is_shader_int16_supported) { |
| 570 | workgroup_layout = { | 570 | workgroup_layout = { |
| 571 | .sType = | 571 | .sType = |
| 572 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR, | 572 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR, |
| @@ -577,6 +577,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 577 | .workgroupMemoryExplicitLayout16BitAccess = VK_TRUE, | 577 | .workgroupMemoryExplicitLayout16BitAccess = VK_TRUE, |
| 578 | }; | 578 | }; |
| 579 | SetNext(next, workgroup_layout); | 579 | SetNext(next, workgroup_layout); |
| 580 | } else if (khr_workgroup_memory_explicit_layout) { | ||
| 581 | // TODO(lat9nq): Find a proper fix for this | ||
| 582 | LOG_WARNING(Render_Vulkan, "Disabling VK_KHR_workgroup_memory_explicit_layout due to a " | ||
| 583 | "yuzu bug when host driver does not support 16-bit integers"); | ||
| 584 | khr_workgroup_memory_explicit_layout = false; | ||
| 580 | } | 585 | } |
| 581 | 586 | ||
| 582 | VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR executable_properties; | 587 | VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR executable_properties; |
| @@ -664,6 +669,17 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 664 | const bool is_amd = | 669 | const bool is_amd = |
| 665 | driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE; | 670 | driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE; |
| 666 | if (is_amd) { | 671 | if (is_amd) { |
| 672 | // TODO(lat9nq): Add an upper bound when AMD fixes their VK_KHR_push_descriptor | ||
| 673 | const bool has_broken_push_descriptor = VK_VERSION_MAJOR(properties.driverVersion) == 2 && | ||
| 674 | VK_VERSION_MINOR(properties.driverVersion) == 0 && | ||
| 675 | VK_VERSION_PATCH(properties.driverVersion) >= 226; | ||
| 676 | if (khr_push_descriptor && has_broken_push_descriptor) { | ||
| 677 | LOG_WARNING( | ||
| 678 | Render_Vulkan, | ||
| 679 | "Disabling AMD driver 2.0.226 and later from broken VK_KHR_push_descriptor"); | ||
| 680 | khr_push_descriptor = false; | ||
| 681 | } | ||
| 682 | |||
| 667 | // AMD drivers need a higher amount of Sets per Pool in certain circunstances like in XC2. | 683 | // AMD drivers need a higher amount of Sets per Pool in certain circunstances like in XC2. |
| 668 | sets_per_pool = 96; | 684 | sets_per_pool = 96; |
| 669 | // Disable VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT on AMD GCN4 and lower as it is broken. | 685 | // Disable VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT on AMD GCN4 and lower as it is broken. |
| @@ -722,9 +738,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags | |||
| 722 | // The wanted format is not supported by hardware, search for alternatives | 738 | // The wanted format is not supported by hardware, search for alternatives |
| 723 | const VkFormat* alternatives = GetFormatAlternatives(wanted_format); | 739 | const VkFormat* alternatives = GetFormatAlternatives(wanted_format); |
| 724 | if (alternatives == nullptr) { | 740 | if (alternatives == nullptr) { |
| 725 | UNREACHABLE_MSG("Format={} with usage={} and type={} has no defined alternatives and host " | 741 | ASSERT_MSG(false, |
| 726 | "hardware does not support it", | 742 | "Format={} with usage={} and type={} has no defined alternatives and host " |
| 727 | wanted_format, wanted_usage, format_type); | 743 | "hardware does not support it", |
| 744 | wanted_format, wanted_usage, format_type); | ||
| 728 | return wanted_format; | 745 | return wanted_format; |
| 729 | } | 746 | } |
| 730 | 747 | ||
| @@ -740,9 +757,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags | |||
| 740 | } | 757 | } |
| 741 | 758 | ||
| 742 | // No alternatives found, panic | 759 | // No alternatives found, panic |
| 743 | UNREACHABLE_MSG("Format={} with usage={} and type={} is not supported by the host hardware and " | 760 | ASSERT_MSG(false, |
| 744 | "doesn't support any of the alternatives", | 761 | "Format={} with usage={} and type={} is not supported by the host hardware and " |
| 745 | wanted_format, wanted_usage, format_type); | 762 | "doesn't support any of the alternatives", |
| 763 | wanted_format, wanted_usage, format_type); | ||
| 746 | return wanted_format; | 764 | return wanted_format; |
| 747 | } | 765 | } |
| 748 | 766 | ||
diff --git a/src/video_core/vulkan_common/vulkan_library.cpp b/src/video_core/vulkan_common/vulkan_library.cpp index a5dd33fb2..4eb3913ee 100644 --- a/src/video_core/vulkan_common/vulkan_library.cpp +++ b/src/video_core/vulkan_common/vulkan_library.cpp | |||
| @@ -5,11 +5,13 @@ | |||
| 5 | 5 | ||
| 6 | #include "common/dynamic_library.h" | 6 | #include "common/dynamic_library.h" |
| 7 | #include "common/fs/path_util.h" | 7 | #include "common/fs/path_util.h" |
| 8 | #include "common/logging/log.h" | ||
| 8 | #include "video_core/vulkan_common/vulkan_library.h" | 9 | #include "video_core/vulkan_common/vulkan_library.h" |
| 9 | 10 | ||
| 10 | namespace Vulkan { | 11 | namespace Vulkan { |
| 11 | 12 | ||
| 12 | Common::DynamicLibrary OpenLibrary() { | 13 | Common::DynamicLibrary OpenLibrary() { |
| 14 | LOG_DEBUG(Render_Vulkan, "Looking for a Vulkan library"); | ||
| 13 | Common::DynamicLibrary library; | 15 | Common::DynamicLibrary library; |
| 14 | #ifdef __APPLE__ | 16 | #ifdef __APPLE__ |
| 15 | // Check if a path to a specific Vulkan library has been specified. | 17 | // Check if a path to a specific Vulkan library has been specified. |
| @@ -22,9 +24,11 @@ Common::DynamicLibrary OpenLibrary() { | |||
| 22 | } | 24 | } |
| 23 | #else | 25 | #else |
| 24 | std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); | 26 | std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); |
| 27 | LOG_DEBUG(Render_Vulkan, "Trying Vulkan library: {}", filename); | ||
| 25 | if (!library.Open(filename.c_str())) { | 28 | if (!library.Open(filename.c_str())) { |
| 26 | // Android devices may not have libvulkan.so.1, only libvulkan.so. | 29 | // Android devices may not have libvulkan.so.1, only libvulkan.so. |
| 27 | filename = Common::DynamicLibrary::GetVersionedFilename("vulkan"); | 30 | filename = Common::DynamicLibrary::GetVersionedFilename("vulkan"); |
| 31 | LOG_DEBUG(Render_Vulkan, "Trying Vulkan library (second attempt): {}", filename); | ||
| 28 | void(library.Open(filename.c_str())); | 32 | void(library.Open(filename.c_str())); |
| 29 | } | 33 | } |
| 30 | #endif | 34 | #endif |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index caae6dfdc..6442898bd 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp | |||
| @@ -49,7 +49,7 @@ struct Range { | |||
| 49 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | | 49 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | |
| 50 | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; | 50 | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; |
| 51 | } | 51 | } |
| 52 | UNREACHABLE_MSG("Invalid memory usage={}", usage); | 52 | ASSERT_MSG(false, "Invalid memory usage={}", usage); |
| 53 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | 53 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| @@ -325,7 +325,7 @@ VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, | |||
| 325 | // Remove device local, if it's not supported by the requested resource | 325 | // Remove device local, if it's not supported by the requested resource |
| 326 | return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); | 326 | return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| 327 | } | 327 | } |
| 328 | UNREACHABLE_MSG("No compatible memory types found"); | 328 | ASSERT_MSG(false, "No compatible memory types found"); |
| 329 | return 0; | 329 | return 0; |
| 330 | } | 330 | } |
| 331 | 331 | ||
| @@ -349,7 +349,7 @@ bool IsHostVisible(MemoryUsage usage) noexcept { | |||
| 349 | case MemoryUsage::Download: | 349 | case MemoryUsage::Download: |
| 350 | return true; | 350 | return true; |
| 351 | } | 351 | } |
| 352 | UNREACHABLE_MSG("Invalid memory usage={}", usage); | 352 | ASSERT_MSG(false, "Invalid memory usage={}", usage); |
| 353 | return false; | 353 | return false; |
| 354 | } | 354 | } |
| 355 | 355 | ||
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index b1ea6075a..2ad98dcfe 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp | |||
| @@ -325,6 +325,8 @@ const char* ToString(VkResult result) noexcept { | |||
| 325 | return "VK_PIPELINE_COMPILE_REQUIRED_EXT"; | 325 | return "VK_PIPELINE_COMPILE_REQUIRED_EXT"; |
| 326 | case VkResult::VK_RESULT_MAX_ENUM: | 326 | case VkResult::VK_RESULT_MAX_ENUM: |
| 327 | return "VK_RESULT_MAX_ENUM"; | 327 | return "VK_RESULT_MAX_ENUM"; |
| 328 | case VkResult::VK_ERROR_COMPRESSION_EXHAUSTED_EXT: | ||
| 329 | return "VK_ERROR_COMPRESSION_EXHAUSTED_EXT"; | ||
| 328 | } | 330 | } |
| 329 | return "Unknown"; | 331 | return "Unknown"; |
| 330 | } | 332 | } |
diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp index 6215c914f..46faddb61 100644 --- a/src/web_service/telemetry_json.cpp +++ b/src/web_service/telemetry_json.cpp | |||
| @@ -13,8 +13,8 @@ namespace WebService { | |||
| 13 | namespace Telemetry = Common::Telemetry; | 13 | namespace Telemetry = Common::Telemetry; |
| 14 | 14 | ||
| 15 | struct TelemetryJson::Impl { | 15 | struct TelemetryJson::Impl { |
| 16 | Impl(std::string host, std::string username, std::string token) | 16 | Impl(std::string host_, std::string username_, std::string token_) |
| 17 | : host{std::move(host)}, username{std::move(username)}, token{std::move(token)} {} | 17 | : host{std::move(host_)}, username{std::move(username_)}, token{std::move(token_)} {} |
| 18 | 18 | ||
| 19 | nlohmann::json& TopSection() { | 19 | nlohmann::json& TopSection() { |
| 20 | return sections[static_cast<u8>(Telemetry::FieldType::None)]; | 20 | return sections[static_cast<u8>(Telemetry::FieldType::None)]; |
diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp index 58b0c2f10..dce9772fe 100644 --- a/src/web_service/web_backend.cpp +++ b/src/web_service/web_backend.cpp | |||
| @@ -30,10 +30,10 @@ constexpr std::array<const char, 1> API_VERSION{'1'}; | |||
| 30 | constexpr std::size_t TIMEOUT_SECONDS = 30; | 30 | constexpr std::size_t TIMEOUT_SECONDS = 30; |
| 31 | 31 | ||
| 32 | struct Client::Impl { | 32 | struct Client::Impl { |
| 33 | Impl(std::string host, std::string username, std::string token) | 33 | Impl(std::string host_, std::string username_, std::string token_) |
| 34 | : host{std::move(host)}, username{std::move(username)}, token{std::move(token)} { | 34 | : host{std::move(host_)}, username{std::move(username_)}, token{std::move(token_)} { |
| 35 | std::scoped_lock lock{jwt_cache.mutex}; | 35 | std::scoped_lock lock{jwt_cache.mutex}; |
| 36 | if (this->username == jwt_cache.username && this->token == jwt_cache.token) { | 36 | if (username == jwt_cache.username && token == jwt_cache.token) { |
| 37 | jwt = jwt_cache.jwt; | 37 | jwt = jwt_cache.jwt; |
| 38 | } | 38 | } |
| 39 | } | 39 | } |
| @@ -69,8 +69,8 @@ struct Client::Impl { | |||
| 69 | */ | 69 | */ |
| 70 | WebResult GenericRequest(const std::string& method, const std::string& path, | 70 | WebResult GenericRequest(const std::string& method, const std::string& path, |
| 71 | const std::string& data, const std::string& accept, | 71 | const std::string& data, const std::string& accept, |
| 72 | const std::string& jwt = "", const std::string& username = "", | 72 | const std::string& jwt_ = "", const std::string& username_ = "", |
| 73 | const std::string& token = "") { | 73 | const std::string& token_ = "") { |
| 74 | if (cli == nullptr) { | 74 | if (cli == nullptr) { |
| 75 | cli = std::make_unique<httplib::Client>(host.c_str()); | 75 | cli = std::make_unique<httplib::Client>(host.c_str()); |
| 76 | } | 76 | } |
| @@ -85,14 +85,14 @@ struct Client::Impl { | |||
| 85 | cli->set_write_timeout(TIMEOUT_SECONDS); | 85 | cli->set_write_timeout(TIMEOUT_SECONDS); |
| 86 | 86 | ||
| 87 | httplib::Headers params; | 87 | httplib::Headers params; |
| 88 | if (!jwt.empty()) { | 88 | if (!jwt_.empty()) { |
| 89 | params = { | 89 | params = { |
| 90 | {std::string("Authorization"), fmt::format("Bearer {}", jwt)}, | 90 | {std::string("Authorization"), fmt::format("Bearer {}", jwt_)}, |
| 91 | }; | 91 | }; |
| 92 | } else if (!username.empty()) { | 92 | } else if (!username_.empty()) { |
| 93 | params = { | 93 | params = { |
| 94 | {std::string("x-username"), username}, | 94 | {std::string("x-username"), username_}, |
| 95 | {std::string("x-token"), token}, | 95 | {std::string("x-token"), token_}, |
| 96 | }; | 96 | }; |
| 97 | } | 97 | } |
| 98 | 98 | ||
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 2ee21f751..242867a4f 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -30,6 +30,8 @@ add_executable(yuzu | |||
| 30 | applets/qt_web_browser_scripts.h | 30 | applets/qt_web_browser_scripts.h |
| 31 | bootmanager.cpp | 31 | bootmanager.cpp |
| 32 | bootmanager.h | 32 | bootmanager.h |
| 33 | check_vulkan.cpp | ||
| 34 | check_vulkan.h | ||
| 33 | compatdb.ui | 35 | compatdb.ui |
| 34 | compatibility_list.cpp | 36 | compatibility_list.cpp |
| 35 | compatibility_list.h | 37 | compatibility_list.h |
| @@ -187,7 +189,7 @@ if (ENABLE_QT_TRANSLATION) | |||
| 187 | # Update source TS file if enabled | 189 | # Update source TS file if enabled |
| 188 | if (GENERATE_QT_TRANSLATION) | 190 | if (GENERATE_QT_TRANSLATION) |
| 189 | get_target_property(SRCS yuzu SOURCES) | 191 | get_target_property(SRCS yuzu SOURCES) |
| 190 | qt5_create_translation(QM_FILES | 192 | qt_create_translation(QM_FILES |
| 191 | ${SRCS} | 193 | ${SRCS} |
| 192 | ${UIS} | 194 | ${UIS} |
| 193 | ${YUZU_QT_LANGUAGES}/en.ts | 195 | ${YUZU_QT_LANGUAGES}/en.ts |
| @@ -203,7 +205,7 @@ if (ENABLE_QT_TRANSLATION) | |||
| 203 | list(REMOVE_ITEM LANGUAGES_TS ${YUZU_QT_LANGUAGES}/en.ts) | 205 | list(REMOVE_ITEM LANGUAGES_TS ${YUZU_QT_LANGUAGES}/en.ts) |
| 204 | 206 | ||
| 205 | # Compile TS files to QM files | 207 | # Compile TS files to QM files |
| 206 | qt5_add_translation(LANGUAGES_QM ${LANGUAGES_TS}) | 208 | qt_add_translation(LANGUAGES_QM ${LANGUAGES_TS}) |
| 207 | 209 | ||
| 208 | # Build a QRC file from the QM file list | 210 | # Build a QRC file from the QM file list |
| 209 | set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc) | 211 | set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc) |
| @@ -215,7 +217,7 @@ if (ENABLE_QT_TRANSLATION) | |||
| 215 | file(APPEND ${LANGUAGES_QRC} "</qresource></RCC>") | 217 | file(APPEND ${LANGUAGES_QRC} "</qresource></RCC>") |
| 216 | 218 | ||
| 217 | # Add the QRC file to package in all QM files | 219 | # Add the QRC file to package in all QM files |
| 218 | qt5_add_resources(LANGUAGES ${LANGUAGES_QRC}) | 220 | qt_add_resources(LANGUAGES ${LANGUAGES_QRC}) |
| 219 | else() | 221 | else() |
| 220 | set(LANGUAGES) | 222 | set(LANGUAGES) |
| 221 | endif() | 223 | endif() |
| @@ -236,18 +238,23 @@ if (APPLE) | |||
| 236 | set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) | 238 | set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) |
| 237 | elseif(WIN32) | 239 | elseif(WIN32) |
| 238 | # compile as a win32 gui application instead of a console application | 240 | # compile as a win32 gui application instead of a console application |
| 239 | target_link_libraries(yuzu PRIVATE Qt5::WinMain) | 241 | if (QT_VERSION VERSION_GREATER 6) |
| 242 | target_link_libraries(yuzu PRIVATE Qt6::EntryPointPrivate) | ||
| 243 | else() | ||
| 244 | target_link_libraries(yuzu PRIVATE Qt5::WinMain) | ||
| 245 | endif() | ||
| 240 | if(MSVC) | 246 | if(MSVC) |
| 247 | target_link_libraries(yuzu PRIVATE version.lib) | ||
| 241 | set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") | 248 | set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") |
| 242 | elseif(MINGW) | 249 | elseif(MINGW) |
| 243 | set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "-mwindows") | 250 | set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "-Wl,--subsystem,windows") |
| 244 | endif() | 251 | endif() |
| 245 | endif() | 252 | endif() |
| 246 | 253 | ||
| 247 | create_target_directory_groups(yuzu) | 254 | create_target_directory_groups(yuzu) |
| 248 | 255 | ||
| 249 | target_link_libraries(yuzu PRIVATE common core input_common video_core) | 256 | target_link_libraries(yuzu PRIVATE common core input_common video_core) |
| 250 | target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::Widgets) | 257 | target_link_libraries(yuzu PRIVATE Boost::boost glad Qt::Widgets) |
| 251 | target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) | 258 | target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) |
| 252 | 259 | ||
| 253 | target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include) | 260 | target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include) |
| @@ -255,7 +262,7 @@ if (NOT WIN32) | |||
| 255 | target_include_directories(yuzu PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) | 262 | target_include_directories(yuzu PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) |
| 256 | endif() | 263 | endif() |
| 257 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") | 264 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") |
| 258 | target_link_libraries(yuzu PRIVATE Qt5::DBus) | 265 | target_link_libraries(yuzu PRIVATE Qt::DBus) |
| 259 | endif() | 266 | endif() |
| 260 | 267 | ||
| 261 | target_compile_definitions(yuzu PRIVATE | 268 | target_compile_definitions(yuzu PRIVATE |
| @@ -291,7 +298,7 @@ if (USE_DISCORD_PRESENCE) | |||
| 291 | endif() | 298 | endif() |
| 292 | 299 | ||
| 293 | if (YUZU_USE_QT_WEB_ENGINE) | 300 | if (YUZU_USE_QT_WEB_ENGINE) |
| 294 | target_link_libraries(yuzu PRIVATE Qt5::WebEngineCore Qt5::WebEngineWidgets) | 301 | target_link_libraries(yuzu PRIVATE Qt::WebEngineCore Qt::WebEngineWidgets) |
| 295 | target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE) | 302 | target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE) |
| 296 | endif () | 303 | endif () |
| 297 | 304 | ||
| @@ -319,3 +326,7 @@ endif() | |||
| 319 | if (NOT APPLE) | 326 | if (NOT APPLE) |
| 320 | target_compile_definitions(yuzu PRIVATE HAS_OPENGL) | 327 | target_compile_definitions(yuzu PRIVATE HAS_OPENGL) |
| 321 | endif() | 328 | endif() |
| 329 | |||
| 330 | if (ARCHITECTURE_x86_64) | ||
| 331 | target_link_libraries(yuzu PRIVATE dynarmic) | ||
| 332 | endif() | ||
diff --git a/src/yuzu/about_dialog.cpp b/src/yuzu/about_dialog.cpp index cbcef7b45..eeff54359 100644 --- a/src/yuzu/about_dialog.cpp +++ b/src/yuzu/about_dialog.cpp | |||
| @@ -19,7 +19,11 @@ AboutDialog::AboutDialog(QWidget* parent) | |||
| 19 | const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build; | 19 | const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build; |
| 20 | 20 | ||
| 21 | ui->setupUi(this); | 21 | ui->setupUi(this); |
| 22 | ui->labelLogo->setPixmap(QIcon::fromTheme(QStringLiteral("yuzu")).pixmap(200)); | 22 | // Try and request the icon from Qt theme (Linux?) |
| 23 | const QIcon yuzu_logo = QIcon::fromTheme(QStringLiteral("org.yuzu_emu.yuzu")); | ||
| 24 | if (!yuzu_logo.isNull()) { | ||
| 25 | ui->labelLogo->setPixmap(yuzu_logo.pixmap(200)); | ||
| 26 | } | ||
| 23 | ui->labelBuildInfo->setText( | 27 | ui->labelBuildInfo->setText( |
| 24 | ui->labelBuildInfo->text().arg(QString::fromStdString(yuzu_build_version), | 28 | ui->labelBuildInfo->text().arg(QString::fromStdString(yuzu_build_version), |
| 25 | QString::fromUtf8(Common::g_build_date).left(10))); | 29 | QString::fromUtf8(Common::g_build_date).left(10))); |
diff --git a/src/yuzu/aboutdialog.ui b/src/yuzu/aboutdialog.ui index 2f7ddc7f3..1dd7b74bf 100644 --- a/src/yuzu/aboutdialog.ui +++ b/src/yuzu/aboutdialog.ui | |||
| @@ -26,8 +26,20 @@ | |||
| 26 | <verstretch>0</verstretch> | 26 | <verstretch>0</verstretch> |
| 27 | </sizepolicy> | 27 | </sizepolicy> |
| 28 | </property> | 28 | </property> |
| 29 | <property name="maximumSize"> | ||
| 30 | <size> | ||
| 31 | <width>200</width> | ||
| 32 | <height>200</height> | ||
| 33 | </size> | ||
| 34 | </property> | ||
| 29 | <property name="text"> | 35 | <property name="text"> |
| 30 | <string><html><head/><body><p><img src=":/icons/yuzu.png"/></p></body></html></string> | 36 | <string/> |
| 37 | </property> | ||
| 38 | <property name="pixmap"> | ||
| 39 | <pixmap resource="../../dist/qt_themes/default/default.qrc">:/icons/default/256x256/yuzu.png</pixmap> | ||
| 40 | </property> | ||
| 41 | <property name="scaledContents"> | ||
| 42 | <bool>true</bool> | ||
| 31 | </property> | 43 | </property> |
| 32 | </widget> | 44 | </widget> |
| 33 | </item> | 45 | </item> |
| @@ -152,7 +164,7 @@ p, li { white-space: pre-wrap; } | |||
| 152 | </layout> | 164 | </layout> |
| 153 | </widget> | 165 | </widget> |
| 154 | <resources> | 166 | <resources> |
| 155 | <include location="../../dist/icons/icons.qrc"/> | 167 | <include location="../../dist/qt_themes_default/default/default.qrc"/> |
| 156 | </resources> | 168 | </resources> |
| 157 | <connections> | 169 | <connections> |
| 158 | <connection> | 170 | <connection> |
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index c924cb0cb..8be311fcb 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp | |||
| @@ -631,7 +631,7 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() { | |||
| 631 | switch (max_supported_players) { | 631 | switch (max_supported_players) { |
| 632 | case 0: | 632 | case 0: |
| 633 | default: | 633 | default: |
| 634 | UNREACHABLE(); | 634 | ASSERT(false); |
| 635 | return; | 635 | return; |
| 636 | case 1: | 636 | case 1: |
| 637 | ui->widgetSpacer->hide(); | 637 | ui->widgetSpacer->hide(); |
diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp index d3cf0b43b..e8b217d90 100644 --- a/src/yuzu/applets/qt_software_keyboard.cpp +++ b/src/yuzu/applets/qt_software_keyboard.cpp | |||
| @@ -411,11 +411,11 @@ void QtSoftwareKeyboardDialog::ShowTextCheckDialog( | |||
| 411 | break; | 411 | break; |
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | auto text = ui->topOSK->currentIndex() == 1 | 414 | const auto text = ui->topOSK->currentIndex() == 1 ? ui->text_edit_osk->toPlainText() |
| 415 | ? ui->text_edit_osk->toPlainText().toStdU16String() | 415 | : ui->line_edit_osk->text(); |
| 416 | : ui->line_edit_osk->text().toStdU16String(); | 416 | auto text_str = Common::U16StringFromBuffer(text.utf16(), text.size()); |
| 417 | 417 | ||
| 418 | emit SubmitNormalText(SwkbdResult::Ok, std::move(text), true); | 418 | emit SubmitNormalText(SwkbdResult::Ok, std::move(text_str), true); |
| 419 | break; | 419 | break; |
| 420 | } | 420 | } |
| 421 | } | 421 | } |
| @@ -562,7 +562,7 @@ void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) { | |||
| 562 | return; | 562 | return; |
| 563 | } | 563 | } |
| 564 | 564 | ||
| 565 | InlineTextInsertString(entered_text.toStdU16String()); | 565 | InlineTextInsertString(Common::U16StringFromBuffer(entered_text.utf16(), entered_text.size())); |
| 566 | } | 566 | } |
| 567 | 567 | ||
| 568 | void QtSoftwareKeyboardDialog::MoveAndResizeWindow(QPoint pos, QSize size) { | 568 | void QtSoftwareKeyboardDialog::MoveAndResizeWindow(QPoint pos, QSize size) { |
| @@ -1119,11 +1119,11 @@ void QtSoftwareKeyboardDialog::NormalKeyboardButtonClicked(QPushButton* button) | |||
| 1119 | } | 1119 | } |
| 1120 | 1120 | ||
| 1121 | if (button == ui->button_ok || button == ui->button_ok_shift || button == ui->button_ok_num) { | 1121 | if (button == ui->button_ok || button == ui->button_ok_shift || button == ui->button_ok_num) { |
| 1122 | auto text = ui->topOSK->currentIndex() == 1 | 1122 | const auto text = ui->topOSK->currentIndex() == 1 ? ui->text_edit_osk->toPlainText() |
| 1123 | ? ui->text_edit_osk->toPlainText().toStdU16String() | 1123 | : ui->line_edit_osk->text(); |
| 1124 | : ui->line_edit_osk->text().toStdU16String(); | 1124 | auto text_str = Common::U16StringFromBuffer(text.utf16(), text.size()); |
| 1125 | 1125 | ||
| 1126 | emit SubmitNormalText(SwkbdResult::Ok, std::move(text)); | 1126 | emit SubmitNormalText(SwkbdResult::Ok, std::move(text_str)); |
| 1127 | return; | 1127 | return; |
| 1128 | } | 1128 | } |
| 1129 | 1129 | ||
| @@ -1189,7 +1189,8 @@ void QtSoftwareKeyboardDialog::InlineKeyboardButtonClicked(QPushButton* button) | |||
| 1189 | return; | 1189 | return; |
| 1190 | } | 1190 | } |
| 1191 | 1191 | ||
| 1192 | InlineTextInsertString(button->text().toStdU16String()); | 1192 | const auto button_text = button->text(); |
| 1193 | InlineTextInsertString(Common::U16StringFromBuffer(button_text.utf16(), button_text.size())); | ||
| 1193 | 1194 | ||
| 1194 | // Revert the keyboard to lowercase if the shift key is active. | 1195 | // Revert the keyboard to lowercase if the shift key is active. |
| 1195 | if (bottom_osk_index == BottomOSKIndex::UpperCase && !caps_lock_enabled) { | 1196 | if (bottom_osk_index == BottomOSKIndex::UpperCase && !caps_lock_enabled) { |
| @@ -1282,11 +1283,11 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(Core::HID::NpadButton button | |||
| 1282 | if (is_inline) { | 1283 | if (is_inline) { |
| 1283 | emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position); | 1284 | emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position); |
| 1284 | } else { | 1285 | } else { |
| 1285 | auto text = ui->topOSK->currentIndex() == 1 | 1286 | const auto text = ui->topOSK->currentIndex() == 1 ? ui->text_edit_osk->toPlainText() |
| 1286 | ? ui->text_edit_osk->toPlainText().toStdU16String() | 1287 | : ui->line_edit_osk->text(); |
| 1287 | : ui->line_edit_osk->text().toStdU16String(); | 1288 | auto text_str = Common::U16StringFromBuffer(text.utf16(), text.size()); |
| 1288 | 1289 | ||
| 1289 | emit SubmitNormalText(SwkbdResult::Cancel, std::move(text)); | 1290 | emit SubmitNormalText(SwkbdResult::Cancel, std::move(text_str)); |
| 1290 | } | 1291 | } |
| 1291 | break; | 1292 | break; |
| 1292 | case Core::HID::NpadButton::Y: | 1293 | case Core::HID::NpadButton::Y: |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index a1b819ae0..cbe4e2daa 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -50,6 +50,7 @@ void EmuThread::run() { | |||
| 50 | 50 | ||
| 51 | auto& gpu = system.GPU(); | 51 | auto& gpu = system.GPU(); |
| 52 | auto stop_token = stop_source.get_token(); | 52 | auto stop_token = stop_source.get_token(); |
| 53 | bool debugger_should_start = system.DebuggerEnabled(); | ||
| 53 | 54 | ||
| 54 | system.RegisterHostThread(); | 55 | system.RegisterHostThread(); |
| 55 | 56 | ||
| @@ -89,6 +90,12 @@ void EmuThread::run() { | |||
| 89 | this->SetRunning(false); | 90 | this->SetRunning(false); |
| 90 | emit ErrorThrown(result, system.GetStatusDetails()); | 91 | emit ErrorThrown(result, system.GetStatusDetails()); |
| 91 | } | 92 | } |
| 93 | |||
| 94 | if (debugger_should_start) { | ||
| 95 | system.InitializeDebugger(); | ||
| 96 | debugger_should_start = false; | ||
| 97 | } | ||
| 98 | |||
| 92 | running_wait.Wait(); | 99 | running_wait.Wait(); |
| 93 | result = system.Pause(); | 100 | result = system.Pause(); |
| 94 | if (result != Core::SystemResultStatus::Success) { | 101 | if (result != Core::SystemResultStatus::Success) { |
| @@ -102,11 +109,9 @@ void EmuThread::run() { | |||
| 102 | was_active = true; | 109 | was_active = true; |
| 103 | emit DebugModeEntered(); | 110 | emit DebugModeEntered(); |
| 104 | } | 111 | } |
| 105 | } else if (exec_step) { | ||
| 106 | UNIMPLEMENTED(); | ||
| 107 | } else { | 112 | } else { |
| 108 | std::unique_lock lock{running_mutex}; | 113 | std::unique_lock lock{running_mutex}; |
| 109 | running_cv.wait(lock, stop_token, [this] { return IsRunning() || exec_step; }); | 114 | running_cv.wait(lock, stop_token, [this] { return IsRunning(); }); |
| 110 | } | 115 | } |
| 111 | } | 116 | } |
| 112 | 117 | ||
| @@ -122,7 +127,7 @@ void EmuThread::run() { | |||
| 122 | class OpenGLSharedContext : public Core::Frontend::GraphicsContext { | 127 | class OpenGLSharedContext : public Core::Frontend::GraphicsContext { |
| 123 | public: | 128 | public: |
| 124 | /// Create the original context that should be shared from | 129 | /// Create the original context that should be shared from |
| 125 | explicit OpenGLSharedContext(QSurface* surface) : surface(surface) { | 130 | explicit OpenGLSharedContext(QSurface* surface_) : surface{surface_} { |
| 126 | QSurfaceFormat format; | 131 | QSurfaceFormat format; |
| 127 | format.setVersion(4, 6); | 132 | format.setVersion(4, 6); |
| 128 | format.setProfile(QSurfaceFormat::CompatibilityProfile); | 133 | format.setProfile(QSurfaceFormat::CompatibilityProfile); |
| @@ -359,9 +364,9 @@ void GRenderWindow::RestoreGeometry() { | |||
| 359 | QWidget::restoreGeometry(geometry); | 364 | QWidget::restoreGeometry(geometry); |
| 360 | } | 365 | } |
| 361 | 366 | ||
| 362 | void GRenderWindow::restoreGeometry(const QByteArray& geometry) { | 367 | void GRenderWindow::restoreGeometry(const QByteArray& geometry_) { |
| 363 | // Make sure users of this class don't need to deal with backing up the geometry themselves | 368 | // Make sure users of this class don't need to deal with backing up the geometry themselves |
| 364 | QWidget::restoreGeometry(geometry); | 369 | QWidget::restoreGeometry(geometry_); |
| 365 | BackupGeometry(); | 370 | BackupGeometry(); |
| 366 | } | 371 | } |
| 367 | 372 | ||
| @@ -747,7 +752,7 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { | |||
| 747 | input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, center_x, center_y); | 752 | input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, center_x, center_y); |
| 748 | 753 | ||
| 749 | if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { | 754 | if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { |
| 750 | QCursor::setPos(mapToGlobal({center_x, center_y})); | 755 | QCursor::setPos(mapToGlobal(QPoint{center_x, center_y})); |
| 751 | } | 756 | } |
| 752 | 757 | ||
| 753 | emit MouseActivity(); | 758 | emit MouseActivity(); |
| @@ -772,65 +777,25 @@ void GRenderWindow::wheelEvent(QWheelEvent* event) { | |||
| 772 | void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { | 777 | void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { |
| 773 | QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints(); | 778 | QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints(); |
| 774 | for (const auto& touch_point : touch_points) { | 779 | for (const auto& touch_point : touch_points) { |
| 775 | if (!TouchUpdate(touch_point)) { | 780 | const auto [x, y] = ScaleTouch(touch_point.pos()); |
| 776 | TouchStart(touch_point); | 781 | const auto [touch_x, touch_y] = MapToTouchScreen(x, y); |
| 777 | } | 782 | input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, touch_point.id()); |
| 778 | } | 783 | } |
| 779 | } | 784 | } |
| 780 | 785 | ||
| 781 | void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) { | 786 | void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) { |
| 782 | QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints(); | 787 | QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints(); |
| 788 | input_subsystem->GetTouchScreen()->ClearActiveFlag(); | ||
| 783 | for (const auto& touch_point : touch_points) { | 789 | for (const auto& touch_point : touch_points) { |
| 784 | if (!TouchUpdate(touch_point)) { | 790 | const auto [x, y] = ScaleTouch(touch_point.pos()); |
| 785 | TouchStart(touch_point); | 791 | const auto [touch_x, touch_y] = MapToTouchScreen(x, y); |
| 786 | } | 792 | input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, touch_point.id()); |
| 787 | } | ||
| 788 | // Release all inactive points | ||
| 789 | for (std::size_t id = 0; id < touch_ids.size(); ++id) { | ||
| 790 | if (!TouchExist(touch_ids[id], touch_points)) { | ||
| 791 | touch_ids[id] = 0; | ||
| 792 | input_subsystem->GetTouchScreen()->TouchReleased(id); | ||
| 793 | } | ||
| 794 | } | 793 | } |
| 794 | input_subsystem->GetTouchScreen()->ReleaseInactiveTouch(); | ||
| 795 | } | 795 | } |
| 796 | 796 | ||
| 797 | void GRenderWindow::TouchEndEvent() { | 797 | void GRenderWindow::TouchEndEvent() { |
| 798 | for (std::size_t id = 0; id < touch_ids.size(); ++id) { | 798 | input_subsystem->GetTouchScreen()->ReleaseAllTouch(); |
| 799 | if (touch_ids[id] != 0) { | ||
| 800 | touch_ids[id] = 0; | ||
| 801 | input_subsystem->GetTouchScreen()->TouchReleased(id); | ||
| 802 | } | ||
| 803 | } | ||
| 804 | } | ||
| 805 | |||
| 806 | void GRenderWindow::TouchStart(const QTouchEvent::TouchPoint& touch_point) { | ||
| 807 | for (std::size_t id = 0; id < touch_ids.size(); ++id) { | ||
| 808 | if (touch_ids[id] == 0) { | ||
| 809 | touch_ids[id] = touch_point.id() + 1; | ||
| 810 | const auto [x, y] = ScaleTouch(touch_point.pos()); | ||
| 811 | const auto [touch_x, touch_y] = MapToTouchScreen(x, y); | ||
| 812 | input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, id); | ||
| 813 | } | ||
| 814 | } | ||
| 815 | } | ||
| 816 | |||
| 817 | bool GRenderWindow::TouchUpdate(const QTouchEvent::TouchPoint& touch_point) { | ||
| 818 | for (std::size_t id = 0; id < touch_ids.size(); ++id) { | ||
| 819 | if (touch_ids[id] == static_cast<std::size_t>(touch_point.id() + 1)) { | ||
| 820 | const auto [x, y] = ScaleTouch(touch_point.pos()); | ||
| 821 | const auto [touch_x, touch_y] = MapToTouchScreen(x, y); | ||
| 822 | input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, id); | ||
| 823 | return true; | ||
| 824 | } | ||
| 825 | } | ||
| 826 | return false; | ||
| 827 | } | ||
| 828 | |||
| 829 | bool GRenderWindow::TouchExist(std::size_t id, | ||
| 830 | const QList<QTouchEvent::TouchPoint>& touch_points) const { | ||
| 831 | return std::any_of(touch_points.begin(), touch_points.end(), [id](const auto& point) { | ||
| 832 | return id == static_cast<std::size_t>(point.id() + 1); | ||
| 833 | }); | ||
| 834 | } | 799 | } |
| 835 | 800 | ||
| 836 | bool GRenderWindow::event(QEvent* event) { | 801 | bool GRenderWindow::event(QEvent* event) { |
| @@ -1049,8 +1014,8 @@ QStringList GRenderWindow::GetUnsupportedGLExtensions() const { | |||
| 1049 | return unsupported_ext; | 1014 | return unsupported_ext; |
| 1050 | } | 1015 | } |
| 1051 | 1016 | ||
| 1052 | void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) { | 1017 | void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread_) { |
| 1053 | this->emu_thread = emu_thread; | 1018 | emu_thread = emu_thread_; |
| 1054 | } | 1019 | } |
| 1055 | 1020 | ||
| 1056 | void GRenderWindow::OnEmulationStopping() { | 1021 | void GRenderWindow::OnEmulationStopping() { |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 4b0ce0293..81fe52c0e 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <mutex> | 10 | #include <mutex> |
| 11 | 11 | ||
| 12 | #include <QImage> | 12 | #include <QImage> |
| 13 | #include <QStringList> | ||
| 13 | #include <QThread> | 14 | #include <QThread> |
| 14 | #include <QTouchEvent> | 15 | #include <QTouchEvent> |
| 15 | #include <QWidget> | 16 | #include <QWidget> |
| @@ -20,7 +21,6 @@ | |||
| 20 | class GRenderWindow; | 21 | class GRenderWindow; |
| 21 | class GMainWindow; | 22 | class GMainWindow; |
| 22 | class QKeyEvent; | 23 | class QKeyEvent; |
| 23 | class QStringList; | ||
| 24 | 24 | ||
| 25 | namespace Core { | 25 | namespace Core { |
| 26 | enum class SystemResultStatus : u32; | 26 | enum class SystemResultStatus : u32; |
| @@ -55,22 +55,13 @@ public: | |||
| 55 | void run() override; | 55 | void run() override; |
| 56 | 56 | ||
| 57 | /** | 57 | /** |
| 58 | * Steps the emulation thread by a single CPU instruction (if the CPU is not already running) | ||
| 59 | * @note This function is thread-safe | ||
| 60 | */ | ||
| 61 | void ExecStep() { | ||
| 62 | exec_step = true; | ||
| 63 | running_cv.notify_all(); | ||
| 64 | } | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Sets whether the emulation thread is running or not | 58 | * Sets whether the emulation thread is running or not |
| 68 | * @param running Boolean value, set the emulation thread to running if true | 59 | * @param running_ Boolean value, set the emulation thread to running if true |
| 69 | * @note This function is thread-safe | 60 | * @note This function is thread-safe |
| 70 | */ | 61 | */ |
| 71 | void SetRunning(bool running) { | 62 | void SetRunning(bool running_) { |
| 72 | std::unique_lock lock{running_mutex}; | 63 | std::unique_lock lock{running_mutex}; |
| 73 | this->running = running; | 64 | running = running_; |
| 74 | lock.unlock(); | 65 | lock.unlock(); |
| 75 | running_cv.notify_all(); | 66 | running_cv.notify_all(); |
| 76 | if (!running) { | 67 | if (!running) { |
| @@ -99,7 +90,6 @@ public: | |||
| 99 | } | 90 | } |
| 100 | 91 | ||
| 101 | private: | 92 | private: |
| 102 | bool exec_step = false; | ||
| 103 | bool running = false; | 93 | bool running = false; |
| 104 | std::stop_source stop_source; | 94 | std::stop_source stop_source; |
| 105 | std::mutex running_mutex; | 95 | std::mutex running_mutex; |
| @@ -148,8 +138,8 @@ public: | |||
| 148 | 138 | ||
| 149 | void BackupGeometry(); | 139 | void BackupGeometry(); |
| 150 | void RestoreGeometry(); | 140 | void RestoreGeometry(); |
| 151 | void restoreGeometry(const QByteArray& geometry); // overridden | 141 | void restoreGeometry(const QByteArray& geometry_); // overridden |
| 152 | QByteArray saveGeometry(); // overridden | 142 | QByteArray saveGeometry(); // overridden |
| 153 | 143 | ||
| 154 | qreal windowPixelRatio() const; | 144 | qreal windowPixelRatio() const; |
| 155 | 145 | ||
| @@ -199,7 +189,7 @@ public: | |||
| 199 | void Exit(); | 189 | void Exit(); |
| 200 | 190 | ||
| 201 | public slots: | 191 | public slots: |
| 202 | void OnEmulationStarting(EmuThread* emu_thread); | 192 | void OnEmulationStarting(EmuThread* emu_thread_); |
| 203 | void OnEmulationStopping(); | 193 | void OnEmulationStopping(); |
| 204 | void OnFramebufferSizeChanged(); | 194 | void OnFramebufferSizeChanged(); |
| 205 | 195 | ||
| @@ -217,10 +207,6 @@ private: | |||
| 217 | void TouchUpdateEvent(const QTouchEvent* event); | 207 | void TouchUpdateEvent(const QTouchEvent* event); |
| 218 | void TouchEndEvent(); | 208 | void TouchEndEvent(); |
| 219 | 209 | ||
| 220 | void TouchStart(const QTouchEvent::TouchPoint& touch_point); | ||
| 221 | bool TouchUpdate(const QTouchEvent::TouchPoint& touch_point); | ||
| 222 | bool TouchExist(std::size_t id, const QList<QTouchEvent::TouchPoint>& touch_points) const; | ||
| 223 | |||
| 224 | void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override; | 210 | void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override; |
| 225 | 211 | ||
| 226 | bool InitializeOpenGL(); | 212 | bool InitializeOpenGL(); |
| @@ -246,8 +232,6 @@ private: | |||
| 246 | bool first_frame = false; | 232 | bool first_frame = false; |
| 247 | InputCommon::TasInput::TasState last_tas_state; | 233 | InputCommon::TasInput::TasState last_tas_state; |
| 248 | 234 | ||
| 249 | std::array<std::size_t, 16> touch_ids{}; | ||
| 250 | |||
| 251 | Core::System& system; | 235 | Core::System& system; |
| 252 | 236 | ||
| 253 | protected: | 237 | protected: |
diff --git a/src/yuzu/check_vulkan.cpp b/src/yuzu/check_vulkan.cpp new file mode 100644 index 000000000..e6d66ab34 --- /dev/null +++ b/src/yuzu/check_vulkan.cpp | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 5 | |||
| 6 | #include <filesystem> | ||
| 7 | #include <fstream> | ||
| 8 | #include "common/fs/fs.h" | ||
| 9 | #include "common/fs/path_util.h" | ||
| 10 | #include "common/logging/log.h" | ||
| 11 | #include "video_core/vulkan_common/vulkan_instance.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_library.h" | ||
| 13 | #include "yuzu/check_vulkan.h" | ||
| 14 | #include "yuzu/uisettings.h" | ||
| 15 | |||
| 16 | constexpr char TEMP_FILE_NAME[] = "vulkan_check"; | ||
| 17 | |||
| 18 | bool CheckVulkan() { | ||
| 19 | if (UISettings::values.has_broken_vulkan) { | ||
| 20 | return true; | ||
| 21 | } | ||
| 22 | |||
| 23 | LOG_DEBUG(Frontend, "Checking presence of Vulkan"); | ||
| 24 | |||
| 25 | const auto fs_config_loc = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir); | ||
| 26 | const auto temp_file_loc = fs_config_loc / TEMP_FILE_NAME; | ||
| 27 | |||
| 28 | if (std::filesystem::exists(temp_file_loc)) { | ||
| 29 | LOG_WARNING(Frontend, "Detected recovery from previous failed Vulkan initialization"); | ||
| 30 | |||
| 31 | UISettings::values.has_broken_vulkan = true; | ||
| 32 | std::filesystem::remove(temp_file_loc); | ||
| 33 | return false; | ||
| 34 | } | ||
| 35 | |||
| 36 | std::ofstream temp_file_handle(temp_file_loc); | ||
| 37 | temp_file_handle.close(); | ||
| 38 | |||
| 39 | try { | ||
| 40 | Vulkan::vk::InstanceDispatch dld; | ||
| 41 | const Common::DynamicLibrary library = Vulkan::OpenLibrary(); | ||
| 42 | const Vulkan::vk::Instance instance = | ||
| 43 | Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0); | ||
| 44 | |||
| 45 | } catch (const Vulkan::vk::Exception& exception) { | ||
| 46 | LOG_ERROR(Frontend, "Failed to initialize Vulkan: {}", exception.what()); | ||
| 47 | // Don't set has_broken_vulkan to true here: we care when loading Vulkan crashes the | ||
| 48 | // application, not when we can handle it. | ||
| 49 | } | ||
| 50 | |||
| 51 | std::filesystem::remove(temp_file_loc); | ||
| 52 | return true; | ||
| 53 | } | ||
diff --git a/src/yuzu/check_vulkan.h b/src/yuzu/check_vulkan.h new file mode 100644 index 000000000..e4ea93582 --- /dev/null +++ b/src/yuzu/check_vulkan.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | bool CheckVulkan(); | ||
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index ac26b885b..9df4752be 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -71,28 +71,28 @@ const std::array<int, 2> Config::default_ringcon_analogs{{ | |||
| 71 | // UISetting::values.shortcuts, which is alphabetically ordered. | 71 | // UISetting::values.shortcuts, which is alphabetically ordered. |
| 72 | // clang-format off | 72 | // clang-format off |
| 73 | const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{ | 73 | const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{ |
| 74 | {QStringLiteral("Audio Mute/Unmute"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut}}, | 74 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut}}, |
| 75 | {QStringLiteral("Audio Volume Down"), QStringLiteral("Main Window"), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut}}, | 75 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut}}, |
| 76 | {QStringLiteral("Audio Volume Up"), QStringLiteral("Main Window"), {QStringLiteral("+"), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut}}, | 76 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("+"), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut}}, |
| 77 | {QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut}}, | 77 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut}}, |
| 78 | {QStringLiteral("Change Adapting Filter"), QStringLiteral("Main Window"), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut}}, | 78 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut}}, |
| 79 | {QStringLiteral("Change Docked Mode"), QStringLiteral("Main Window"), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut}}, | 79 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut}}, |
| 80 | {QStringLiteral("Change GPU Accuracy"), QStringLiteral("Main Window"), {QStringLiteral("F9"), QStringLiteral("Home+R"), Qt::ApplicationShortcut}}, | 80 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F9"), QStringLiteral("Home+R"), Qt::ApplicationShortcut}}, |
| 81 | {QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut}}, | 81 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut}}, |
| 82 | {QStringLiteral("Exit Fullscreen"), QStringLiteral("Main Window"), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut}}, | 82 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut}}, |
| 83 | {QStringLiteral("Exit yuzu"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut}}, | 83 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit yuzu")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut}}, |
| 84 | {QStringLiteral("Fullscreen"), QStringLiteral("Main Window"), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut}}, | 84 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut}}, |
| 85 | {QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut}}, | 85 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut}}, |
| 86 | {QStringLiteral("Load/Remove Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut}}, | 86 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut}}, |
| 87 | {QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), QStringLiteral(""), Qt::WindowShortcut}}, | 87 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F6"), QStringLiteral(""), Qt::WindowShortcut}}, |
| 88 | {QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), QStringLiteral(""), Qt::WindowShortcut}}, | 88 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F5"), QStringLiteral(""), Qt::WindowShortcut}}, |
| 89 | {QStringLiteral("TAS Record"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut}}, | 89 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut}}, |
| 90 | {QStringLiteral("TAS Reset"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut}}, | 90 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut}}, |
| 91 | {QStringLiteral("TAS Start/Stop"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut}}, | 91 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut}}, |
| 92 | {QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut}}, | 92 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut}}, |
| 93 | {QStringLiteral("Toggle Framerate Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut}}, | 93 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut}}, |
| 94 | {QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut}}, | 94 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut}}, |
| 95 | {QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut}}, | 95 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut}}, |
| 96 | }}; | 96 | }}; |
| 97 | // clang-format on | 97 | // clang-format on |
| 98 | 98 | ||
| @@ -525,6 +525,9 @@ void Config::ReadDebuggingValues() { | |||
| 525 | // Intentionally not using the QT default setting as this is intended to be changed in the ini | 525 | // Intentionally not using the QT default setting as this is intended to be changed in the ini |
| 526 | Settings::values.record_frame_times = | 526 | Settings::values.record_frame_times = |
| 527 | qt_config->value(QStringLiteral("record_frame_times"), false).toBool(); | 527 | qt_config->value(QStringLiteral("record_frame_times"), false).toBool(); |
| 528 | |||
| 529 | ReadBasicSetting(Settings::values.use_gdbstub); | ||
| 530 | ReadBasicSetting(Settings::values.gdbstub_port); | ||
| 528 | ReadBasicSetting(Settings::values.program_args); | 531 | ReadBasicSetting(Settings::values.program_args); |
| 529 | ReadBasicSetting(Settings::values.dump_exefs); | 532 | ReadBasicSetting(Settings::values.dump_exefs); |
| 530 | ReadBasicSetting(Settings::values.dump_nso); | 533 | ReadBasicSetting(Settings::values.dump_nso); |
| @@ -679,6 +682,12 @@ void Config::ReadRendererValues() { | |||
| 679 | ReadGlobalSetting(Settings::values.bg_green); | 682 | ReadGlobalSetting(Settings::values.bg_green); |
| 680 | ReadGlobalSetting(Settings::values.bg_blue); | 683 | ReadGlobalSetting(Settings::values.bg_blue); |
| 681 | 684 | ||
| 685 | if (!global && UISettings::values.has_broken_vulkan && | ||
| 686 | Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::Vulkan && | ||
| 687 | !Settings::values.renderer_backend.UsingGlobal()) { | ||
| 688 | Settings::values.renderer_backend.SetGlobal(true); | ||
| 689 | } | ||
| 690 | |||
| 682 | if (global) { | 691 | if (global) { |
| 683 | ReadBasicSetting(Settings::values.renderer_debug); | 692 | ReadBasicSetting(Settings::values.renderer_debug); |
| 684 | ReadBasicSetting(Settings::values.renderer_shader_feedback); | 693 | ReadBasicSetting(Settings::values.renderer_shader_feedback); |
| @@ -798,6 +807,7 @@ void Config::ReadUIValues() { | |||
| 798 | ReadBasicSetting(UISettings::values.pause_when_in_background); | 807 | ReadBasicSetting(UISettings::values.pause_when_in_background); |
| 799 | ReadBasicSetting(UISettings::values.mute_when_in_background); | 808 | ReadBasicSetting(UISettings::values.mute_when_in_background); |
| 800 | ReadBasicSetting(UISettings::values.hide_mouse); | 809 | ReadBasicSetting(UISettings::values.hide_mouse); |
| 810 | ReadBasicSetting(UISettings::values.has_broken_vulkan); | ||
| 801 | ReadBasicSetting(UISettings::values.disable_web_applet); | 811 | ReadBasicSetting(UISettings::values.disable_web_applet); |
| 802 | 812 | ||
| 803 | qt_config->endGroup(); | 813 | qt_config->endGroup(); |
| @@ -1095,6 +1105,8 @@ void Config::SaveDebuggingValues() { | |||
| 1095 | 1105 | ||
| 1096 | // Intentionally not using the QT default setting as this is intended to be changed in the ini | 1106 | // Intentionally not using the QT default setting as this is intended to be changed in the ini |
| 1097 | qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times); | 1107 | qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times); |
| 1108 | WriteBasicSetting(Settings::values.use_gdbstub); | ||
| 1109 | WriteBasicSetting(Settings::values.gdbstub_port); | ||
| 1098 | WriteBasicSetting(Settings::values.program_args); | 1110 | WriteBasicSetting(Settings::values.program_args); |
| 1099 | WriteBasicSetting(Settings::values.dump_exefs); | 1111 | WriteBasicSetting(Settings::values.dump_exefs); |
| 1100 | WriteBasicSetting(Settings::values.dump_nso); | 1112 | WriteBasicSetting(Settings::values.dump_nso); |
| @@ -1343,6 +1355,7 @@ void Config::SaveUIValues() { | |||
| 1343 | WriteBasicSetting(UISettings::values.pause_when_in_background); | 1355 | WriteBasicSetting(UISettings::values.pause_when_in_background); |
| 1344 | WriteBasicSetting(UISettings::values.mute_when_in_background); | 1356 | WriteBasicSetting(UISettings::values.mute_when_in_background); |
| 1345 | WriteBasicSetting(UISettings::values.hide_mouse); | 1357 | WriteBasicSetting(UISettings::values.hide_mouse); |
| 1358 | WriteBasicSetting(UISettings::values.has_broken_vulkan); | ||
| 1346 | WriteBasicSetting(UISettings::values.disable_web_applet); | 1359 | WriteBasicSetting(UISettings::values.disable_web_applet); |
| 1347 | 1360 | ||
| 1348 | qt_config->endGroup(); | 1361 | qt_config->endGroup(); |
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index bd50f7a68..343d2aee1 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp | |||
| @@ -24,13 +24,18 @@ ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent) | |||
| 24 | QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::LogDir)); | 24 | QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::LogDir)); |
| 25 | QDesktopServices::openUrl(QUrl::fromLocalFile(path)); | 25 | QDesktopServices::openUrl(QUrl::fromLocalFile(path)); |
| 26 | }); | 26 | }); |
| 27 | |||
| 28 | connect(ui->toggle_gdbstub, &QCheckBox::toggled, | ||
| 29 | [&]() { ui->gdbport_spinbox->setEnabled(ui->toggle_gdbstub->isChecked()); }); | ||
| 27 | } | 30 | } |
| 28 | 31 | ||
| 29 | ConfigureDebug::~ConfigureDebug() = default; | 32 | ConfigureDebug::~ConfigureDebug() = default; |
| 30 | 33 | ||
| 31 | void ConfigureDebug::SetConfiguration() { | 34 | void ConfigureDebug::SetConfiguration() { |
| 32 | const bool runtime_lock = !system.IsPoweredOn(); | 35 | const bool runtime_lock = !system.IsPoweredOn(); |
| 33 | 36 | ui->toggle_gdbstub->setChecked(Settings::values.use_gdbstub.GetValue()); | |
| 37 | ui->gdbport_spinbox->setEnabled(Settings::values.use_gdbstub.GetValue()); | ||
| 38 | ui->gdbport_spinbox->setValue(Settings::values.gdbstub_port.GetValue()); | ||
| 34 | ui->toggle_console->setEnabled(runtime_lock); | 39 | ui->toggle_console->setEnabled(runtime_lock); |
| 35 | ui->toggle_console->setChecked(UISettings::values.show_console.GetValue()); | 40 | ui->toggle_console->setChecked(UISettings::values.show_console.GetValue()); |
| 36 | ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue())); | 41 | ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue())); |
| @@ -53,6 +58,8 @@ void ConfigureDebug::SetConfiguration() { | |||
| 53 | ui->enable_nsight_aftermath->setChecked(Settings::values.enable_nsight_aftermath.GetValue()); | 58 | ui->enable_nsight_aftermath->setChecked(Settings::values.enable_nsight_aftermath.GetValue()); |
| 54 | ui->dump_shaders->setEnabled(runtime_lock); | 59 | ui->dump_shaders->setEnabled(runtime_lock); |
| 55 | ui->dump_shaders->setChecked(Settings::values.dump_shaders.GetValue()); | 60 | ui->dump_shaders->setChecked(Settings::values.dump_shaders.GetValue()); |
| 61 | ui->dump_macros->setEnabled(runtime_lock); | ||
| 62 | ui->dump_macros->setChecked(Settings::values.dump_macros.GetValue()); | ||
| 56 | ui->disable_macro_jit->setEnabled(runtime_lock); | 63 | ui->disable_macro_jit->setEnabled(runtime_lock); |
| 57 | ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue()); | 64 | ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue()); |
| 58 | ui->disable_loop_safety_checks->setEnabled(runtime_lock); | 65 | ui->disable_loop_safety_checks->setEnabled(runtime_lock); |
| @@ -69,6 +76,8 @@ void ConfigureDebug::SetConfiguration() { | |||
| 69 | } | 76 | } |
| 70 | 77 | ||
| 71 | void ConfigureDebug::ApplyConfiguration() { | 78 | void ConfigureDebug::ApplyConfiguration() { |
| 79 | Settings::values.use_gdbstub = ui->toggle_gdbstub->isChecked(); | ||
| 80 | Settings::values.gdbstub_port = ui->gdbport_spinbox->value(); | ||
| 72 | UISettings::values.show_console = ui->toggle_console->isChecked(); | 81 | UISettings::values.show_console = ui->toggle_console->isChecked(); |
| 73 | Settings::values.log_filter = ui->log_filter_edit->text().toStdString(); | 82 | Settings::values.log_filter = ui->log_filter_edit->text().toStdString(); |
| 74 | Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); | 83 | Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); |
| @@ -83,6 +92,7 @@ void ConfigureDebug::ApplyConfiguration() { | |||
| 83 | Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked(); | 92 | Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked(); |
| 84 | Settings::values.enable_nsight_aftermath = ui->enable_nsight_aftermath->isChecked(); | 93 | Settings::values.enable_nsight_aftermath = ui->enable_nsight_aftermath->isChecked(); |
| 85 | Settings::values.dump_shaders = ui->dump_shaders->isChecked(); | 94 | Settings::values.dump_shaders = ui->dump_shaders->isChecked(); |
| 95 | Settings::values.dump_macros = ui->dump_macros->isChecked(); | ||
| 86 | Settings::values.disable_shader_loop_safety_checks = | 96 | Settings::values.disable_shader_loop_safety_checks = |
| 87 | ui->disable_loop_safety_checks->isChecked(); | 97 | ui->disable_loop_safety_checks->isChecked(); |
| 88 | Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); | 98 | Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); |
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index c1d90d588..1152fa6c6 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui | |||
| @@ -3,6 +3,60 @@ | |||
| 3 | <class>ConfigureDebug</class> | 3 | <class>ConfigureDebug</class> |
| 4 | <widget class="QWidget" name="ConfigureDebug"> | 4 | <widget class="QWidget" name="ConfigureDebug"> |
| 5 | <layout class="QVBoxLayout" name="verticalLayout_1"> | 5 | <layout class="QVBoxLayout" name="verticalLayout_1"> |
| 6 | <item> | ||
| 7 | <layout class="QVBoxLayout" name="verticalLayout_2"> | ||
| 8 | <item> | ||
| 9 | <widget class="QGroupBox" name="groupBox"> | ||
| 10 | <property name="title"> | ||
| 11 | <string>Debugger</string> | ||
| 12 | </property> | ||
| 13 | <layout class="QVBoxLayout" name="verticalLayout_3"> | ||
| 14 | <item> | ||
| 15 | <layout class="QHBoxLayout" name="horizontalLayout_11"> | ||
| 16 | <item> | ||
| 17 | <widget class="QCheckBox" name="toggle_gdbstub"> | ||
| 18 | <property name="text"> | ||
| 19 | <string>Enable GDB Stub</string> | ||
| 20 | </property> | ||
| 21 | </widget> | ||
| 22 | </item> | ||
| 23 | <item> | ||
| 24 | <spacer name="horizontalSpacer"> | ||
| 25 | <property name="orientation"> | ||
| 26 | <enum>Qt::Horizontal</enum> | ||
| 27 | </property> | ||
| 28 | <property name="sizeHint" stdset="0"> | ||
| 29 | <size> | ||
| 30 | <width>40</width> | ||
| 31 | <height>20</height> | ||
| 32 | </size> | ||
| 33 | </property> | ||
| 34 | </spacer> | ||
| 35 | </item> | ||
| 36 | <item> | ||
| 37 | <widget class="QLabel" name="label_11"> | ||
| 38 | <property name="text"> | ||
| 39 | <string>Port:</string> | ||
| 40 | </property> | ||
| 41 | </widget> | ||
| 42 | </item> | ||
| 43 | <item> | ||
| 44 | <widget class="QSpinBox" name="gdbport_spinbox"> | ||
| 45 | <property name="minimum"> | ||
| 46 | <number>1024</number> | ||
| 47 | </property> | ||
| 48 | <property name="maximum"> | ||
| 49 | <number>65535</number> | ||
| 50 | </property> | ||
| 51 | </widget> | ||
| 52 | </item> | ||
| 53 | </layout> | ||
| 54 | </item> | ||
| 55 | </layout> | ||
| 56 | </widget> | ||
| 57 | </item> | ||
| 58 | </layout> | ||
| 59 | </item> | ||
| 6 | <item> | 60 | <item> |
| 7 | <widget class="QGroupBox" name="groupBox_2"> | 61 | <widget class="QGroupBox" name="groupBox_2"> |
| 8 | <property name="title"> | 62 | <property name="title"> |
| @@ -118,6 +172,19 @@ | |||
| 118 | </property> | 172 | </property> |
| 119 | </widget> | 173 | </widget> |
| 120 | </item> | 174 | </item> |
| 175 | <item row="0" column="2"> | ||
| 176 | <widget class="QCheckBox" name="dump_macros"> | ||
| 177 | <property name="enabled"> | ||
| 178 | <bool>true</bool> | ||
| 179 | </property> | ||
| 180 | <property name="toolTip"> | ||
| 181 | <string>When checked, it will dump all the macro programs of the GPU</string> | ||
| 182 | </property> | ||
| 183 | <property name="text"> | ||
| 184 | <string>Dump Maxwell Macros</string> | ||
| 185 | </property> | ||
| 186 | </widget> | ||
| 187 | </item> | ||
| 121 | <item row="0" column="1"> | 188 | <item row="0" column="1"> |
| 122 | <widget class="QCheckBox" name="disable_macro_jit"> | 189 | <widget class="QCheckBox" name="disable_macro_jit"> |
| 123 | <property name="enabled"> | 190 | <property name="enabled"> |
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index b415a1cc4..e99657bd6 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp | |||
| @@ -27,12 +27,11 @@ | |||
| 27 | #include "yuzu/hotkeys.h" | 27 | #include "yuzu/hotkeys.h" |
| 28 | #include "yuzu/uisettings.h" | 28 | #include "yuzu/uisettings.h" |
| 29 | 29 | ||
| 30 | ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, | 30 | ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, |
| 31 | InputCommon::InputSubsystem* input_subsystem, | 31 | InputCommon::InputSubsystem* input_subsystem, |
| 32 | Core::System& system_) | 32 | Core::System& system_) |
| 33 | : QDialog(parent), ui{std::make_unique<Ui::ConfigureDialog>()}, | 33 | : QDialog(parent), ui{std::make_unique<Ui::ConfigureDialog>()}, registry{registry_}, |
| 34 | registry(registry), system{system_}, audio_tab{std::make_unique<ConfigureAudio>(system_, | 34 | system{system_}, audio_tab{std::make_unique<ConfigureAudio>(system_, this)}, |
| 35 | this)}, | ||
| 36 | cpu_tab{std::make_unique<ConfigureCpu>(system_, this)}, | 35 | cpu_tab{std::make_unique<ConfigureCpu>(system_, this)}, |
| 37 | debug_tab_tab{std::make_unique<ConfigureDebugTab>(system_, this)}, | 36 | debug_tab_tab{std::make_unique<ConfigureDebugTab>(system_, this)}, |
| 38 | filesystem_tab{std::make_unique<ConfigureFilesystem>(this)}, | 37 | filesystem_tab{std::make_unique<ConfigureFilesystem>(this)}, |
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index 32ddfd4e0..12cf25daf 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h | |||
| @@ -40,7 +40,7 @@ class ConfigureDialog : public QDialog { | |||
| 40 | Q_OBJECT | 40 | Q_OBJECT |
| 41 | 41 | ||
| 42 | public: | 42 | public: |
| 43 | explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, | 43 | explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, |
| 44 | InputCommon::InputSubsystem* input_subsystem, Core::System& system_); | 44 | InputCommon::InputSubsystem* input_subsystem, Core::System& system_); |
| 45 | ~ConfigureDialog() override; | 45 | ~ConfigureDialog() override; |
| 46 | 46 | ||
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 2f1435b10..85f34dc35 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include "video_core/vulkan_common/vulkan_library.h" | 17 | #include "video_core/vulkan_common/vulkan_library.h" |
| 18 | #include "yuzu/configuration/configuration_shared.h" | 18 | #include "yuzu/configuration/configuration_shared.h" |
| 19 | #include "yuzu/configuration/configure_graphics.h" | 19 | #include "yuzu/configuration/configure_graphics.h" |
| 20 | #include "yuzu/uisettings.h" | ||
| 20 | 21 | ||
| 21 | ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* parent) | 22 | ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* parent) |
| 22 | : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, system{system_} { | 23 | : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, system{system_} { |
| @@ -57,6 +58,24 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* paren | |||
| 57 | UpdateBackgroundColorButton(new_bg_color); | 58 | UpdateBackgroundColorButton(new_bg_color); |
| 58 | }); | 59 | }); |
| 59 | 60 | ||
| 61 | connect(ui->button_check_vulkan, &QAbstractButton::clicked, this, [this] { | ||
| 62 | UISettings::values.has_broken_vulkan = false; | ||
| 63 | |||
| 64 | if (RetrieveVulkanDevices()) { | ||
| 65 | ui->api->setEnabled(true); | ||
| 66 | ui->button_check_vulkan->hide(); | ||
| 67 | |||
| 68 | for (const auto& device : vulkan_devices) { | ||
| 69 | ui->device->addItem(device); | ||
| 70 | } | ||
| 71 | } else { | ||
| 72 | UISettings::values.has_broken_vulkan = true; | ||
| 73 | } | ||
| 74 | }); | ||
| 75 | |||
| 76 | ui->api->setEnabled(!UISettings::values.has_broken_vulkan.GetValue()); | ||
| 77 | ui->button_check_vulkan->setVisible(UISettings::values.has_broken_vulkan.GetValue()); | ||
| 78 | |||
| 60 | ui->bg_label->setVisible(Settings::IsConfiguringGlobal()); | 79 | ui->bg_label->setVisible(Settings::IsConfiguringGlobal()); |
| 61 | ui->bg_combobox->setVisible(!Settings::IsConfiguringGlobal()); | 80 | ui->bg_combobox->setVisible(!Settings::IsConfiguringGlobal()); |
| 62 | } | 81 | } |
| @@ -296,7 +315,7 @@ void ConfigureGraphics::UpdateAPILayout() { | |||
| 296 | vulkan_device = Settings::values.vulkan_device.GetValue(true); | 315 | vulkan_device = Settings::values.vulkan_device.GetValue(true); |
| 297 | shader_backend = Settings::values.shader_backend.GetValue(true); | 316 | shader_backend = Settings::values.shader_backend.GetValue(true); |
| 298 | ui->device_widget->setEnabled(false); | 317 | ui->device_widget->setEnabled(false); |
| 299 | ui->backend_widget->setEnabled(false); | 318 | ui->backend_widget->setEnabled(UISettings::values.has_broken_vulkan.GetValue()); |
| 300 | } else { | 319 | } else { |
| 301 | vulkan_device = Settings::values.vulkan_device.GetValue(); | 320 | vulkan_device = Settings::values.vulkan_device.GetValue(); |
| 302 | shader_backend = Settings::values.shader_backend.GetValue(); | 321 | shader_backend = Settings::values.shader_backend.GetValue(); |
| @@ -318,7 +337,11 @@ void ConfigureGraphics::UpdateAPILayout() { | |||
| 318 | } | 337 | } |
| 319 | } | 338 | } |
| 320 | 339 | ||
| 321 | void ConfigureGraphics::RetrieveVulkanDevices() try { | 340 | bool ConfigureGraphics::RetrieveVulkanDevices() try { |
| 341 | if (UISettings::values.has_broken_vulkan) { | ||
| 342 | return false; | ||
| 343 | } | ||
| 344 | |||
| 322 | using namespace Vulkan; | 345 | using namespace Vulkan; |
| 323 | 346 | ||
| 324 | vk::InstanceDispatch dld; | 347 | vk::InstanceDispatch dld; |
| @@ -333,8 +356,10 @@ void ConfigureGraphics::RetrieveVulkanDevices() try { | |||
| 333 | vulkan_devices.push_back(QString::fromStdString(name)); | 356 | vulkan_devices.push_back(QString::fromStdString(name)); |
| 334 | } | 357 | } |
| 335 | 358 | ||
| 359 | return true; | ||
| 336 | } catch (const Vulkan::vk::Exception& exception) { | 360 | } catch (const Vulkan::vk::Exception& exception) { |
| 337 | LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what()); | 361 | LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what()); |
| 362 | return false; | ||
| 338 | } | 363 | } |
| 339 | 364 | ||
| 340 | Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const { | 365 | Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const { |
| @@ -415,4 +440,11 @@ void ConfigureGraphics::SetupPerGameUI() { | |||
| 415 | ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); | 440 | ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); |
| 416 | ConfigurationShared::InsertGlobalItem( | 441 | ConfigurationShared::InsertGlobalItem( |
| 417 | ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true))); | 442 | ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true))); |
| 443 | |||
| 444 | if (UISettings::values.has_broken_vulkan) { | ||
| 445 | ui->backend_widget->setEnabled(true); | ||
| 446 | ConfigurationShared::SetColoredComboBox( | ||
| 447 | ui->backend, ui->backend_widget, | ||
| 448 | static_cast<int>(Settings::values.shader_backend.GetValue(true))); | ||
| 449 | } | ||
| 418 | } | 450 | } |
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index 1b101c940..8438f0187 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h | |||
| @@ -41,7 +41,7 @@ private: | |||
| 41 | void UpdateDeviceSelection(int device); | 41 | void UpdateDeviceSelection(int device); |
| 42 | void UpdateShaderBackendSelection(int backend); | 42 | void UpdateShaderBackendSelection(int backend); |
| 43 | 43 | ||
| 44 | void RetrieveVulkanDevices(); | 44 | bool RetrieveVulkanDevices(); |
| 45 | 45 | ||
| 46 | void SetupPerGameUI(); | 46 | void SetupPerGameUI(); |
| 47 | 47 | ||
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 74f0e0b79..2f94c94bc 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | <rect> | 6 | <rect> |
| 7 | <x>0</x> | 7 | <x>0</x> |
| 8 | <y>0</y> | 8 | <y>0</y> |
| 9 | <width>437</width> | 9 | <width>471</width> |
| 10 | <height>482</height> | 10 | <height>759</height> |
| 11 | </rect> | 11 | </rect> |
| 12 | </property> | 12 | </property> |
| 13 | <property name="windowTitle"> | 13 | <property name="windowTitle"> |
| @@ -171,11 +171,11 @@ | |||
| 171 | </widget> | 171 | </widget> |
| 172 | </item> | 172 | </item> |
| 173 | <item> | 173 | <item> |
| 174 | <widget class="QCheckBox" name="accelerate_astc"> | 174 | <widget class="QCheckBox" name="accelerate_astc"> |
| 175 | <property name="text"> | 175 | <property name="text"> |
| 176 | <string>Accelerate ASTC texture decoding</string> | 176 | <string>Accelerate ASTC texture decoding</string> |
| 177 | </property> | 177 | </property> |
| 178 | </widget> | 178 | </widget> |
| 179 | </item> | 179 | </item> |
| 180 | <item> | 180 | <item> |
| 181 | <widget class="QWidget" name="nvdec_emulation_widget" native="true"> | 181 | <widget class="QWidget" name="nvdec_emulation_widget" native="true"> |
| @@ -438,43 +438,43 @@ | |||
| 438 | </widget> | 438 | </widget> |
| 439 | </item> | 439 | </item> |
| 440 | <item> | 440 | <item> |
| 441 | <widget class="QWidget" name="anti_aliasing_layout" native="true"> | 441 | <widget class="QWidget" name="anti_aliasing_layout" native="true"> |
| 442 | <layout class="QHBoxLayout" name="horizontalLayout_7"> | 442 | <layout class="QHBoxLayout" name="horizontalLayout_7"> |
| 443 | <property name="leftMargin"> | 443 | <property name="leftMargin"> |
| 444 | <number>0</number> | 444 | <number>0</number> |
| 445 | </property> | 445 | </property> |
| 446 | <property name="topMargin"> | 446 | <property name="topMargin"> |
| 447 | <number>0</number> | 447 | <number>0</number> |
| 448 | </property> | 448 | </property> |
| 449 | <property name="rightMargin"> | 449 | <property name="rightMargin"> |
| 450 | <number>0</number> | 450 | <number>0</number> |
| 451 | </property> | ||
| 452 | <property name="bottomMargin"> | ||
| 453 | <number>0</number> | ||
| 454 | </property> | ||
| 455 | <item> | ||
| 456 | <widget class="QLabel" name="anti_aliasing_label"> | ||
| 457 | <property name="text"> | ||
| 458 | <string>Anti-Aliasing Method:</string> | ||
| 459 | </property> | ||
| 460 | </widget> | ||
| 461 | </item> | ||
| 462 | <item> | ||
| 463 | <widget class="QComboBox" name="anti_aliasing_combobox"> | ||
| 464 | <item> | ||
| 465 | <property name="text"> | ||
| 466 | <string>None</string> | ||
| 451 | </property> | 467 | </property> |
| 452 | <property name="bottomMargin"> | 468 | </item> |
| 453 | <number>0</number> | 469 | <item> |
| 470 | <property name="text"> | ||
| 471 | <string>FXAA</string> | ||
| 454 | </property> | 472 | </property> |
| 455 | <item> | 473 | </item> |
| 456 | <widget class="QLabel" name="anti_aliasing_label"> | 474 | </widget> |
| 457 | <property name="text"> | 475 | </item> |
| 458 | <string>Anti-Aliasing Method:</string> | 476 | </layout> |
| 459 | </property> | 477 | </widget> |
| 460 | </widget> | ||
| 461 | </item> | ||
| 462 | <item> | ||
| 463 | <widget class="QComboBox" name="anti_aliasing_combobox"> | ||
| 464 | <item> | ||
| 465 | <property name="text"> | ||
| 466 | <string>None</string> | ||
| 467 | </property> | ||
| 468 | </item> | ||
| 469 | <item> | ||
| 470 | <property name="text"> | ||
| 471 | <string>FXAA</string> | ||
| 472 | </property> | ||
| 473 | </item> | ||
| 474 | </widget> | ||
| 475 | </item> | ||
| 476 | </layout> | ||
| 477 | </widget> | ||
| 478 | </item> | 478 | </item> |
| 479 | <item> | 479 | <item> |
| 480 | <widget class="QWidget" name="bg_layout" native="true"> | 480 | <widget class="QWidget" name="bg_layout" native="true"> |
| @@ -574,6 +574,13 @@ | |||
| 574 | </property> | 574 | </property> |
| 575 | </spacer> | 575 | </spacer> |
| 576 | </item> | 576 | </item> |
| 577 | <item> | ||
| 578 | <widget class="QPushButton" name="button_check_vulkan"> | ||
| 579 | <property name="text"> | ||
| 580 | <string>Check for Working Vulkan</string> | ||
| 581 | </property> | ||
| 582 | </widget> | ||
| 583 | </item> | ||
| 577 | </layout> | 584 | </layout> |
| 578 | </widget> | 585 | </widget> |
| 579 | <resources/> | 586 | <resources/> |
diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index 6679e9c53..edf0893c4 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp | |||
| @@ -61,14 +61,18 @@ ConfigureHotkeys::~ConfigureHotkeys() = default; | |||
| 61 | 61 | ||
| 62 | void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { | 62 | void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { |
| 63 | for (const auto& group : registry.hotkey_groups) { | 63 | for (const auto& group : registry.hotkey_groups) { |
| 64 | auto* parent_item = new QStandardItem(group.first); | 64 | auto* parent_item = |
| 65 | new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(group.first))); | ||
| 65 | parent_item->setEditable(false); | 66 | parent_item->setEditable(false); |
| 67 | parent_item->setData(group.first); | ||
| 66 | for (const auto& hotkey : group.second) { | 68 | for (const auto& hotkey : group.second) { |
| 67 | auto* action = new QStandardItem(hotkey.first); | 69 | auto* action = |
| 70 | new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(hotkey.first))); | ||
| 68 | auto* keyseq = | 71 | auto* keyseq = |
| 69 | new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText)); | 72 | new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText)); |
| 70 | auto* controller_keyseq = new QStandardItem(hotkey.second.controller_keyseq); | 73 | auto* controller_keyseq = new QStandardItem(hotkey.second.controller_keyseq); |
| 71 | action->setEditable(false); | 74 | action->setEditable(false); |
| 75 | action->setData(hotkey.first); | ||
| 72 | keyseq->setEditable(false); | 76 | keyseq->setEditable(false); |
| 73 | controller_keyseq->setEditable(false); | 77 | controller_keyseq->setEditable(false); |
| 74 | parent_item->appendRow({action, keyseq, controller_keyseq}); | 78 | parent_item->appendRow({action, keyseq, controller_keyseq}); |
| @@ -93,6 +97,16 @@ void ConfigureHotkeys::RetranslateUI() { | |||
| 93 | ui->retranslateUi(this); | 97 | ui->retranslateUi(this); |
| 94 | 98 | ||
| 95 | model->setHorizontalHeaderLabels({tr("Action"), tr("Hotkey"), tr("Controller Hotkey")}); | 99 | model->setHorizontalHeaderLabels({tr("Action"), tr("Hotkey"), tr("Controller Hotkey")}); |
| 100 | for (int key_id = 0; key_id < model->rowCount(); key_id++) { | ||
| 101 | QStandardItem* parent = model->item(key_id, 0); | ||
| 102 | parent->setText( | ||
| 103 | QCoreApplication::translate("Hotkeys", qPrintable(parent->data().toString()))); | ||
| 104 | for (int key_column_id = 0; key_column_id < parent->rowCount(); key_column_id++) { | ||
| 105 | QStandardItem* action = parent->child(key_column_id, name_column); | ||
| 106 | action->setText( | ||
| 107 | QCoreApplication::translate("Hotkeys", qPrintable(action->data().toString()))); | ||
| 108 | } | ||
| 109 | } | ||
| 96 | } | 110 | } |
| 97 | 111 | ||
| 98 | void ConfigureHotkeys::Configure(QModelIndex index) { | 112 | void ConfigureHotkeys::Configure(QModelIndex index) { |
| @@ -273,10 +287,10 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) { | |||
| 273 | const QStandardItem* controller_keyseq = | 287 | const QStandardItem* controller_keyseq = |
| 274 | parent->child(key_column_id, controller_column); | 288 | parent->child(key_column_id, controller_column); |
| 275 | for (auto& [group, sub_actions] : registry.hotkey_groups) { | 289 | for (auto& [group, sub_actions] : registry.hotkey_groups) { |
| 276 | if (group != parent->text()) | 290 | if (group != parent->data()) |
| 277 | continue; | 291 | continue; |
| 278 | for (auto& [action_name, hotkey] : sub_actions) { | 292 | for (auto& [action_name, hotkey] : sub_actions) { |
| 279 | if (action_name != action->text()) | 293 | if (action_name != action->data()) |
| 280 | continue; | 294 | continue; |
| 281 | hotkey.keyseq = QKeySequence(keyseq->text()); | 295 | hotkey.keyseq = QKeySequence(keyseq->text()); |
| 282 | hotkey.controller_keyseq = controller_keyseq->text(); | 296 | hotkey.controller_keyseq = controller_keyseq->text(); |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 1c05dd0f3..f3be9a374 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -264,15 +264,16 @@ QString ConfigureInputPlayer::AnalogToText(const Common::ParamPackage& param, | |||
| 264 | return QObject::tr("[unknown]"); | 264 | return QObject::tr("[unknown]"); |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, | 267 | ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index_, |
| 268 | QWidget* bottom_row, | 268 | QWidget* bottom_row_, |
| 269 | InputCommon::InputSubsystem* input_subsystem_, | 269 | InputCommon::InputSubsystem* input_subsystem_, |
| 270 | InputProfiles* profiles_, Core::HID::HIDCore& hid_core_, | 270 | InputProfiles* profiles_, Core::HID::HIDCore& hid_core_, |
| 271 | bool is_powered_on_, bool debug) | 271 | bool is_powered_on_, bool debug_) |
| 272 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index), | 272 | : QWidget(parent), |
| 273 | debug(debug), is_powered_on{is_powered_on_}, input_subsystem{input_subsystem_}, | 273 | ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index{player_index_}, debug{debug_}, |
| 274 | profiles(profiles_), timeout_timer(std::make_unique<QTimer>()), | 274 | is_powered_on{is_powered_on_}, input_subsystem{input_subsystem_}, profiles(profiles_), |
| 275 | poll_timer(std::make_unique<QTimer>()), bottom_row(bottom_row), hid_core{hid_core_} { | 275 | timeout_timer(std::make_unique<QTimer>()), |
| 276 | poll_timer(std::make_unique<QTimer>()), bottom_row{bottom_row_}, hid_core{hid_core_} { | ||
| 276 | if (player_index == 0) { | 277 | if (player_index == 0) { |
| 277 | auto* emulated_controller_p1 = | 278 | auto* emulated_controller_p1 = |
| 278 | hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); | 279 | hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); |
| @@ -696,39 +697,38 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 696 | UpdateControllerEnabledButtons(); | 697 | UpdateControllerEnabledButtons(); |
| 697 | UpdateControllerButtonNames(); | 698 | UpdateControllerButtonNames(); |
| 698 | UpdateMotionButtons(); | 699 | UpdateMotionButtons(); |
| 699 | connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), | 700 | connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), [this](int) { |
| 700 | [this, player_index](int) { | 701 | UpdateControllerAvailableButtons(); |
| 701 | UpdateControllerAvailableButtons(); | 702 | UpdateControllerEnabledButtons(); |
| 702 | UpdateControllerEnabledButtons(); | 703 | UpdateControllerButtonNames(); |
| 703 | UpdateControllerButtonNames(); | 704 | UpdateMotionButtons(); |
| 704 | UpdateMotionButtons(); | 705 | const Core::HID::NpadStyleIndex type = |
| 705 | const Core::HID::NpadStyleIndex type = | 706 | GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); |
| 706 | GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); | 707 | |
| 707 | 708 | if (player_index == 0) { | |
| 708 | if (player_index == 0) { | 709 | auto* emulated_controller_p1 = |
| 709 | auto* emulated_controller_p1 = | 710 | hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); |
| 710 | hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); | 711 | auto* emulated_controller_handheld = |
| 711 | auto* emulated_controller_handheld = | 712 | hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); |
| 712 | hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); | 713 | bool is_connected = emulated_controller->IsConnected(true); |
| 713 | bool is_connected = emulated_controller->IsConnected(true); | 714 | |
| 714 | 715 | emulated_controller_p1->SetNpadStyleIndex(type); | |
| 715 | emulated_controller_p1->SetNpadStyleIndex(type); | 716 | emulated_controller_handheld->SetNpadStyleIndex(type); |
| 716 | emulated_controller_handheld->SetNpadStyleIndex(type); | 717 | if (is_connected) { |
| 717 | if (is_connected) { | 718 | if (type == Core::HID::NpadStyleIndex::Handheld) { |
| 718 | if (type == Core::HID::NpadStyleIndex::Handheld) { | 719 | emulated_controller_p1->Disconnect(); |
| 719 | emulated_controller_p1->Disconnect(); | 720 | emulated_controller_handheld->Connect(true); |
| 720 | emulated_controller_handheld->Connect(true); | 721 | emulated_controller = emulated_controller_handheld; |
| 721 | emulated_controller = emulated_controller_handheld; | 722 | } else { |
| 722 | } else { | 723 | emulated_controller_handheld->Disconnect(); |
| 723 | emulated_controller_handheld->Disconnect(); | 724 | emulated_controller_p1->Connect(true); |
| 724 | emulated_controller_p1->Connect(true); | 725 | emulated_controller = emulated_controller_p1; |
| 725 | emulated_controller = emulated_controller_p1; | ||
| 726 | } | ||
| 727 | } | ||
| 728 | ui->controllerFrame->SetController(emulated_controller); | ||
| 729 | } | 726 | } |
| 730 | emulated_controller->SetNpadStyleIndex(type); | 727 | } |
| 731 | }); | 728 | ui->controllerFrame->SetController(emulated_controller); |
| 729 | } | ||
| 730 | emulated_controller->SetNpadStyleIndex(type); | ||
| 731 | }); | ||
| 732 | 732 | ||
| 733 | connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this, | 733 | connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this, |
| 734 | &ConfigureInputPlayer::UpdateMappingWithDefaults); | 734 | &ConfigureInputPlayer::UpdateMappingWithDefaults); |
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp index 27559c37b..c313b0919 100644 --- a/src/yuzu/configuration/configure_motion_touch.cpp +++ b/src/yuzu/configuration/configure_motion_touch.cpp | |||
| @@ -151,6 +151,8 @@ void ConfigureMotionTouch::ConnectEvents() { | |||
| 151 | &ConfigureMotionTouch::OnConfigureTouchCalibration); | 151 | &ConfigureMotionTouch::OnConfigureTouchCalibration); |
| 152 | connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this, | 152 | connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this, |
| 153 | &ConfigureMotionTouch::OnConfigureTouchFromButton); | 153 | &ConfigureMotionTouch::OnConfigureTouchFromButton); |
| 154 | connect(ui->buttonBox, &QDialogButtonBox::accepted, this, | ||
| 155 | &ConfigureMotionTouch::ApplyConfiguration); | ||
| 154 | connect(ui->buttonBox, &QDialogButtonBox::rejected, this, [this] { | 156 | connect(ui->buttonBox, &QDialogButtonBox::rejected, this, [this] { |
| 155 | if (CanCloseDialog()) { | 157 | if (CanCloseDialog()) { |
| 156 | reject(); | 158 | reject(); |
diff --git a/src/yuzu/configuration/configure_motion_touch.ui b/src/yuzu/configuration/configure_motion_touch.ui index c75a84ae4..0237fae54 100644 --- a/src/yuzu/configuration/configure_motion_touch.ui +++ b/src/yuzu/configuration/configure_motion_touch.ui | |||
| @@ -293,22 +293,5 @@ | |||
| 293 | </layout> | 293 | </layout> |
| 294 | </widget> | 294 | </widget> |
| 295 | <resources/> | 295 | <resources/> |
| 296 | <connections> | 296 | <connections/> |
| 297 | <connection> | ||
| 298 | <sender>buttonBox</sender> | ||
| 299 | <signal>accepted()</signal> | ||
| 300 | <receiver>ConfigureMotionTouch</receiver> | ||
| 301 | <slot>ApplyConfiguration()</slot> | ||
| 302 | <hints> | ||
| 303 | <hint type="sourcelabel"> | ||
| 304 | <x>20</x> | ||
| 305 | <y>20</y> | ||
| 306 | </hint> | ||
| 307 | <hint type="destinationlabel"> | ||
| 308 | <x>20</x> | ||
| 309 | <y>20</y> | ||
| 310 | </hint> | ||
| 311 | </hints> | ||
| 312 | </connection> | ||
| 313 | </connections> | ||
| 314 | </ui> | 297 | </ui> |
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 54b3fe150..af8343b2e 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp | |||
| @@ -35,10 +35,10 @@ | |||
| 35 | #include "yuzu/uisettings.h" | 35 | #include "yuzu/uisettings.h" |
| 36 | #include "yuzu/util/util.h" | 36 | #include "yuzu/util/util.h" |
| 37 | 37 | ||
| 38 | ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id, const std::string& file_name, | 38 | ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::string& file_name, |
| 39 | Core::System& system_) | 39 | Core::System& system_) |
| 40 | : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()), | 40 | : QDialog(parent), |
| 41 | title_id(title_id), system{system_} { | 41 | ui(std::make_unique<Ui::ConfigurePerGame>()), title_id{title_id_}, system{system_} { |
| 42 | const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name)); | 42 | const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name)); |
| 43 | const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()) | 43 | const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()) |
| 44 | : fmt::format("{:016X}", title_id); | 44 | : fmt::format("{:016X}", title_id); |
| @@ -116,8 +116,8 @@ void ConfigurePerGame::HandleApplyButtonClicked() { | |||
| 116 | ApplyConfiguration(); | 116 | ApplyConfiguration(); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | void ConfigurePerGame::LoadFromFile(FileSys::VirtualFile file) { | 119 | void ConfigurePerGame::LoadFromFile(FileSys::VirtualFile file_) { |
| 120 | this->file = std::move(file); | 120 | file = std::move(file_); |
| 121 | LoadConfiguration(); | 121 | LoadConfiguration(); |
| 122 | } | 122 | } |
| 123 | 123 | ||
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index e6dc05546..17a98a0f3 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h | |||
| @@ -39,14 +39,14 @@ class ConfigurePerGame : public QDialog { | |||
| 39 | 39 | ||
| 40 | public: | 40 | public: |
| 41 | // Cannot use std::filesystem::path due to https://bugreports.qt.io/browse/QTBUG-73263 | 41 | // Cannot use std::filesystem::path due to https://bugreports.qt.io/browse/QTBUG-73263 |
| 42 | explicit ConfigurePerGame(QWidget* parent, u64 title_id, const std::string& file_name, | 42 | explicit ConfigurePerGame(QWidget* parent, u64 title_id_, const std::string& file_name, |
| 43 | Core::System& system_); | 43 | Core::System& system_); |
| 44 | ~ConfigurePerGame() override; | 44 | ~ConfigurePerGame() override; |
| 45 | 45 | ||
| 46 | /// Save all button configurations to settings file | 46 | /// Save all button configurations to settings file |
| 47 | void ApplyConfiguration(); | 47 | void ApplyConfiguration(); |
| 48 | 48 | ||
| 49 | void LoadFromFile(FileSys::VirtualFile file); | 49 | void LoadFromFile(FileSys::VirtualFile file_); |
| 50 | 50 | ||
| 51 | private: | 51 | private: |
| 52 | void changeEvent(QEvent* event) override; | 52 | void changeEvent(QEvent* event) override; |
diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 7893a85bb..4906997ab 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp | |||
| @@ -89,8 +89,8 @@ void ConfigurePerGameAddons::ApplyConfiguration() { | |||
| 89 | Settings::values.disabled_addons[title_id] = disabled_addons; | 89 | Settings::values.disabled_addons[title_id] = disabled_addons; |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | void ConfigurePerGameAddons::LoadFromFile(FileSys::VirtualFile file) { | 92 | void ConfigurePerGameAddons::LoadFromFile(FileSys::VirtualFile file_) { |
| 93 | this->file = std::move(file); | 93 | file = std::move(file_); |
| 94 | LoadConfiguration(); | 94 | LoadConfiguration(); |
| 95 | } | 95 | } |
| 96 | 96 | ||
diff --git a/src/yuzu/configuration/configure_per_game_addons.h b/src/yuzu/configuration/configure_per_game_addons.h index 24b017494..14690fba8 100644 --- a/src/yuzu/configuration/configure_per_game_addons.h +++ b/src/yuzu/configuration/configure_per_game_addons.h | |||
| @@ -35,7 +35,7 @@ public: | |||
| 35 | /// Save all button configurations to settings file | 35 | /// Save all button configurations to settings file |
| 36 | void ApplyConfiguration(); | 36 | void ApplyConfiguration(); |
| 37 | 37 | ||
| 38 | void LoadFromFile(FileSys::VirtualFile file); | 38 | void LoadFromFile(FileSys::VirtualFile file_); |
| 39 | 39 | ||
| 40 | void SetTitleId(u64 id); | 40 | void SetTitleId(u64 id); |
| 41 | 41 | ||
diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index 4fcc22b7a..688c2dd38 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp | |||
| @@ -165,10 +165,10 @@ ConfigureRingController::ConfigureRingController(QWidget* parent, | |||
| 165 | const std::string invert_str = invert_value ? "+" : "-"; | 165 | const std::string invert_str = invert_value ? "+" : "-"; |
| 166 | param.Set("invert_x", invert_str); | 166 | param.Set("invert_x", invert_str); |
| 167 | emulated_device->SetRingParam(param); | 167 | emulated_device->SetRingParam(param); |
| 168 | for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; | 168 | for (int sub_button_id2 = 0; sub_button_id2 < ANALOG_SUB_BUTTONS_NUM; |
| 169 | ++sub_button_id) { | 169 | ++sub_button_id2) { |
| 170 | analog_map_buttons[sub_button_id]->setText( | 170 | analog_map_buttons[sub_button_id2]->setText( |
| 171 | AnalogToText(param, analog_sub_buttons[sub_button_id])); | 171 | AnalogToText(param, analog_sub_buttons[sub_button_id2])); |
| 172 | } | 172 | } |
| 173 | }); | 173 | }); |
| 174 | context_menu.exec( | 174 | context_menu.exec( |
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 19aa589f9..ecebb0fb7 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp | |||
| @@ -130,8 +130,7 @@ void ConfigureSystem::ApplyConfiguration() { | |||
| 130 | // Guard if during game and set to game-specific value | 130 | // Guard if during game and set to game-specific value |
| 131 | if (Settings::values.rng_seed.UsingGlobal()) { | 131 | if (Settings::values.rng_seed.UsingGlobal()) { |
| 132 | if (ui->rng_seed_checkbox->isChecked()) { | 132 | if (ui->rng_seed_checkbox->isChecked()) { |
| 133 | Settings::values.rng_seed.SetValue( | 133 | Settings::values.rng_seed.SetValue(ui->rng_seed_edit->text().toUInt(nullptr, 16)); |
| 134 | ui->rng_seed_edit->text().toULongLong(nullptr, 16)); | ||
| 135 | } else { | 134 | } else { |
| 136 | Settings::values.rng_seed.SetValue(std::nullopt); | 135 | Settings::values.rng_seed.SetValue(std::nullopt); |
| 137 | } | 136 | } |
| @@ -142,8 +141,7 @@ void ConfigureSystem::ApplyConfiguration() { | |||
| 142 | case ConfigurationShared::CheckState::Off: | 141 | case ConfigurationShared::CheckState::Off: |
| 143 | Settings::values.rng_seed.SetGlobal(false); | 142 | Settings::values.rng_seed.SetGlobal(false); |
| 144 | if (ui->rng_seed_checkbox->isChecked()) { | 143 | if (ui->rng_seed_checkbox->isChecked()) { |
| 145 | Settings::values.rng_seed.SetValue( | 144 | Settings::values.rng_seed.SetValue(ui->rng_seed_edit->text().toUInt(nullptr, 16)); |
| 146 | ui->rng_seed_edit->text().toULongLong(nullptr, 16)); | ||
| 147 | } else { | 145 | } else { |
| 148 | Settings::values.rng_seed.SetValue(std::nullopt); | 146 | Settings::values.rng_seed.SetValue(std::nullopt); |
| 149 | } | 147 | } |
diff --git a/src/yuzu/configuration/configure_touch_from_button.cpp b/src/yuzu/configuration/configure_touch_from_button.cpp index c17da6fd1..06cc452c3 100644 --- a/src/yuzu/configuration/configure_touch_from_button.cpp +++ b/src/yuzu/configuration/configure_touch_from_button.cpp | |||
| @@ -68,10 +68,10 @@ static QString ButtonToText(const Common::ParamPackage& param) { | |||
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | ConfigureTouchFromButton::ConfigureTouchFromButton( | 70 | ConfigureTouchFromButton::ConfigureTouchFromButton( |
| 71 | QWidget* parent, const std::vector<Settings::TouchFromButtonMap>& touch_maps, | 71 | QWidget* parent, const std::vector<Settings::TouchFromButtonMap>& touch_maps_, |
| 72 | InputCommon::InputSubsystem* input_subsystem_, const int default_index) | 72 | InputCommon::InputSubsystem* input_subsystem_, const int default_index) |
| 73 | : QDialog(parent), ui(std::make_unique<Ui::ConfigureTouchFromButton>()), | 73 | : QDialog(parent), ui(std::make_unique<Ui::ConfigureTouchFromButton>()), |
| 74 | touch_maps(touch_maps), input_subsystem{input_subsystem_}, selected_index(default_index), | 74 | touch_maps{touch_maps_}, input_subsystem{input_subsystem_}, selected_index{default_index}, |
| 75 | timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) { | 75 | timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) { |
| 76 | ui->setupUi(this); | 76 | ui->setupUi(this); |
| 77 | binding_list_model = new QStandardItemModel(0, 3, this); | 77 | binding_list_model = new QStandardItemModel(0, 3, this); |
diff --git a/src/yuzu/configuration/configure_touch_from_button.h b/src/yuzu/configuration/configure_touch_from_button.h index e1400481a..b8c55db66 100644 --- a/src/yuzu/configuration/configure_touch_from_button.h +++ b/src/yuzu/configuration/configure_touch_from_button.h | |||
| @@ -37,7 +37,7 @@ class ConfigureTouchFromButton : public QDialog { | |||
| 37 | 37 | ||
| 38 | public: | 38 | public: |
| 39 | explicit ConfigureTouchFromButton(QWidget* parent, | 39 | explicit ConfigureTouchFromButton(QWidget* parent, |
| 40 | const std::vector<Settings::TouchFromButtonMap>& touch_maps, | 40 | const std::vector<Settings::TouchFromButtonMap>& touch_maps_, |
| 41 | InputCommon::InputSubsystem* input_subsystem_, | 41 | InputCommon::InputSubsystem* input_subsystem_, |
| 42 | int default_index = 0); | 42 | int default_index = 0); |
| 43 | ~ConfigureTouchFromButton() override; | 43 | ~ConfigureTouchFromButton() override; |
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 8f486a131..0ea31cd33 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp | |||
| @@ -113,9 +113,9 @@ QString WaitTreeText::GetText() const { | |||
| 113 | return text; | 113 | return text; |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table, | 116 | WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address_, const Kernel::KHandleTable& handle_table, |
| 117 | Core::System& system_) | 117 | Core::System& system_) |
| 118 | : mutex_address(mutex_address), system{system_} { | 118 | : mutex_address{mutex_address_}, system{system_} { |
| 119 | mutex_value = system.Memory().Read32(mutex_address); | 119 | mutex_value = system.Memory().Read32(mutex_address); |
| 120 | owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask); | 120 | owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask); |
| 121 | owner = handle_table.GetObject<Kernel::KThread>(owner_handle).GetPointerUnsafe(); | 121 | owner = handle_table.GetObject<Kernel::KThread>(owner_handle).GetPointerUnsafe(); |
| @@ -140,8 +140,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexInfo::GetChildren() cons | |||
| 140 | return list; | 140 | return list; |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | WaitTreeCallstack::WaitTreeCallstack(const Kernel::KThread& thread, Core::System& system_) | 143 | WaitTreeCallstack::WaitTreeCallstack(const Kernel::KThread& thread_, Core::System& system_) |
| 144 | : thread(thread), system{system_} {} | 144 | : thread{thread_}, system{system_} {} |
| 145 | WaitTreeCallstack::~WaitTreeCallstack() = default; | 145 | WaitTreeCallstack::~WaitTreeCallstack() = default; |
| 146 | 146 | ||
| 147 | QString WaitTreeCallstack::GetText() const { | 147 | QString WaitTreeCallstack::GetText() const { |
| @@ -171,8 +171,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons | |||
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | WaitTreeSynchronizationObject::WaitTreeSynchronizationObject( | 173 | WaitTreeSynchronizationObject::WaitTreeSynchronizationObject( |
| 174 | const Kernel::KSynchronizationObject& o, Core::System& system_) | 174 | const Kernel::KSynchronizationObject& object_, Core::System& system_) |
| 175 | : object(o), system{system_} {} | 175 | : object{object_}, system{system_} {} |
| 176 | WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default; | 176 | WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default; |
| 177 | 177 | ||
| 178 | WaitTreeExpandableItem::WaitTreeExpandableItem() = default; | 178 | WaitTreeExpandableItem::WaitTreeExpandableItem() = default; |
| @@ -380,8 +380,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { | |||
| 380 | return list; | 380 | return list; |
| 381 | } | 381 | } |
| 382 | 382 | ||
| 383 | WaitTreeEvent::WaitTreeEvent(const Kernel::KReadableEvent& object, Core::System& system_) | 383 | WaitTreeEvent::WaitTreeEvent(const Kernel::KReadableEvent& object_, Core::System& system_) |
| 384 | : WaitTreeSynchronizationObject(object, system_) {} | 384 | : WaitTreeSynchronizationObject(object_, system_) {} |
| 385 | WaitTreeEvent::~WaitTreeEvent() = default; | 385 | WaitTreeEvent::~WaitTreeEvent() = default; |
| 386 | 386 | ||
| 387 | WaitTreeThreadList::WaitTreeThreadList(std::vector<Kernel::KThread*>&& list, Core::System& system_) | 387 | WaitTreeThreadList::WaitTreeThreadList(std::vector<Kernel::KThread*>&& list, Core::System& system_) |
diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h index 4a36dfc48..f21b9f467 100644 --- a/src/yuzu/debugger/wait_tree.h +++ b/src/yuzu/debugger/wait_tree.h | |||
| @@ -78,7 +78,7 @@ public: | |||
| 78 | class WaitTreeMutexInfo : public WaitTreeExpandableItem { | 78 | class WaitTreeMutexInfo : public WaitTreeExpandableItem { |
| 79 | Q_OBJECT | 79 | Q_OBJECT |
| 80 | public: | 80 | public: |
| 81 | explicit WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table, | 81 | explicit WaitTreeMutexInfo(VAddr mutex_address_, const Kernel::KHandleTable& handle_table, |
| 82 | Core::System& system_); | 82 | Core::System& system_); |
| 83 | ~WaitTreeMutexInfo() override; | 83 | ~WaitTreeMutexInfo() override; |
| 84 | 84 | ||
| @@ -97,7 +97,7 @@ private: | |||
| 97 | class WaitTreeCallstack : public WaitTreeExpandableItem { | 97 | class WaitTreeCallstack : public WaitTreeExpandableItem { |
| 98 | Q_OBJECT | 98 | Q_OBJECT |
| 99 | public: | 99 | public: |
| 100 | explicit WaitTreeCallstack(const Kernel::KThread& thread, Core::System& system_); | 100 | explicit WaitTreeCallstack(const Kernel::KThread& thread_, Core::System& system_); |
| 101 | ~WaitTreeCallstack() override; | 101 | ~WaitTreeCallstack() override; |
| 102 | 102 | ||
| 103 | QString GetText() const override; | 103 | QString GetText() const override; |
| @@ -112,7 +112,7 @@ private: | |||
| 112 | class WaitTreeSynchronizationObject : public WaitTreeExpandableItem { | 112 | class WaitTreeSynchronizationObject : public WaitTreeExpandableItem { |
| 113 | Q_OBJECT | 113 | Q_OBJECT |
| 114 | public: | 114 | public: |
| 115 | explicit WaitTreeSynchronizationObject(const Kernel::KSynchronizationObject& object, | 115 | explicit WaitTreeSynchronizationObject(const Kernel::KSynchronizationObject& object_, |
| 116 | Core::System& system_); | 116 | Core::System& system_); |
| 117 | ~WaitTreeSynchronizationObject() override; | 117 | ~WaitTreeSynchronizationObject() override; |
| 118 | 118 | ||
| @@ -162,7 +162,7 @@ private: | |||
| 162 | class WaitTreeEvent : public WaitTreeSynchronizationObject { | 162 | class WaitTreeEvent : public WaitTreeSynchronizationObject { |
| 163 | Q_OBJECT | 163 | Q_OBJECT |
| 164 | public: | 164 | public: |
| 165 | explicit WaitTreeEvent(const Kernel::KReadableEvent& object, Core::System& system_); | 165 | explicit WaitTreeEvent(const Kernel::KReadableEvent& object_, Core::System& system_); |
| 166 | ~WaitTreeEvent() override; | 166 | ~WaitTreeEvent() override; |
| 167 | }; | 167 | }; |
| 168 | 168 | ||
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 4a6d74a7e..05d309827 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -28,8 +28,8 @@ | |||
| 28 | #include "yuzu/uisettings.h" | 28 | #include "yuzu/uisettings.h" |
| 29 | #include "yuzu/util/controller_navigation.h" | 29 | #include "yuzu/util/controller_navigation.h" |
| 30 | 30 | ||
| 31 | GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist, QObject* parent) | 31 | GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist_, QObject* parent) |
| 32 | : QObject(parent), gamelist{gamelist} {} | 32 | : QObject(parent), gamelist{gamelist_} {} |
| 33 | 33 | ||
| 34 | // EventFilter in order to process systemkeys while editing the searchfield | 34 | // EventFilter in order to process systemkeys while editing the searchfield |
| 35 | bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) { | 35 | bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) { |
| @@ -80,9 +80,9 @@ bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* eve | |||
| 80 | return QObject::eventFilter(obj, event); | 80 | return QObject::eventFilter(obj, event); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | void GameListSearchField::setFilterResult(int visible, int total) { | 83 | void GameListSearchField::setFilterResult(int visible_, int total_) { |
| 84 | this->visible = visible; | 84 | visible = visible_; |
| 85 | this->total = total; | 85 | total = total_; |
| 86 | 86 | ||
| 87 | label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible)); | 87 | label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible)); |
| 88 | } | 88 | } |
| @@ -309,9 +309,9 @@ void GameList::OnFilterCloseClicked() { | |||
| 309 | main_window->filterBarSetChecked(false); | 309 | main_window->filterBarSetChecked(false); |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvider* provider, | 312 | GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvider* provider_, |
| 313 | Core::System& system_, GMainWindow* parent) | 313 | Core::System& system_, GMainWindow* parent) |
| 314 | : QWidget{parent}, vfs(std::move(vfs)), provider(provider), system{system_} { | 314 | : QWidget{parent}, vfs{std::move(vfs_)}, provider{provider_}, system{system_} { |
| 315 | watcher = new QFileSystemWatcher(this); | 315 | watcher = new QFileSystemWatcher(this); |
| 316 | connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory); | 316 | connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory); |
| 317 | 317 | ||
| @@ -483,7 +483,7 @@ void GameList::DonePopulating(const QStringList& watch_list) { | |||
| 483 | // Also artificially caps the watcher to a certain number of directories | 483 | // Also artificially caps the watcher to a certain number of directories |
| 484 | constexpr int LIMIT_WATCH_DIRECTORIES = 5000; | 484 | constexpr int LIMIT_WATCH_DIRECTORIES = 5000; |
| 485 | constexpr int SLICE_SIZE = 25; | 485 | constexpr int SLICE_SIZE = 25; |
| 486 | int len = std::min(watch_list.length(), LIMIT_WATCH_DIRECTORIES); | 486 | int len = std::min(static_cast<int>(watch_list.size()), LIMIT_WATCH_DIRECTORIES); |
| 487 | for (int i = 0; i < len; i += SLICE_SIZE) { | 487 | for (int i = 0; i < len; i += SLICE_SIZE) { |
| 488 | watcher->addPaths(watch_list.mid(i, i + SLICE_SIZE)); | 488 | watcher->addPaths(watch_list.mid(i, i + SLICE_SIZE)); |
| 489 | QCoreApplication::processEvents(); | 489 | QCoreApplication::processEvents(); |
| @@ -870,7 +870,7 @@ GameListPlaceholder::GameListPlaceholder(GMainWindow* parent) : QWidget{parent} | |||
| 870 | layout->setAlignment(Qt::AlignCenter); | 870 | layout->setAlignment(Qt::AlignCenter); |
| 871 | image->setPixmap(QIcon::fromTheme(QStringLiteral("plus_folder")).pixmap(200)); | 871 | image->setPixmap(QIcon::fromTheme(QStringLiteral("plus_folder")).pixmap(200)); |
| 872 | 872 | ||
| 873 | text->setText(tr("Double-click to add a new folder to the game list")); | 873 | RetranslateUI(); |
| 874 | QFont font = text->font(); | 874 | QFont font = text->font(); |
| 875 | font.setPointSize(20); | 875 | font.setPointSize(20); |
| 876 | text->setFont(font); | 876 | text->setFont(font); |
| @@ -891,3 +891,15 @@ void GameListPlaceholder::onUpdateThemedIcons() { | |||
| 891 | void GameListPlaceholder::mouseDoubleClickEvent(QMouseEvent* event) { | 891 | void GameListPlaceholder::mouseDoubleClickEvent(QMouseEvent* event) { |
| 892 | emit GameListPlaceholder::AddDirectory(); | 892 | emit GameListPlaceholder::AddDirectory(); |
| 893 | } | 893 | } |
| 894 | |||
| 895 | void GameListPlaceholder::changeEvent(QEvent* event) { | ||
| 896 | if (event->type() == QEvent::LanguageChange) { | ||
| 897 | RetranslateUI(); | ||
| 898 | } | ||
| 899 | |||
| 900 | QWidget::changeEvent(event); | ||
| 901 | } | ||
| 902 | |||
| 903 | void GameListPlaceholder::RetranslateUI() { | ||
| 904 | text->setText(tr("Double-click to add a new folder to the game list")); | ||
| 905 | } | ||
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index d19dbe4b0..bc36d015a 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h | |||
| @@ -67,8 +67,8 @@ public: | |||
| 67 | COLUMN_COUNT, // Number of columns | 67 | COLUMN_COUNT, // Number of columns |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | explicit GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs, | 70 | explicit GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs_, |
| 71 | FileSys::ManualContentProvider* provider, Core::System& system_, | 71 | FileSys::ManualContentProvider* provider_, Core::System& system_, |
| 72 | GMainWindow* parent = nullptr); | 72 | GMainWindow* parent = nullptr); |
| 73 | ~GameList() override; | 73 | ~GameList() override; |
| 74 | 74 | ||
| @@ -166,6 +166,9 @@ protected: | |||
| 166 | void mouseDoubleClickEvent(QMouseEvent* event) override; | 166 | void mouseDoubleClickEvent(QMouseEvent* event) override; |
| 167 | 167 | ||
| 168 | private: | 168 | private: |
| 169 | void changeEvent(QEvent* event) override; | ||
| 170 | void RetranslateUI(); | ||
| 171 | |||
| 169 | QVBoxLayout* layout = nullptr; | 172 | QVBoxLayout* layout = nullptr; |
| 170 | QLabel* image = nullptr; | 173 | QLabel* image = nullptr; |
| 171 | QLabel* text = nullptr; | 174 | QLabel* text = nullptr; |
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index f2a986ed8..cd7d63536 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h | |||
| @@ -225,8 +225,8 @@ public: | |||
| 225 | static constexpr int GameDirRole = Qt::UserRole + 2; | 225 | static constexpr int GameDirRole = Qt::UserRole + 2; |
| 226 | 226 | ||
| 227 | explicit GameListDir(UISettings::GameDir& directory, | 227 | explicit GameListDir(UISettings::GameDir& directory, |
| 228 | GameListItemType dir_type = GameListItemType::CustomDir) | 228 | GameListItemType dir_type_ = GameListItemType::CustomDir) |
| 229 | : dir_type{dir_type} { | 229 | : dir_type{dir_type_} { |
| 230 | setData(type(), TypeRole); | 230 | setData(type(), TypeRole); |
| 231 | 231 | ||
| 232 | UISettings::GameDir* game_dir = &directory; | 232 | UISettings::GameDir* game_dir = &directory; |
| @@ -348,7 +348,7 @@ public: | |||
| 348 | explicit GameListSearchField(GameList* parent = nullptr); | 348 | explicit GameListSearchField(GameList* parent = nullptr); |
| 349 | 349 | ||
| 350 | QString filterText() const; | 350 | QString filterText() const; |
| 351 | void setFilterResult(int visible, int total); | 351 | void setFilterResult(int visible_, int total_); |
| 352 | 352 | ||
| 353 | void clear(); | 353 | void clear(); |
| 354 | void setFocus(); | 354 | void setFocus(); |
| @@ -356,7 +356,7 @@ public: | |||
| 356 | private: | 356 | private: |
| 357 | class KeyReleaseEater : public QObject { | 357 | class KeyReleaseEater : public QObject { |
| 358 | public: | 358 | public: |
| 359 | explicit KeyReleaseEater(GameList* gamelist, QObject* parent = nullptr); | 359 | explicit KeyReleaseEater(GameList* gamelist_, QObject* parent = nullptr); |
| 360 | 360 | ||
| 361 | private: | 361 | private: |
| 362 | GameList* gamelist = nullptr; | 362 | GameList* gamelist = nullptr; |
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index ca1899b5c..63326968b 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp | |||
| @@ -223,12 +223,12 @@ QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::stri | |||
| 223 | } | 223 | } |
| 224 | } // Anonymous namespace | 224 | } // Anonymous namespace |
| 225 | 225 | ||
| 226 | GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs, | 226 | GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs_, |
| 227 | FileSys::ManualContentProvider* provider, | 227 | FileSys::ManualContentProvider* provider_, |
| 228 | QVector<UISettings::GameDir>& game_dirs, | 228 | QVector<UISettings::GameDir>& game_dirs_, |
| 229 | const CompatibilityList& compatibility_list, Core::System& system_) | 229 | const CompatibilityList& compatibility_list_, Core::System& system_) |
| 230 | : vfs(std::move(vfs)), provider(provider), game_dirs(game_dirs), | 230 | : vfs{std::move(vfs_)}, provider{provider_}, game_dirs{game_dirs_}, |
| 231 | compatibility_list(compatibility_list), system{system_} {} | 231 | compatibility_list{compatibility_list_}, system{system_} {} |
| 232 | 232 | ||
| 233 | GameListWorker::~GameListWorker() = default; | 233 | GameListWorker::~GameListWorker() = default; |
| 234 | 234 | ||
diff --git a/src/yuzu/game_list_worker.h b/src/yuzu/game_list_worker.h index 622d241fb..24a4e92c3 100644 --- a/src/yuzu/game_list_worker.h +++ b/src/yuzu/game_list_worker.h | |||
| @@ -33,10 +33,10 @@ class GameListWorker : public QObject, public QRunnable { | |||
| 33 | Q_OBJECT | 33 | Q_OBJECT |
| 34 | 34 | ||
| 35 | public: | 35 | public: |
| 36 | explicit GameListWorker(std::shared_ptr<FileSys::VfsFilesystem> vfs, | 36 | explicit GameListWorker(std::shared_ptr<FileSys::VfsFilesystem> vfs_, |
| 37 | FileSys::ManualContentProvider* provider, | 37 | FileSys::ManualContentProvider* provider_, |
| 38 | QVector<UISettings::GameDir>& game_dirs, | 38 | QVector<UISettings::GameDir>& game_dirs_, |
| 39 | const CompatibilityList& compatibility_list, Core::System& system_); | 39 | const CompatibilityList& compatibility_list_, Core::System& system_); |
| 40 | ~GameListWorker() override; | 40 | ~GameListWorker() override; |
| 41 | 41 | ||
| 42 | /// Starts the processing of directory tree information. | 42 | /// Starts the processing of directory tree information. |
diff --git a/src/yuzu/loading_screen.cpp b/src/yuzu/loading_screen.cpp index edfb946a8..e273744fd 100644 --- a/src/yuzu/loading_screen.cpp +++ b/src/yuzu/loading_screen.cpp | |||
| @@ -183,7 +183,7 @@ void LoadingScreen::OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size | |||
| 183 | 183 | ||
| 184 | void LoadingScreen::paintEvent(QPaintEvent* event) { | 184 | void LoadingScreen::paintEvent(QPaintEvent* event) { |
| 185 | QStyleOption opt; | 185 | QStyleOption opt; |
| 186 | opt.init(this); | 186 | opt.initFrom(this); |
| 187 | QPainter p(this); | 187 | QPainter p(this); |
| 188 | style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); | 188 | style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); |
| 189 | QWidget::paintEvent(event); | 189 | QWidget::paintEvent(event); |
diff --git a/src/yuzu/loading_screen.h b/src/yuzu/loading_screen.h index 7c960ee72..17045595d 100644 --- a/src/yuzu/loading_screen.h +++ b/src/yuzu/loading_screen.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <QString> | 8 | #include <QString> |
| 9 | #include <QWidget> | 9 | #include <QWidget> |
| 10 | #include <QtGlobal> | ||
| 10 | 11 | ||
| 11 | #if !QT_CONFIG(movie) | 12 | #if !QT_CONFIG(movie) |
| 12 | #define YUZU_QT_MOVIE_MISSING 1 | 13 | #define YUZU_QT_MOVIE_MISSING 1 |
| @@ -88,4 +89,6 @@ private: | |||
| 88 | std::size_t slow_shader_first_value = 0; | 89 | std::size_t slow_shader_first_value = 0; |
| 89 | }; | 90 | }; |
| 90 | 91 | ||
| 92 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) | ||
| 91 | Q_DECLARE_METATYPE(VideoCore::LoadCallbackStage); | 93 | Q_DECLARE_METATYPE(VideoCore::LoadCallbackStage); |
| 94 | #endif | ||
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f607f464a..b460020b1 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -52,7 +52,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||
| 52 | #define QT_NO_OPENGL | 52 | #define QT_NO_OPENGL |
| 53 | #include <QClipboard> | 53 | #include <QClipboard> |
| 54 | #include <QDesktopServices> | 54 | #include <QDesktopServices> |
| 55 | #include <QDesktopWidget> | ||
| 56 | #include <QFile> | 55 | #include <QFile> |
| 57 | #include <QFileDialog> | 56 | #include <QFileDialog> |
| 58 | #include <QInputDialog> | 57 | #include <QInputDialog> |
| @@ -60,6 +59,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||
| 60 | #include <QProgressBar> | 59 | #include <QProgressBar> |
| 61 | #include <QProgressDialog> | 60 | #include <QProgressDialog> |
| 62 | #include <QPushButton> | 61 | #include <QPushButton> |
| 62 | #include <QScreen> | ||
| 63 | #include <QShortcut> | 63 | #include <QShortcut> |
| 64 | #include <QStatusBar> | 64 | #include <QStatusBar> |
| 65 | #include <QString> | 65 | #include <QString> |
| @@ -115,6 +115,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||
| 115 | #include "video_core/shader_notify.h" | 115 | #include "video_core/shader_notify.h" |
| 116 | #include "yuzu/about_dialog.h" | 116 | #include "yuzu/about_dialog.h" |
| 117 | #include "yuzu/bootmanager.h" | 117 | #include "yuzu/bootmanager.h" |
| 118 | #include "yuzu/check_vulkan.h" | ||
| 118 | #include "yuzu/compatdb.h" | 119 | #include "yuzu/compatdb.h" |
| 119 | #include "yuzu/compatibility_list.h" | 120 | #include "yuzu/compatibility_list.h" |
| 120 | #include "yuzu/configuration/config.h" | 121 | #include "yuzu/configuration/config.h" |
| @@ -198,6 +199,59 @@ static void RemoveCachedContents() { | |||
| 198 | Common::FS::RemoveDirRecursively(offline_system_data); | 199 | Common::FS::RemoveDirRecursively(offline_system_data); |
| 199 | } | 200 | } |
| 200 | 201 | ||
| 202 | static void LogRuntimes() { | ||
| 203 | #ifdef _MSC_VER | ||
| 204 | // It is possible that the name of the dll will change. | ||
| 205 | // vcruntime140.dll is for 2015 and onwards | ||
| 206 | constexpr char runtime_dll_name[] = "vcruntime140.dll"; | ||
| 207 | UINT sz = GetFileVersionInfoSizeA(runtime_dll_name, nullptr); | ||
| 208 | bool runtime_version_inspection_worked = false; | ||
| 209 | if (sz > 0) { | ||
| 210 | std::vector<u8> buf(sz); | ||
| 211 | if (GetFileVersionInfoA(runtime_dll_name, 0, sz, buf.data())) { | ||
| 212 | VS_FIXEDFILEINFO* pvi; | ||
| 213 | sz = sizeof(VS_FIXEDFILEINFO); | ||
| 214 | if (VerQueryValueA(buf.data(), "\\", reinterpret_cast<LPVOID*>(&pvi), &sz)) { | ||
| 215 | if (pvi->dwSignature == VS_FFI_SIGNATURE) { | ||
| 216 | runtime_version_inspection_worked = true; | ||
| 217 | LOG_INFO(Frontend, "MSVC Compiler: {} Runtime: {}.{}.{}.{}", _MSC_VER, | ||
| 218 | pvi->dwProductVersionMS >> 16, pvi->dwProductVersionMS & 0xFFFF, | ||
| 219 | pvi->dwProductVersionLS >> 16, pvi->dwProductVersionLS & 0xFFFF); | ||
| 220 | } | ||
| 221 | } | ||
| 222 | } | ||
| 223 | } | ||
| 224 | if (!runtime_version_inspection_worked) { | ||
| 225 | LOG_INFO(Frontend, "Unable to inspect {}", runtime_dll_name); | ||
| 226 | } | ||
| 227 | #endif | ||
| 228 | } | ||
| 229 | |||
| 230 | static QString PrettyProductName() { | ||
| 231 | #ifdef _WIN32 | ||
| 232 | // After Windows 10 Version 2004, Microsoft decided to switch to a different notation: 20H2 | ||
| 233 | // With that notation change they changed the registry key used to denote the current version | ||
| 234 | QSettings windows_registry( | ||
| 235 | QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), | ||
| 236 | QSettings::NativeFormat); | ||
| 237 | const QString release_id = windows_registry.value(QStringLiteral("ReleaseId")).toString(); | ||
| 238 | if (release_id == QStringLiteral("2009")) { | ||
| 239 | const u32 current_build = windows_registry.value(QStringLiteral("CurrentBuild")).toUInt(); | ||
| 240 | const QString display_version = | ||
| 241 | windows_registry.value(QStringLiteral("DisplayVersion")).toString(); | ||
| 242 | const u32 ubr = windows_registry.value(QStringLiteral("UBR")).toUInt(); | ||
| 243 | u32 version = 10; | ||
| 244 | if (current_build >= 22000) { | ||
| 245 | version = 11; | ||
| 246 | } | ||
| 247 | return QStringLiteral("Windows %1 Version %2 (Build %3.%4)") | ||
| 248 | .arg(QString::number(version), display_version, QString::number(current_build), | ||
| 249 | QString::number(ubr)); | ||
| 250 | } | ||
| 251 | #endif | ||
| 252 | return QSysInfo::prettyProductName(); | ||
| 253 | } | ||
| 254 | |||
| 201 | GMainWindow::GMainWindow() | 255 | GMainWindow::GMainWindow() |
| 202 | : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()}, | 256 | : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()}, |
| 203 | input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, | 257 | input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, |
| @@ -243,6 +297,7 @@ GMainWindow::GMainWindow() | |||
| 243 | const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build; | 297 | const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build; |
| 244 | 298 | ||
| 245 | LOG_INFO(Frontend, "yuzu Version: {}", yuzu_build_version); | 299 | LOG_INFO(Frontend, "yuzu Version: {}", yuzu_build_version); |
| 300 | LogRuntimes(); | ||
| 246 | #ifdef ARCHITECTURE_x86_64 | 301 | #ifdef ARCHITECTURE_x86_64 |
| 247 | const auto& caps = Common::GetCPUCaps(); | 302 | const auto& caps = Common::GetCPUCaps(); |
| 248 | std::string cpu_string = caps.cpu_string; | 303 | std::string cpu_string = caps.cpu_string; |
| @@ -259,7 +314,7 @@ GMainWindow::GMainWindow() | |||
| 259 | } | 314 | } |
| 260 | LOG_INFO(Frontend, "Host CPU: {}", cpu_string); | 315 | LOG_INFO(Frontend, "Host CPU: {}", cpu_string); |
| 261 | #endif | 316 | #endif |
| 262 | LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString()); | 317 | LOG_INFO(Frontend, "Host OS: {}", PrettyProductName().toStdString()); |
| 263 | LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", | 318 | LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", |
| 264 | Common::GetMemInfo().TotalPhysicalMemory / f64{1_GiB}); | 319 | Common::GetMemInfo().TotalPhysicalMemory / f64{1_GiB}); |
| 265 | LOG_INFO(Frontend, "Host Swap: {:.2f} GiB", Common::GetMemInfo().TotalSwapMemory / f64{1_GiB}); | 320 | LOG_INFO(Frontend, "Host Swap: {:.2f} GiB", Common::GetMemInfo().TotalSwapMemory / f64{1_GiB}); |
| @@ -297,6 +352,23 @@ GMainWindow::GMainWindow() | |||
| 297 | 352 | ||
| 298 | MigrateConfigFiles(); | 353 | MigrateConfigFiles(); |
| 299 | 354 | ||
| 355 | if (!CheckVulkan()) { | ||
| 356 | config->Save(); | ||
| 357 | |||
| 358 | QMessageBox::warning( | ||
| 359 | this, tr("Broken Vulkan Installation Detected"), | ||
| 360 | tr("Vulkan initialization failed on the previous boot.<br><br>Click <a " | ||
| 361 | "href='https://yuzu-emu.org/wiki/faq/" | ||
| 362 | "#yuzu-starts-with-the-error-broken-vulkan-installation-detected'>here for " | ||
| 363 | "instructions to fix the issue</a>.")); | ||
| 364 | } | ||
| 365 | if (UISettings::values.has_broken_vulkan) { | ||
| 366 | Settings::values.renderer_backend = Settings::RendererBackend::OpenGL; | ||
| 367 | |||
| 368 | renderer_status_button->setDisabled(true); | ||
| 369 | renderer_status_button->setChecked(false); | ||
| 370 | } | ||
| 371 | |||
| 300 | #if defined(HAVE_SDL2) && !defined(_WIN32) | 372 | #if defined(HAVE_SDL2) && !defined(_WIN32) |
| 301 | SDL_InitSubSystem(SDL_INIT_VIDEO); | 373 | SDL_InitSubSystem(SDL_INIT_VIDEO); |
| 302 | // SDL disables the screen saver by default, and setting the hint | 374 | // SDL disables the screen saver by default, and setting the hint |
| @@ -827,12 +899,11 @@ void GMainWindow::InitializeWidgets() { | |||
| 827 | 899 | ||
| 828 | // Setup Dock button | 900 | // Setup Dock button |
| 829 | dock_status_button = new QPushButton(); | 901 | dock_status_button = new QPushButton(); |
| 830 | dock_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton")); | 902 | dock_status_button->setObjectName(QStringLiteral("DockingStatusBarButton")); |
| 831 | dock_status_button->setFocusPolicy(Qt::NoFocus); | 903 | dock_status_button->setFocusPolicy(Qt::NoFocus); |
| 832 | connect(dock_status_button, &QPushButton::clicked, this, &GMainWindow::OnToggleDockedMode); | 904 | connect(dock_status_button, &QPushButton::clicked, this, &GMainWindow::OnToggleDockedMode); |
| 833 | dock_status_button->setText(tr("DOCK")); | ||
| 834 | dock_status_button->setCheckable(true); | 905 | dock_status_button->setCheckable(true); |
| 835 | dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue()); | 906 | UpdateDockedButton(); |
| 836 | statusBar()->insertPermanentWidget(0, dock_status_button); | 907 | statusBar()->insertPermanentWidget(0, dock_status_button); |
| 837 | 908 | ||
| 838 | gpu_accuracy_button = new QPushButton(); | 909 | gpu_accuracy_button = new QPushButton(); |
| @@ -863,8 +934,7 @@ void GMainWindow::InitializeWidgets() { | |||
| 863 | Settings::values.renderer_backend.SetValue(Settings::RendererBackend::Vulkan); | 934 | Settings::values.renderer_backend.SetValue(Settings::RendererBackend::Vulkan); |
| 864 | } else { | 935 | } else { |
| 865 | Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL); | 936 | Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL); |
| 866 | const auto filter = Settings::values.scaling_filter.GetValue(); | 937 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { |
| 867 | if (filter == Settings::ScalingFilter::Fsr) { | ||
| 868 | Settings::values.scaling_filter.SetValue(Settings::ScalingFilter::NearestNeighbor); | 938 | Settings::values.scaling_filter.SetValue(Settings::ScalingFilter::NearestNeighbor); |
| 869 | UpdateFilterText(); | 939 | UpdateFilterText(); |
| 870 | } | 940 | } |
| @@ -1002,7 +1072,7 @@ void GMainWindow::InitializeHotkeys() { | |||
| 1002 | 1072 | ||
| 1003 | void GMainWindow::SetDefaultUIGeometry() { | 1073 | void GMainWindow::SetDefaultUIGeometry() { |
| 1004 | // geometry: 53% of the window contents are in the upper screen half, 47% in the lower half | 1074 | // geometry: 53% of the window contents are in the upper screen half, 47% in the lower half |
| 1005 | const QRect screenRect = QApplication::desktop()->screenGeometry(this); | 1075 | const QRect screenRect = QGuiApplication::primaryScreen()->geometry(); |
| 1006 | 1076 | ||
| 1007 | const int w = screenRect.width() * 2 / 3; | 1077 | const int w = screenRect.width() * 2 / 3; |
| 1008 | const int h = screenRect.height() * 2 / 3; | 1078 | const int h = screenRect.height() * 2 / 3; |
| @@ -1015,6 +1085,10 @@ void GMainWindow::SetDefaultUIGeometry() { | |||
| 1015 | void GMainWindow::RestoreUIState() { | 1085 | void GMainWindow::RestoreUIState() { |
| 1016 | setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint); | 1086 | setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint); |
| 1017 | restoreGeometry(UISettings::values.geometry); | 1087 | restoreGeometry(UISettings::values.geometry); |
| 1088 | // Work-around because the games list isn't supposed to be full screen | ||
| 1089 | if (isFullScreen()) { | ||
| 1090 | showNormal(); | ||
| 1091 | } | ||
| 1018 | restoreState(UISettings::values.state); | 1092 | restoreState(UISettings::values.state); |
| 1019 | render_window->setWindowFlags(render_window->windowFlags() & ~Qt::FramelessWindowHint); | 1093 | render_window->setWindowFlags(render_window->windowFlags() & ~Qt::FramelessWindowHint); |
| 1020 | render_window->restoreGeometry(UISettings::values.renderwindow_geometry); | 1094 | render_window->restoreGeometry(UISettings::values.renderwindow_geometry); |
| @@ -1367,7 +1441,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p | |||
| 1367 | } | 1441 | } |
| 1368 | return false; | 1442 | return false; |
| 1369 | } | 1443 | } |
| 1370 | game_path = filename; | 1444 | current_game_path = filename; |
| 1371 | 1445 | ||
| 1372 | system->TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "Qt"); | 1446 | system->TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "Qt"); |
| 1373 | return true; | 1447 | return true; |
| @@ -1401,7 +1475,8 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t | |||
| 1401 | if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success && | 1475 | if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success && |
| 1402 | type == StartGameType::Normal) { | 1476 | type == StartGameType::Normal) { |
| 1403 | // Load per game settings | 1477 | // Load per game settings |
| 1404 | const auto file_path = std::filesystem::path{filename.toStdU16String()}; | 1478 | const auto file_path = |
| 1479 | std::filesystem::path{Common::U16StringFromBuffer(filename.utf16(), filename.size())}; | ||
| 1405 | const auto config_file_name = title_id == 0 | 1480 | const auto config_file_name = title_id == 0 |
| 1406 | ? Common::FS::PathToUTF8String(file_path.filename()) | 1481 | ? Common::FS::PathToUTF8String(file_path.filename()) |
| 1407 | : fmt::format("{:016X}", title_id); | 1482 | : fmt::format("{:016X}", title_id); |
| @@ -1432,7 +1507,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t | |||
| 1432 | 1507 | ||
| 1433 | // Register an ExecuteProgram callback such that Core can execute a sub-program | 1508 | // Register an ExecuteProgram callback such that Core can execute a sub-program |
| 1434 | system->RegisterExecuteProgramCallback( | 1509 | system->RegisterExecuteProgramCallback( |
| 1435 | [this](std::size_t program_index) { render_window->ExecuteProgram(program_index); }); | 1510 | [this](std::size_t program_index_) { render_window->ExecuteProgram(program_index_); }); |
| 1436 | 1511 | ||
| 1437 | // Register an Exit callback such that Core can exit the currently running application. | 1512 | // Register an Exit callback such that Core can exit the currently running application. |
| 1438 | system->RegisterExitCallback([this]() { render_window->Exit(); }); | 1513 | system->RegisterExitCallback([this]() { render_window->Exit(); }); |
| @@ -1482,7 +1557,8 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t | |||
| 1482 | } | 1557 | } |
| 1483 | if (res != Loader::ResultStatus::Success || title_name.empty()) { | 1558 | if (res != Loader::ResultStatus::Success || title_name.empty()) { |
| 1484 | title_name = Common::FS::PathToUTF8String( | 1559 | title_name = Common::FS::PathToUTF8String( |
| 1485 | std::filesystem::path{filename.toStdU16String()}.filename()); | 1560 | std::filesystem::path{Common::U16StringFromBuffer(filename.utf16(), filename.size())} |
| 1561 | .filename()); | ||
| 1486 | } | 1562 | } |
| 1487 | const bool is_64bit = system->Kernel().CurrentProcess()->Is64BitProcess(); | 1563 | const bool is_64bit = system->Kernel().CurrentProcess()->Is64BitProcess(); |
| 1488 | const auto instruction_set_suffix = is_64bit ? tr("(64-bit)") : tr("(32-bit)"); | 1564 | const auto instruction_set_suffix = is_64bit ? tr("(64-bit)") : tr("(32-bit)"); |
| @@ -1514,6 +1590,7 @@ void GMainWindow::ShutdownGame() { | |||
| 1514 | 1590 | ||
| 1515 | AllowOSSleep(); | 1591 | AllowOSSleep(); |
| 1516 | 1592 | ||
| 1593 | system->DetachDebugger(); | ||
| 1517 | discord_rpc->Pause(); | 1594 | discord_rpc->Pause(); |
| 1518 | emu_thread->RequestStop(); | 1595 | emu_thread->RequestStop(); |
| 1519 | 1596 | ||
| @@ -1561,9 +1638,9 @@ void GMainWindow::ShutdownGame() { | |||
| 1561 | emu_speed_label->setVisible(false); | 1638 | emu_speed_label->setVisible(false); |
| 1562 | game_fps_label->setVisible(false); | 1639 | game_fps_label->setVisible(false); |
| 1563 | emu_frametime_label->setVisible(false); | 1640 | emu_frametime_label->setVisible(false); |
| 1564 | renderer_status_button->setEnabled(true); | 1641 | renderer_status_button->setEnabled(!UISettings::values.has_broken_vulkan); |
| 1565 | 1642 | ||
| 1566 | game_path.clear(); | 1643 | current_game_path.clear(); |
| 1567 | 1644 | ||
| 1568 | // When closing the game, destroy the GLWindow to clear the context after the game is closed | 1645 | // When closing the game, destroy the GLWindow to clear the context after the game is closed |
| 1569 | render_window->ReleaseRenderTarget(); | 1646 | render_window->ReleaseRenderTarget(); |
| @@ -1581,7 +1658,7 @@ void GMainWindow::StoreRecentFile(const QString& filename) { | |||
| 1581 | 1658 | ||
| 1582 | void GMainWindow::UpdateRecentFiles() { | 1659 | void GMainWindow::UpdateRecentFiles() { |
| 1583 | const int num_recent_files = | 1660 | const int num_recent_files = |
| 1584 | std::min(UISettings::values.recent_files.size(), max_recent_files_item); | 1661 | std::min(static_cast<int>(UISettings::values.recent_files.size()), max_recent_files_item); |
| 1585 | 1662 | ||
| 1586 | for (int i = 0; i < num_recent_files; i++) { | 1663 | for (int i = 0; i < num_recent_files; i++) { |
| 1587 | const QString text = QStringLiteral("&%1. %2").arg(i + 1).arg( | 1664 | const QString text = QStringLiteral("&%1. %2").arg(i + 1).arg( |
| @@ -2482,7 +2559,7 @@ void GMainWindow::OnRestartGame() { | |||
| 2482 | return; | 2559 | return; |
| 2483 | } | 2560 | } |
| 2484 | // Make a copy since BootGame edits game_path | 2561 | // Make a copy since BootGame edits game_path |
| 2485 | BootGame(QString(game_path)); | 2562 | BootGame(QString(current_game_path)); |
| 2486 | } | 2563 | } |
| 2487 | 2564 | ||
| 2488 | void GMainWindow::OnPauseGame() { | 2565 | void GMainWindow::OnPauseGame() { |
| @@ -2579,6 +2656,18 @@ void GMainWindow::ToggleFullscreen() { | |||
| 2579 | } | 2656 | } |
| 2580 | } | 2657 | } |
| 2581 | 2658 | ||
| 2659 | // We're going to return the screen that the given window has the most pixels on | ||
| 2660 | static QScreen* GuessCurrentScreen(QWidget* window) { | ||
| 2661 | const QList<QScreen*> screens = QGuiApplication::screens(); | ||
| 2662 | return *std::max_element( | ||
| 2663 | screens.cbegin(), screens.cend(), [window](const QScreen* left, const QScreen* right) { | ||
| 2664 | const QSize left_size = left->geometry().intersected(window->geometry()).size(); | ||
| 2665 | const QSize right_size = right->geometry().intersected(window->geometry()).size(); | ||
| 2666 | return (left_size.height() * left_size.width()) < | ||
| 2667 | (right_size.height() * right_size.width()); | ||
| 2668 | }); | ||
| 2669 | } | ||
| 2670 | |||
| 2582 | void GMainWindow::ShowFullscreen() { | 2671 | void GMainWindow::ShowFullscreen() { |
| 2583 | const auto show_fullscreen = [](QWidget* window) { | 2672 | const auto show_fullscreen = [](QWidget* window) { |
| 2584 | if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { | 2673 | if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { |
| @@ -2587,7 +2676,7 @@ void GMainWindow::ShowFullscreen() { | |||
| 2587 | } | 2676 | } |
| 2588 | window->hide(); | 2677 | window->hide(); |
| 2589 | window->setWindowFlags(window->windowFlags() | Qt::FramelessWindowHint); | 2678 | window->setWindowFlags(window->windowFlags() | Qt::FramelessWindowHint); |
| 2590 | const auto screen_geometry = QApplication::desktop()->screenGeometry(window); | 2679 | const auto screen_geometry = GuessCurrentScreen(window)->geometry(); |
| 2591 | window->setGeometry(screen_geometry.x(), screen_geometry.y(), screen_geometry.width(), | 2680 | window->setGeometry(screen_geometry.x(), screen_geometry.y(), screen_geometry.width(), |
| 2592 | screen_geometry.height() + 1); | 2681 | screen_geometry.height() + 1); |
| 2593 | window->raise(); | 2682 | window->raise(); |
| @@ -2771,6 +2860,10 @@ void GMainWindow::OnConfigure() { | |||
| 2771 | mouse_hide_timer.start(); | 2860 | mouse_hide_timer.start(); |
| 2772 | } | 2861 | } |
| 2773 | 2862 | ||
| 2863 | if (!UISettings::values.has_broken_vulkan) { | ||
| 2864 | renderer_status_button->setEnabled(!emulation_running); | ||
| 2865 | } | ||
| 2866 | |||
| 2774 | UpdateStatusButtons(); | 2867 | UpdateStatusButtons(); |
| 2775 | controller_dialog->refreshConfiguration(); | 2868 | controller_dialog->refreshConfiguration(); |
| 2776 | } | 2869 | } |
| @@ -2856,7 +2949,7 @@ void GMainWindow::OnToggleDockedMode() { | |||
| 2856 | } | 2949 | } |
| 2857 | 2950 | ||
| 2858 | Settings::values.use_docked_mode.SetValue(!is_docked); | 2951 | Settings::values.use_docked_mode.SetValue(!is_docked); |
| 2859 | dock_status_button->setChecked(!is_docked); | 2952 | UpdateDockedButton(); |
| 2860 | OnDockedModeChanged(is_docked, !is_docked, *system); | 2953 | OnDockedModeChanged(is_docked, !is_docked, *system); |
| 2861 | } | 2954 | } |
| 2862 | 2955 | ||
| @@ -2895,7 +2988,7 @@ void GMainWindow::OnToggleAdaptingFilter() { | |||
| 2895 | 2988 | ||
| 2896 | void GMainWindow::OnConfigurePerGame() { | 2989 | void GMainWindow::OnConfigurePerGame() { |
| 2897 | const u64 title_id = system->GetCurrentProcessProgramID(); | 2990 | const u64 title_id = system->GetCurrentProcessProgramID(); |
| 2898 | OpenPerGameConfiguration(title_id, game_path.toStdString()); | 2991 | OpenPerGameConfiguration(title_id, current_game_path.toStdString()); |
| 2899 | } | 2992 | } |
| 2900 | 2993 | ||
| 2901 | void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file_name) { | 2994 | void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file_name) { |
| @@ -3150,7 +3243,7 @@ void GMainWindow::OnTasStateChanged() { | |||
| 3150 | } | 3243 | } |
| 3151 | 3244 | ||
| 3152 | void GMainWindow::UpdateStatusBar() { | 3245 | void GMainWindow::UpdateStatusBar() { |
| 3153 | if (emu_thread == nullptr) { | 3246 | if (emu_thread == nullptr || !system->IsPoweredOn()) { |
| 3154 | status_bar_update_timer.stop(); | 3247 | status_bar_update_timer.stop(); |
| 3155 | return; | 3248 | return; |
| 3156 | } | 3249 | } |
| @@ -3222,6 +3315,12 @@ void GMainWindow::UpdateGPUAccuracyButton() { | |||
| 3222 | } | 3315 | } |
| 3223 | } | 3316 | } |
| 3224 | 3317 | ||
| 3318 | void GMainWindow::UpdateDockedButton() { | ||
| 3319 | const bool is_docked = Settings::values.use_docked_mode.GetValue(); | ||
| 3320 | dock_status_button->setChecked(is_docked); | ||
| 3321 | dock_status_button->setText(is_docked ? tr("DOCKED") : tr("HANDHELD")); | ||
| 3322 | } | ||
| 3323 | |||
| 3225 | void GMainWindow::UpdateFilterText() { | 3324 | void GMainWindow::UpdateFilterText() { |
| 3226 | const auto filter = Settings::values.scaling_filter.GetValue(); | 3325 | const auto filter = Settings::values.scaling_filter.GetValue(); |
| 3227 | switch (filter) { | 3326 | switch (filter) { |
| @@ -3265,10 +3364,10 @@ void GMainWindow::UpdateAAText() { | |||
| 3265 | } | 3364 | } |
| 3266 | 3365 | ||
| 3267 | void GMainWindow::UpdateStatusButtons() { | 3366 | void GMainWindow::UpdateStatusButtons() { |
| 3268 | dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue()); | ||
| 3269 | renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == | 3367 | renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == |
| 3270 | Settings::RendererBackend::Vulkan); | 3368 | Settings::RendererBackend::Vulkan); |
| 3271 | UpdateGPUAccuracyButton(); | 3369 | UpdateGPUAccuracyButton(); |
| 3370 | UpdateDockedButton(); | ||
| 3272 | UpdateFilterText(); | 3371 | UpdateFilterText(); |
| 3273 | UpdateAAText(); | 3372 | UpdateAAText(); |
| 3274 | } | 3373 | } |
| @@ -3319,7 +3418,7 @@ void GMainWindow::CenterMouseCursor() { | |||
| 3319 | const int center_x = render_window->width() / 2; | 3418 | const int center_x = render_window->width() / 2; |
| 3320 | const int center_y = render_window->height() / 2; | 3419 | const int center_y = render_window->height() / 2; |
| 3321 | 3420 | ||
| 3322 | QCursor::setPos(mapToGlobal({center_x, center_y})); | 3421 | QCursor::setPos(mapToGlobal(QPoint{center_x, center_y})); |
| 3323 | } | 3422 | } |
| 3324 | 3423 | ||
| 3325 | void GMainWindow::OnMouseActivity() { | 3424 | void GMainWindow::OnMouseActivity() { |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index b399e9b01..8cf224c9c 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -320,6 +320,7 @@ private: | |||
| 320 | void MigrateConfigFiles(); | 320 | void MigrateConfigFiles(); |
| 321 | void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {}, | 321 | void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {}, |
| 322 | std::string_view gpu_vendor = {}); | 322 | std::string_view gpu_vendor = {}); |
| 323 | void UpdateDockedButton(); | ||
| 323 | void UpdateFilterText(); | 324 | void UpdateFilterText(); |
| 324 | void UpdateAAText(); | 325 | void UpdateAAText(); |
| 325 | void UpdateStatusBar(); | 326 | void UpdateStatusBar(); |
| @@ -368,7 +369,7 @@ private: | |||
| 368 | bool emulation_running = false; | 369 | bool emulation_running = false; |
| 369 | std::unique_ptr<EmuThread> emu_thread; | 370 | std::unique_ptr<EmuThread> emu_thread; |
| 370 | // The path to the game currently running | 371 | // The path to the game currently running |
| 371 | QString game_path; | 372 | QString current_game_path; |
| 372 | 373 | ||
| 373 | bool auto_paused = false; | 374 | bool auto_paused = false; |
| 374 | bool auto_muted = false; | 375 | bool auto_muted = false; |
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 15ba9ea17..c64d87ace 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -77,6 +77,8 @@ struct Values { | |||
| 77 | Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"}; | 77 | Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"}; |
| 78 | Settings::BasicSetting<bool> mute_when_in_background{false, "muteWhenInBackground"}; | 78 | Settings::BasicSetting<bool> mute_when_in_background{false, "muteWhenInBackground"}; |
| 79 | Settings::BasicSetting<bool> hide_mouse{true, "hideInactiveMouse"}; | 79 | Settings::BasicSetting<bool> hide_mouse{true, "hideInactiveMouse"}; |
| 80 | // Set when Vulkan is known to crash the application | ||
| 81 | Settings::BasicSetting<bool> has_broken_vulkan{false, "has_broken_vulkan"}; | ||
| 80 | 82 | ||
| 81 | Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"}; | 83 | Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"}; |
| 82 | 84 | ||
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index fc16f0f0c..fc4744fb0 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp | |||
| @@ -344,6 +344,8 @@ void Config::ReadValues() { | |||
| 344 | ReadSetting("Debugging", Settings::values.use_debug_asserts); | 344 | ReadSetting("Debugging", Settings::values.use_debug_asserts); |
| 345 | ReadSetting("Debugging", Settings::values.use_auto_stub); | 345 | ReadSetting("Debugging", Settings::values.use_auto_stub); |
| 346 | ReadSetting("Debugging", Settings::values.disable_macro_jit); | 346 | ReadSetting("Debugging", Settings::values.disable_macro_jit); |
| 347 | ReadSetting("Debugging", Settings::values.use_gdbstub); | ||
| 348 | ReadSetting("Debugging", Settings::values.gdbstub_port); | ||
| 347 | 349 | ||
| 348 | const auto title_list = sdl2_config->Get("AddOns", "title_ids", ""); | 350 | const auto title_list = sdl2_config->Get("AddOns", "title_ids", ""); |
| 349 | std::stringstream ss(title_list); | 351 | std::stringstream ss(title_list); |
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index f34d6b728..a3b8432f5 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h | |||
| @@ -218,7 +218,7 @@ cpuopt_unsafe_ignore_global_monitor = | |||
| 218 | 218 | ||
| 219 | [Renderer] | 219 | [Renderer] |
| 220 | # Which backend API to use. | 220 | # Which backend API to use. |
| 221 | # 0 (default): OpenGL, 1: Vulkan | 221 | # 0: OpenGL, 1 (default): Vulkan |
| 222 | backend = | 222 | backend = |
| 223 | 223 | ||
| 224 | # Enable graphics API debugging mode. | 224 | # Enable graphics API debugging mode. |
| @@ -437,6 +437,11 @@ disable_macro_jit=false | |||
| 437 | # Presents guest frames as they become available. Experimental. | 437 | # Presents guest frames as they become available. Experimental. |
| 438 | # false: Disabled (default), true: Enabled | 438 | # false: Disabled (default), true: Enabled |
| 439 | disable_fps_limit=false | 439 | disable_fps_limit=false |
| 440 | # Determines whether to enable the GDB stub and wait for the debugger to attach before running. | ||
| 441 | # false: Disabled (default), true: Enabled | ||
| 442 | use_gdbstub=false | ||
| 443 | # The port to use for the GDB server, if it is enabled. | ||
| 444 | gdbstub_port=6543 | ||
| 440 | 445 | ||
| 441 | [WebService] | 446 | [WebService] |
| 442 | # Whether or not to enable telemetry | 447 | # Whether or not to enable telemetry |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index ae2e62dc5..8e38724db 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | |||
| @@ -93,7 +93,7 @@ void EmuWindow_SDL2::OnFingerMotion(float x, float y, std::size_t id) { | |||
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | void EmuWindow_SDL2::OnFingerUp() { | 95 | void EmuWindow_SDL2::OnFingerUp() { |
| 96 | input_subsystem->GetTouchScreen()->TouchReleased(0); | 96 | input_subsystem->GetTouchScreen()->ReleaseAllTouch(); |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { | 99 | void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { |
| @@ -162,7 +162,15 @@ void EmuWindow_SDL2::WaitEvent() { | |||
| 162 | SDL_Event event; | 162 | SDL_Event event; |
| 163 | 163 | ||
| 164 | if (!SDL_WaitEvent(&event)) { | 164 | if (!SDL_WaitEvent(&event)) { |
| 165 | LOG_CRITICAL(Frontend, "SDL_WaitEvent failed: {}", SDL_GetError()); | 165 | const char* error = SDL_GetError(); |
| 166 | if (!error || strcmp(error, "") == 0) { | ||
| 167 | // https://github.com/libsdl-org/SDL/issues/5780 | ||
| 168 | // Sometimes SDL will return without actually having hit an error condition; | ||
| 169 | // just ignore it in this case. | ||
| 170 | return; | ||
| 171 | } | ||
| 172 | |||
| 173 | LOG_CRITICAL(Frontend, "SDL_WaitEvent failed: {}", error); | ||
| 166 | exit(1); | 174 | exit(1); |
| 167 | } | 175 | } |
| 168 | 176 | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h index 9746585f5..58b885465 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h | |||
| @@ -20,7 +20,7 @@ enum class MouseButton; | |||
| 20 | 20 | ||
| 21 | class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { | 21 | class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { |
| 22 | public: | 22 | public: |
| 23 | explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem, Core::System& system_); | 23 | explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_); |
| 24 | ~EmuWindow_SDL2(); | 24 | ~EmuWindow_SDL2(); |
| 25 | 25 | ||
| 26 | /// Whether the window is still open, and a close request hasn't yet been sent | 26 | /// Whether the window is still open, and a close request hasn't yet been sent |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp index 8075c9082..9b660c13c 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp | |||
| @@ -73,9 +73,9 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { | |||
| 73 | return unsupported_ext.empty(); | 73 | return unsupported_ext.empty(); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, | 76 | EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem_, |
| 77 | Core::System& system_, bool fullscreen) | 77 | Core::System& system_, bool fullscreen) |
| 78 | : EmuWindow_SDL2{input_subsystem, system_} { | 78 | : EmuWindow_SDL2{input_subsystem_, system_} { |
| 79 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); | 79 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); |
| 80 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6); | 80 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6); |
| 81 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); | 81 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h index d159166fd..39346e704 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h | |||
| @@ -17,7 +17,7 @@ class InputSubsystem; | |||
| 17 | 17 | ||
| 18 | class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 { | 18 | class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 { |
| 19 | public: | 19 | public: |
| 20 | explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, Core::System& system_, | 20 | explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_, |
| 21 | bool fullscreen); | 21 | bool fullscreen); |
| 22 | ~EmuWindow_SDL2_GL(); | 22 | ~EmuWindow_SDL2_GL(); |
| 23 | 23 | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index d5fe35aa0..65455c86e 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp | |||
| @@ -21,9 +21,9 @@ | |||
| 21 | #include <SDL.h> | 21 | #include <SDL.h> |
| 22 | #include <SDL_syswm.h> | 22 | #include <SDL_syswm.h> |
| 23 | 23 | ||
| 24 | EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem, | 24 | EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem_, |
| 25 | Core::System& system_, bool fullscreen) | 25 | Core::System& system_, bool fullscreen) |
| 26 | : EmuWindow_SDL2{input_subsystem, system_} { | 26 | : EmuWindow_SDL2{input_subsystem_, system_} { |
| 27 | const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name, | 27 | const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name, |
| 28 | Common::g_scm_branch, Common::g_scm_desc); | 28 | Common::g_scm_branch, Common::g_scm_desc); |
| 29 | render_window = | 29 | render_window = |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h index d92e3aaab..e39ad754d 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h | |||
| @@ -18,7 +18,7 @@ class InputSubsystem; | |||
| 18 | 18 | ||
| 19 | class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 { | 19 | class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 { |
| 20 | public: | 20 | public: |
| 21 | explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem, Core::System& system, | 21 | explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem_, Core::System& system, |
| 22 | bool fullscreen); | 22 | bool fullscreen); |
| 23 | ~EmuWindow_SDL2_VK() override; | 23 | ~EmuWindow_SDL2_VK() override; |
| 24 | 24 | ||
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index ab12dd15d..0dce5e274 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -217,10 +217,19 @@ int main(int argc, char** argv) { | |||
| 217 | [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); | 217 | [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | system.RegisterExitCallback([&] { | ||
| 221 | // Just exit right away. | ||
| 222 | exit(0); | ||
| 223 | }); | ||
| 224 | |||
| 220 | void(system.Run()); | 225 | void(system.Run()); |
| 226 | if (system.DebuggerEnabled()) { | ||
| 227 | system.InitializeDebugger(); | ||
| 228 | } | ||
| 221 | while (emu_window->IsOpen()) { | 229 | while (emu_window->IsOpen()) { |
| 222 | emu_window->WaitEvent(); | 230 | emu_window->WaitEvent(); |
| 223 | } | 231 | } |
| 232 | system.DetachDebugger(); | ||
| 224 | void(system.Pause()); | 233 | void(system.Pause()); |
| 225 | system.Shutdown(); | 234 | system.Shutdown(); |
| 226 | 235 | ||